
Express + TypeScript - ESLint i Prettier
Wstęp
Każdy projekt powinien trzymać się z góry założonych norm stylistycznych. Adaptacja w projekcie ESLint i Prettier pozwoli nie tylko na utrzymanie czystości kodu, ale również pomoże wyłapać część błędów. W obecnych czasach niemal każdy projekt korzysta z omawianych tutaj bądź bliźniaczych narzędzi, a im bardziej rozwinięty i skomplikowany jest projekt, tym bardziej stają się one nieodzowne.
Wpis ten jest kontynuacją artykułu Express + TypeScript - konfiguracja projektu, z którym to zalecam się zapoznać w pierwszej kolejności. Opisywane tu zagadnienia można również stosować dla dowolnego projektu pisanego w Node i TypeScript, gdyż są dosyć uniwersalne. Kod omawiany w artykule można znaleźć w repozytorium github.
- Express + TypeScript - konfiguracja projektu
- Express + TypeScript - ESLint i Prettier
- Express + TypeScript - CRUD boilerplate
- Express + TypeScript - struktura aplikacji
- Express + TypeScript - konfiguracja MongoDB
- Express + TypeScript - walidacja requestów z biblioteką Joi
- Express + TypeScript - middlewares aplikacji
ESLint
Linter jak np. ESLint, to narzędzie skanujące i sprawdzające kod aplikacji w celu wyszukiwania błędów składniowych, stylistycznych oraz fragmentów kodu o wątpliwej jakości.
ESLint do linter dla szeroko pojętego ECMAScript, może być wykorzystywany zarówno w projektach JavaScript jak i TypeSctipt.
Inicjalizacja ESLint w projekcie polega na dodaniu w głównym katalogu aplikacji pliku .eslintrc.json (plik ten może mieć różne rozszerzenia), zawierającego konfigurację lintera. Nie ma jednak sensu robić ręcznie, wystarczy wywołać metodę, która zainicjalizuje linter w projekcie.
npx eslint --init
npx instaluje niezbędne paczki lokalnie, ale po zakończeniu wywoływania komendy usuwa je. W ten sposób nie zanieczyszczamy systemu sporadycznie używanymi pakietami.
Po wywołaniu powyższej komendy dostaję kilka pytań. Na podstawie odpowiedzi na nie, paczka wytworzy konfigurację lintera, która zostanie zapisana w pliku .eslintrc.json.
Pierwsze pytania dotyczą zgody na zainstalowanie paczek, tutaj oczywiście zgadzam się na wszystko. Kolejne pytania są bardziej konkretne.
? How would you like to use ESLint? …
To check syntax only
To check syntax and find problems
▸ To check syntax, find problems, and enforce code style
? What type of modules does your project use? …
▸ JavaScript modules (import/export)
CommonJS (require/exports)
None of these
? Which framework does your project use? …
React
Vue.js
▸ None of these
? Does your project use TypeScript?
No
‣ Yes
? Where does your code run? …
Browser
✔ Node
? How would you like to define a style for your project? …
▸ Use a popular style guide
Answer questions about your style
? Which style guide do you want to follow? …
▸ Standard: https://github.com/standard/eslint-config-standard-with-typescript
XO: https://github.com/xojs/eslint-config-xo-typescript
? What format do you want your config file to be in? …
JavaScript
YAML
▸ JSON
Po inicjalizacji lintera mój plik wygląda jak poniżej. Jedyna rzecz, którą zmieniłem to "parserOptions.project": "./tsconfig.json", czyli przekazanie względnej ścieżki do pliku tsconfig.json. Jest to wymagane, jeśli chcę, aby ESLint współpracował z TypeScript. Bez tej opcji nie ma wsparcia dla reguł związanych z typami itp.
{
"env": {
"es2021": true,
"node": true
},
"extends": "standard-with-typescript",
"overrides": [],
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module",
"project": "./tsconfig.json"
},
"rules": {}
}
Prettier
Prettier jest narzędziem do formatowania kodu, które wspiera bardzo wiele języków programowania. Wystarczy zainstalować go w projekcie.
npm i -D prettier
Teraz tworzę nowy plik .prettierrc.json, w którym zapisuje reguły, którymi chciałbym, aby posługiwał się edytor przy formatowaniu mojego kodu.
{
"singleQuote": true,
"arrowParens": "avoid",
"printWidth": 100,
"tabWidth": 2
}
Zdecydowana większość edytorów kodu ma wsparcie zarówno dla ESLint jak pakietu Prettier, stąd np. w VSC wystarczy zainstalować wtyczki o tych samych nazwach. Jeśli chcę, aby kod był formatowany automatycznie, wystarczy utworzyć nowy plik
.vscodei uzupełnić go kodem poniżej. Powie to edytorowi, że ma automatycznie formatować kod przy każdym zapisie pliku. Ustawienie to można również dodać globalnie do ustawień edytora.{ "editor.formatOnSave": true, }
Prettier razem z ESLint
Prettier może w bardzo sprawny sposób pracować razem z linterem, jakim jest ESLint. Dzięki temu uniknę konfliktów formatowania, to znaczy: czasem prettier autoformatuje fragmenty kodu, które linter następnie podkreśla jako błędne. Gdy połączę ich działanie ESLint nie będzie zaznaczał elementów, na które wpływ ma Prettier. Aby to zrobić, muszę doinstalować kilka pakietów:
npm i -D eslint-config-prettier eslint-plugin-prettier
Teraz tylko w pliku .eslintrc.json rozszerzam pole extends o dwa nowe elementy: eslint-config-prettier i prettier (teraz jest to lista, jako że są trzy elementy). Do listy plugins natomiast dodaję eslint-plugin-prettier.
eslint-config-prettier- wyłącza wszystkie reguły ESLint, które mogłyby kolidować z Prettiereslint-plugin-prettier- dodaje reguły Prettier do ESLint
Na koniec pozostaje tylko dodać nową regułę "prettier/prettier": "error" mówiącą o tym, że linter będzie zaznaczał jako błędy składnie sprzeczne z regułami formatowania.
{
"env": {
"browser": true,
"es2021": true
},
"extends": ["standard-with-typescript", "eslint-config-prettier", "prettier"],
"plugins": ["eslint-plugin-prettier"],
"overrides": [],
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module",
"project": "./tsconfig.json"
},
"rules": {
"prettier/prettier": "error"
}
}
Gdy wszystkie reguły ESLint i Prettier są już poprawnie zainstalowane i skonfigurowane, ostatnią rzeczą jest dodać możliwość sprawdzania i formatowania kodu. Wyżej wspominałem, że edytory kodu mają wbudowane (w postaci rozszerzeń) wsparcie dla linterów i formaterów, ale jednak są takie przypadki, gdy będę chciał odpalać sprawdzanie składni czy formatowanie ręcznie. Przykładami mogą być tzw. pre-commit hooks czyli polecenia odpalające w jak nazwa wskazuje podczas commitowania kodu. Może to też być jeden z etapów CI/CD pipelinu.
Z powyższych powodów dodam do package.json dwa skrypty.
{
"name": "express-ts",
"version": "1.0.0",
"main": "src/index.js",
"scripts": {
"build": "npx tsc",
"start": "node dist/index.js",
"start:dev": "nodemon src/index.ts",
"lint": "eslint . --ext .ts",
"lint:fix": "eslint . --ext .ts --fix"
},
...
}
lint po odpaleniu sprawdza kod według reguł zawartych w konfiguracji eslint, natomiast lint:fix robi to samo, przy czym stara się naprawić te błędy i ostrzeżenia, które jest w stanie.
Wykluczanie plików
Jeśli nie chcę, aby jakieś pliki czy foldery były brane pod uwagę w procesie formatowania, czy lintowania, mogę dodać je odpowiednio do plików .prettierignore i .eslintignore. Pliki te działają w ten sam sposób co .gitignore dla git. Warto dodać, że folder node_modules jest automatycznie wyłączony z bycia branym pod uwagę, więc nie muszę go dodawać.
distdistNie ma sensu w aplikacji sprawdzać pod względem składni i formatowania wygenerowanego za pomocą skryptu npm run build kodu JavaScript.
Podsumowanie
Proces formatowania kodu i automatycznego wyszukiwania błędów stylistycznych i składniowych znacznie ułatwia dewelopment aplikacji i przyśpiesza proces tworzenia oprogramowania. Unikamy bardzo wiele błędów podczas budowania aplikacji, które zostają wyłapane już na etapie pisania kodu. W przyszłości omawiał będę CI/CD pipelines, wtedy ustawienie powyższych narzędzi w projekcie będzie wręcz wymagane do poprawnego działania procesów automatyzacyjnych. Kod z artykułu można znaleźć w repozytorium github.