Konfiguracja projektu frontendowego w React

Czego się dowiesz?
- jak skonfigurować projekt frontendowy,
- jak pracować z eslint, prettier, husky,
- jak łatwo zarządzać wersjami aplikacji,
- jak dbać o aktualizacje paczek zewnętrznych
W tym artykule skonfigurujemy projekt, który ma konfigurację zbliżoną do projektu komercyjnego. Naszą konfigurację oprzemy o popularny starter Vite, ale jego użycie nie jest konieczne. Jeśli wybierzesz inny starter to niektóre kroki będzie trzeba pominąć lub będą się trochę różnić od podanych. Najbardziej mi zależy abyś zapoznał/a się z gamą narzędzi i tym co oferują. Vite to popularny lokalny serwer programistyczny, który pozwala nam uruchomić aplikację. Vite obsługuje Hot module reloading (obserwuje zmiany w plikach i automatycznie mówi przeglądarce, że ma przeładować stronę). Vite wyróżnia się szybkością działania i cały czas jest wspierane przez społeczność i autora.
Zaczynamy od instalacji Vite. W terminalu wpisujemy:
npm create vite
- Wpisujemy nazwę projektu
- package name - enter
- Wybieramy React - enter
- Wybieramy TypeScript - enter
Wchodzimy do projektu
cd nazwa-projektu
Instalujemy zależności zalinkowane w pliku package.json
npm install
Eslint
Eslint to narzędzie do statycznej analizy kodu (analizuje strukturę kodu bez jego uruchomienia). Reguły eslinta pozwalają na utrzymywanie w projekcie jednakowej stylistyki kodu i zapobiega powstawaniu częstych błędów. Eslint składa się z pojedynczych reguł, ale też z pluginów czyli paczek reguł, które są już skonfigurowane i możemy je stosować.
Vite w starterze do React domyślnie dodaje jako devDependency eslinta, więc nie musimy go już instalować. Jeśli nie masz eslinta w devDependency, bo użyłeś/aś innego startera lub frameworka trzeba go zainstalować i skonfigurować poleceniem:
npm install --save-dev eslint
Następnie w innych kompilatorach niż Vite musimy rozpocząć konfigurację. Najlepiej to zrobić za pomocą narzędzi CLI od eslinta. Jeśli korzystasz z Vite ten krok należy pominąć!
npx eslint --init
Wybierz odpowiednie opcje:
- check syntax and find problems,
- JavaScript modules
- React
- TypeScript Yes
- Browser
- JSON
- Doinstalowanie Yes
- npm w naszym przypadku
Po npx eslint --init powstanie plik .eslintrc.json
W vite mamy już plik .eslintrc.cjs w folderze głównym naszego projektu. Zmieńmy rozszerzenie na json (.eslintrc.json), bo w ten sposób będziemy go dalej konfigurować.
Teraz doinstalujmy moim zdaniem najbardziej przydatne pluginy:
npm install --save-dev eslint-plugin-react-hooks eslint-plugin-react eslint-plugin-jsx-a11y eslint-plugin-simple-import-sort @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-plugin-unused-imports eslint-plugin-typescript-sort-keys eslint-plugin-sort-destructure-keys
Finalny plik eslintrc.json do wklejenia:
{
"root": true,
"env": {
"browser": true,
"es2021": true,
"jest": true
},
"parser": "@typescript-eslint/parser",
//czego eslint ma nie sprawdzać
"ignorePatterns": ["dist", ".eslintrc.json", "*.config.ts", "*.config.js"],
"extends": [
"eslint:recommended",
"plugin:react/recommended",
"plugin:@typescript-eslint/recommended",
"plugin:react-hooks/recommended",
"plugin:jsx-a11y/recommended",
"plugin:typescript-sort-keys/recommended"
],
"overrides": [
// override "simple-import-sort" config
{
"files": ["*.js", "*.jsx", "*.ts", "*.tsx"],
"rules": {
"simple-import-sort/imports": [
"error",
{
"groups": [
// Packages `react` related packages come first.
["^react", "^@?\\w"],
// Internal packages.
["^(@|components)(/.*|$)"],
// Side effect imports.
["^\\u0000"],
// Parent imports. Put `..` last.
["^\\.\\.(?!/?$)", "^\\.\\./?$"],
// Other relative imports. Put same-folder imports and `.` last.
["^\\./(?=.*/)(?!/?$)", "^\\.(?!/?$)", "^\\./?$"],
// Style imports.
["^.+\\.?(css)$"]
]
}
]
}
}
],
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module",
"project": ["./tsconfig.json"]
},
"plugins": [
"react",
"@typescript-eslint",
"simple-import-sort",
"eslint-plugin-unused-imports",
"sort-destructure-keys"
],
"rules": {
"react/react-in-jsx-scope": "off",
"unused-imports/no-unused-imports": "warn",
"react/no-array-index-key": "error",
"simple-import-sort/imports": "error",
"simple-import-sort/exports": "error",
"react/self-closing-comp": ["error", { "component": true, "html": true }],
"react/function-component-definition": [
"error",
{
"namedComponents": "arrow-function"
}
],
"no-console": "error",
"@typescript-eslint/ban-ts-comment": "error",
"@typescript-eslint/no-empty-interface": "error",
"@typescript-eslint/no-unused-vars": [
"error",
{
"argsIgnorePattern": "^_",
"varsIgnorePattern": "^_"
}
],
"multiline-ternary": "error",
"no-unused-vars": "error",
"no-use-before-define": "error",
"no-magic-numbers": "error",
"sort-keys": ["error", "asc", { "caseSensitive": false, "natural": true, "minKeys": 2 }],
"sort-vars": ["error", { "ignoreCase": true }],
"react/jsx-sort-props": [
"error",
{
"callbacksLast": true,
"shorthandFirst": true,
"multiline": "last",
"ignoreCase": true,
"noSortAlphabetically": false,
"reservedFirst": ["key"],
"locale": "auto"
}
],
"sort-destructure-keys/sort-destructure-keys": ["error", { "caseSensitive": false }],
"no-multiple-empty-lines": ["error", { "max": 2, "maxBOF": 0, "maxEOF": 1 }]
},
"settings": {
"react": {
"version": "detect"
}
}
}
W package.json mamy już skrypt lint skonfigurowany przez vite (jeśli korzystasz z innego startera trzeba go dodać)
"scripts":{
...
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0"
...
},
Po włączeniu tego skryptu z terminala poleceniem:
npm run lint
powinno pojawić się kilka problemów. To dowód że eslint działa 😀 Nie chcemy za każdym razem rozwiązywać każdego problemu ręcznie. Pozwólmy działać automatyzacji. Dodajmy skrypt w package.json pod skryptem lint:
"scripts":{
...
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"lint-fix":"eslint . --fix --ext ts,tsx --report-unused-disable-directives --max-warnings 0"
...
},
Po włączeniu tego skryptu z terminala poleceniem:
npm run lint-fix
eslint powinien automatycznie rozwiązać problemy, które potrafi sam rozwiązać i zwrócić listę problemów, które zostały do rozwiązania ręcznie
Prettier
Prettier to formater kodu który jest kompatybilny z wieloma językami programowania i edytorami kodu, pozwala na zachowanie spójności w formatowaniu kodu w projekcie pomiędzy wieloma pracującymi nad nim programistkami/programistami
Instalujemy prettiera poprzez terminal
npm install --save-dev prettier
Tworzymy plik .prettierrc dla prettiera w głównym folderze projektu z treścią
{
"semi": true,
"tabWidth": 2,
"printWidth": 100,
"singleQuote": true,
"trailingComma": "all",
"jsxSingleQuote": true,
"bracketSpacing": true
}
Dodajemy kolejny skrypt do listy skryptów w package.json
"scripts":{
...
"prettier": "prettier --write .",
...
}
i uruchamiamy prettiera poleceniem
npm run prettier
Prettier powinien sformatować nam kilka plików.
Commitlint i husky
Narzędzie commitlint pozwala na wprowadzenie analizy treści commita. Żeby pisać prawidłowo commity w projekcie będziemy się trzymać znanej konwencji conventional-commits
Użyjmy biblioteki commitlint:
npm install --save-dev @commitlint/config-conventional @commitlint/cli
Tworzymy plik commitlint.config.js z treścią:
export default { extends: ['@commitlint/config-conventional'] };
Wykorzystajmy bibliotekę commitlint, tak żeby sprawdzała nasze commity automatycznie. Zainstalujmy narzędzie Husky.
Husky to narzędzie do automatycznego odpalania skryptów podczas commitowania lub pushowania zmian, wykorzystuje git-hooks. Instalujemy i konfigurujemy narzędzie husky
npm install --save-dev husky
git init (jeśli nie masz repozytorium)
npx husky init
w package.json husky dodał skrypt prepare:
"prepare": "husky"
W folderze .husky powstał plik pre-commit, zmieńmy jego treść aby uruchamiała nasz skrypt lint-fix. W pliku podmieniamy zawartość na:
npm run lint-fix
Jeśli chcesz żeby oprócz eslinta przed commitem sprawdzana była też treść commita, dodajemy kolejny hook w folderze .husky. Dodajemy plik commit-msg z treścią:
npx --no -- commitlint --edit ${1}
Teraz wystarczy spróbować zacommitować zmiany aby husky uruchomił automatycznie skrypty.
git add .
git commit -m "chore: config"
Jeśli pojawi się jakiś problem husky nie pozwoli nam na dodanie zmian.
Aby zautomatyzować swoją pracę w pliku .vscode/settings.json dopisz:
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"eslint.validate": ["javascript", "javascriptreact", "html", "typescriptreact"]
aby eslint sprawdzał i poprawiał błędy podczas zapisywania
Pull request template
Dzięki temu będziemy mieli wzór, który pomoże nam szybciej tworzyć pull requesty i ich opisy. Jest to bardzo przydatne, aby upewnić się, że postępujemy zgodnie ze standardowym procesem dla każdego PRka. Dobrze jest mieć listę rzeczy do zrobienia przed poproszeniem o recenzję swojego kodu. Tworzymy plik pull_request_template.md. Poniżej wklejam przykładowy template:
# Description
Please include:
- summary of the changes and the related issue,
- relevant motivation and context.
List any dependencies that are required for this change.
Issue link: [TICKET-NUMBER](link)
## Type of change
Please delete options that are not relevant.
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] This change requires a documentation update
# How Has This Been Tested?
Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce.
Please also list any relevant details for your test configuration
# Checklist:
- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream modules
Jeśli templatka Ci się spodobała i korzystasz z githuba do zarządzania projektem można też utworzyć issue templates do zgłaszania błędów.
cz git, commitizen
Commitizen to narzędzie do zarządzania releasami.
Commitizen zakłada, że zespół używa metodologii conventional commits (mozna też stworzyć własny zestaw reguł)
Instalujemy narzędzie globalnie
npm i -D cz-git
w package.json dodajemy:
"scripts": {
...
"commit": "git-cz"
},
"config": {
"commitizen": {
"path": "node_modules/cz-git",
"useEmoji": true
}
}
Aby go użyć wpisujemy w terminalu:
git cz
W terminalu wybieramy typ commita i postępujemy zgodnie z instrukcjami z cli. To utworzy nam nowy commit. Automatycznie zareaguje też husky.
release-please
Narzędzie to automatyzuje generowanie CHANGELOGa na podstawie treści commitów (o których prawidłową treść już dbamy), tworzy releasy na github i aktualizuje projekt. Narzędzie opiera się też na konwencji conventional commits. Gdy zmergujesz już zmiany z PR stworzonego przez release-please. Release-please:
- Aktualizuje changelog file (CHANGELOG.md),
- Dodaje tag do commita z numerem wersji,
- Tworzy release na github bazując na tagu,
Aby dodać to do naszego repozytorium najlepiej podążąć za oficjalną dokumentacją i skopiować plik github-action do naszego repozytorium.
Release please action
Dependabot
Narzędzie to automatycznie wykrywa paczki w projekcie które należy zaktualizować, ponieważ zawierają luki bezpieczeństwa, są przestarzałe lub ostrzegają Cię o znanej jeszcze nie załatanej luce.
Aby go odblokować:
- Wchodzimy w ustawienia repozytorium.
- W sekcji Security w Code security and analysis
- Odblokowujemy Dependabot przyciskami enable
Źródła:
Vite
Eslint
Prettier
Dependabot
Pull request template
Git cz