Przejdź do treści

Aplikacje Command Line

Oprogramowanie tworzone w Node.js, zwykle kojarzymy z aplikacjami webowymi - w formie strony internetowej lub API w jakiejkolwiek postaci (REST API, GraphQL itp.).

Jednak podczas rozwoju oprogramowania wspomagamy się także dodatkowymi narzędziami, szczególnie tymi uruchamianymi z linii poleceń. Świetnym przykładem jest npm cli. Rozwiązane w pełni stworzone w JavaScript, Node.js i uruchamiane z poziomu terminala.

W swojej przygodzie z Node.js tworzyłem narzędzia wspomagające pracę z aplikacjami, właśnie za pomocą CLI. Były to narzędzia administracyjne, odpowiedzialne za operacje na bazie danych (czyszczenie tabel, okresowe kalkulacje itp.), usuwanie/agregowanie logów, generatory szablonów czy też migratory danych z jednego źródła danych do innego.

Oto najważniejsze elementy dzięki, którym tworzenie aplikacji CLI, będzie ciekawym wyzwaniem.

Parametry procesu

Podstawową rzeczą, bez której nie wyobrażam sobie dobrego rozwiązania CLI jest możliwość parametryzacji. Nie wszystkie operacje chcemy zawsze wykonywać z tym samym zestawem danych konfiguracyjnych. Czasem zmienimy adres URL do zasobu zewnętrznego, po to, aby nie pisać skryptów zależnych od środowisk uruchomieniowych. Czy też zmniejszymy wolumen przetwarzanych danych, ograniczając wykonywaną operację do danego okresu.

$: node app.js https://nodestart.pl \
   --period-start=2021-06-01 \
   --period-end=2021-06-28

Dostęp do argumentów przekazywanych podczas uruchamiania procesu, możliwy jest za pomocą process.argv.

W profesjonalny sposób (sic!) podejrzymy zawartość tej zmiennej:

1
console.log(process.argv);

Po uruchomieniu tego niesamowitego skryptu otrzymamy mniej więcej poniższy rezultat:

$: node app.js param1 param2 param3

[
  '/home/adrian/.nvm/versions/node/v16.4.0/bin/node',
  '/home/adrian/projects/nodestart/comand-line-app/app.js',
  'param1',
  'param2',
  'param3'
]

Pierwszy element w tablicy to pełna ścieżka do pliku wykonywalnego Node.

Drugi to ścieżka do skryptu, który uruchomiliśmy. Zwykle te dwie informacje nie są interesujące, gdy chcemy pobrać tylko i wyłącznie przekazane parametry. Do nich mamy dostęp dopiero od trzeciej pozycji (indexu = 2).

Finalnie wykorzystanie funkcji slice(), zwróci nam tablicę przekazanych parametrów. Rezultatem wykonania process.argv.slice(2) będzie:

$: node app.js param1 param2 param3

[
  'param1',
  'param2',
  'param3'
]

Jeżeli chcemy skorzystać z bardziej złożonych argumentów (nazywanych), musimy pokusić się o nieco więcej inicjatywy, implementując parsowanie argumentów po swojej stronie.

1
2
3
4
5
6
7
const args = process.argv.slice(2).reduce((acc, current) => {
  const item = current.split('=');
  acc[item[0]] = item[1];
  return acc;
}, {});

console.log(args);

Uruchomienie coraz bardziej przypomina konwencję dla POSIX CLI.

$: node app-02.js param1=1 param2=2 param3=3

{ param1: '1', param2: '2', param3: '3' }

Parametry i generowanie pomocy

Jeżeli tworzymy bardziej rozbudowane narzędzie, obsługujące wiele różnych poleceń, gdzie każde może posiadać inny zestaw parametrów, nie unikniemy budowania podpowiedzi. No, bo jak odnaleźć się w dostępnych poleceniach, jak nie za pomocą –help?

W tym wypadku pomocna może stać się biblioteka yargs. Pozwalająca zdefiniować komendy wraz z parametrami. Wszystko dzieje się za pomocą dość przyjaznego buildera. Dodatkowym atutem jest możliwość generowania w sposób automatyczny pomocy:

$: node app-yargs.js --help

nodestart <cmd> [args]

Commands:
  nodestart last-newsletter Wyświetl tytuł ostatniego newslettera
  nodestart subscribe-newsletter [mail] Zapisz się do newslettera

Options:
  --version Show version number
  --help Show help</cmd>

Przykład wykorzystania yargs w formie, którą widzisz powyżej, zawarłem w repozytorium NodeStart na GitHubie.

Można również skorzystać z prostszej biblioteki - minimist.

Wczytywanie danych od użytkownika

TODO

Formatowanie komunikatów

Pracując z różnymi, narzędziami CLI, da się zauważyć niestandardowy wynik działania aplikacji na ekranie. Szczególnie w JS, gdzie kolorystyka komunikatów, ich forma oraz interaktywność nie jest rzadkością.

Zastosowanie fajerwerków, nie jest niczym trudnym. Z pomocą przychodzą nam gotowe rozwiązania, działające na różnych systemach operacyjnych, a co za tym idzie również odmiennych powłokach - bash, zsh, sh itp.

Poniżej zrobiłem małe zestawienie ciekawych bibliotek, na które warto rzucić okiem, jeśli zależy nam na oryginalnym outpucie:

Kilka przykładów związanych z aplikacjami CLI, znajdziesz w repozytorium GitHub.