Базовая версія React готавайнае да вырабоцтва: Калі саме функцыянаюць усе пакеты
Установіце Vite, Tailwind v4, Redux Toolkit, React Router, Jest і Prettier для прыекта на React, а таксама з’ясавайце, чым служыць кожны пакет і кожная лінія налаштавання.
Выкананне команды npm create vite дае вам аплікацыю на React, якая можа быць адразу выведзена, але гэта не тая версія, якую можна было б даць рэальным корыстнікаў: тут няма системы стайлізацыі, няма спакаванага статаусу, няма маршрутацыі, няма тэстаў і няма адпрацаванага формата коду. У гэтым кяліку шаго за шагам ствараецца нехватныя адносні базы з выкарыстоўванням Tailwind CSS, Redux Toolkit, React Router, Jest з React Testing Library і Prettier. Для кожнага пакета тут адпаведзаны на два запитанні: што он на самай працоўнае робіць і шта зламаецца, якщо яго не выкарыстоўваць? У канцы вы будете мяць рабочую базу для дадатковага розвіцця функцыяй, а таксама зможаце чытаць свой package.json і поясніць кожную лінію.
Короткая інфармацыя пра выкарыстоўваныя інструменты:
- Tailwind CSS — для стайлізацыі
- Redux Toolkit — для спакаваных дадзенняў аплікацыі
- React Router — для навігацыі між сторункамі
Дзеяныя з іх можна установіць за адну лінію. Іншыя скрываюць неспадзеваныя деталі; напрыклад, “React Testing Library” на самай працоўцы ёсць трое пакетаў з трома разнымі задачамі.
Пачніце з чыстага проекту Vite, выкарыстоўваючы шаблон React + TypeScript:
npm create vite@latest react-production-stack -- --template react-ts
cd react-production-stack
npm install
Tailwind CSS: стайлізацыя ўжо з самага пачатку
Пакеты: tailwindcss, @tailwindcss/vite
Стайлізацыя паўтараецца ў кожным компоненте, таму логічна пераканацца, што ён працуе, прытаму як толькі дадаць што-небудзь іншае.
npm install tailwindcss @tailwindcss/vite
Этот кастомны код устанавляець оба пакеты як звычныя залежнасці, а не як devDependencies. Якща говорыць строго, ніхто з пакетаў не работае ў браузеры: плагін Vite выкананае свою роботу пад час складання, і толькі створаны CSS потрапляе ў фінальны пакет для рэлізу. Таму багато команд ставяць іх у категорыю devDependencies, а для аплікацый на одной стороне экрана такой выбар не вплывае на рэзультат. Выберыце адну стандартную практыку і прытрымвайцеся яе.
Далей неабходна зарэгістраваць плагін разам з плагіном React у налаштаваннях Vite:
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [react(), tailwindcss()],
})
Пасля чаго неабходна заменіць вэрыянт файлу src/index.css на адны імпорт. Усё, што ў цым файле — гэта саме адны імпорт.
/* Tailwind v4 is CSS-first. No config file, no content globs. */
@import 'tailwindcss';
Гэта ўсё, што трэба зробіць для налаштавання. Tailwind v4 базуецца на CSS: тут няма файлу tailwind.config.js, а таксама няма спісу контэнтных элементаў, тым болей што система сама шукае імены класаў у вашых вачальных файлах.
Перакананне ў правільной працэздатнасі
Вяроцей дадзіце калькі прыемных класаў да заглавняка ў App.tsx, напрыклад text-3xl font-bold text-blue-600, запусціце npm run dev і пераканаецеся, што заглавняк змяніўся. Якщо так, значы плагін і імпорт CSS з’яўіліся у сувязі.
Чаму прыемныя класы, а не околачынныя файлы стылю
Tailwind заставляе стылі безпасэродзейна наявныя ў самай маркапе, яку яны паўтараюць. Калі існуе околачынны файл CSS, лёгка зменіць компонент і забыць пра яго файл стылю, што паступова прыводзіць да накоплення мертвых і застарэлых правілаў. У табло-панелях, у чыяму разе, аднаковыя элементы (карты, значкі, кантрабалі) паўтараюцца часта, і ўжыцце іх з адной спяльнай групы прыемных класаў дапамагае падтрымваць візуальную аднаковасць за меньшай колькасцю коду. Компрэсія — у змене прычынкі: замест таго, каб выдумваць назвы класаў уродзімо .card-header-active, кожны элемент складаецца з маленькіх, заздалегідь заданых класаў.
Redux Toolkit: хранальнік і мост даўжынай да React
Пакеты: @reduxjs/toolkit, react-redux
Этыя два пакеты легка сплутваць, але яны виконваюць разнае заведамства:
@reduxjs/toolkit— гэта сам хранальнік: ён зберагае даны прыемлівання і застосоўвае да яных апдэйты.react-redux— гэта з’яўленне з React: ён задае<Provider>і компоненты-хукі, якія викорыстоўваюцца для чытання і апдэйтування гэтых даных.
Вам патрэбны якія-то з іх, таму што ні аднаго не можа виконваць заведамства другога.
npm install @reduxjs/toolkit react-redux
Створыце хранальнік у src/app/store.ts. Ён пачынаецца з порожняй карточкі редюсераў і экспортуе два типы, выведзеных з хранальніка, каб рэшта прыемлівання ніколі не мусела ўводзіць іх вручную:
import { configureStore } from '@reduxjs/toolkit'
export const store = configureStore({
reducer: {},
})
export type RootState = ReturnType<typeof store.getState>
export type AppDispatch = typeof store.dispatch
Об’ект reducer: {} нараз чысты. Фрагменты будуць дадзены тады, калі патрэбны рэальныя функцыяналі, такія як проекты чыста задачы; нема сэнсу ствараць стан раней, чым яго будзе выкарыстоўваць какі-небудзь экран.
Пасля чаго ў файле src/app/hooks.ts адзначаюцца типаваныя хукі. Памочныя функцыі withTypes, якія є у новейшых версіях React Redux, аднойчы прыўязуюць useDispatch і useSelector да типаў вашага складу, тады компоненты можаць атрымваць полную інференцію типаў без неабходнасці анотавацыі кожнага вызову:
import { useDispatch, useSelector } from 'react-redux'
import type { AppDispatch, RootState } from './store'
export const useAppDispatch = useDispatch.withTypes<AppDispatch>()
export const useAppSelector = useSelector.withTypes<RootState>()
Дастатак складу компонентнам дрэву
У гэты момент склад існуе, але React не ведае пра яго. Тэг <Provider> робіць яго доступным для кожнага компонента пад сабой, таму ён размешчаецца на самай верхній ступені дрэва у файле src/main.tsx:
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import { Provider } from 'react-redux'
import { store } from './app/store'
import App from './App'
import './index.css'
createRoot(document.getElementById('root')!).render(
<StrictMode>
<Provider store={store}>
<App />
</Provider>
</StrictMode>,
)
Усе, што адражуецца ўнутрь <Provider>, тепер можа вызваць useAppSelector і useAppDispatch.
Перакананне ў правільной працэйнасці
Запускайте аплікацыю і пераканаўся, што сторунка яшчэ адражуецца без памылкі "could not find react-redux context". Гэта памылка з’яўляецца кожны раз, калі компонент выкарыстоўвае хуки Redux за межамі Provider. Калі хранальнік пусты, яшчо няма чаго тэставаць.
Калі варыта выкарыстоўваць Redux, а калі дастатнек useState
Не все паслужыць для зберагання ў Redux, і размешчэнне всіх статаў у хранальніку такое ж аблуднае, як і ўтримванне всіх статаў у локальным рэжыме. Практычная правіла:
useStateдля дадзеных, важных для адной экранаўкі чыя компонента: чы ўвімкнута модальна вікно, тэчная значенне вводу, выбраны варыянт у выпадаючым списку.
Якщо якае-небудзь станавое значэнне інакш было б перадаванае через калькольва шароў чы дуплікувалася межа экранамі, гэта ўжо хорашы знак, што яго трэба разместіць у хранільні дадзенняў.
React Router: маршрутызацыя да першага рэальнага экрана
Пакет: react-router
Даўжынка маршрутызацыі яшчэ до стварэння рэальных экранаў можа здавацца прытрыманай, але гэта быстра даўа плоды: кожны новы экран становіцца ўтаманнай <Route>, замест таго, каб пазней было трэба перастраіваць всю аплікацыю.
npm install react-router
Разместіце таблыцу маршрутаў у сваём самастоятельным модулі, src/routes/AppRoutes.tsx. Наразе ён супарабатоўвае / з компонентам-заместыканнем, стайлізаваным за дапамою інструментаў Tailwind:
import { Route, Routes } from 'react-router'
function Placeholder() {
return (
<div className="flex min-h-screen items-center justify-center">
<p className="text-slate-600">Routes coming soon</p>
</div>
)
}
export function AppRoutes() {
return (
<Routes>
<Route path="/" element={<Placeholder />} />
</Routes>
)
}
src/App.tsx проста атрыбуее на экран гэту таблыцу маршрутаў:
import { AppRoutes } from './routes/AppRoutes'
function App() {
return <AppRoutes />
}
export default App
У канцы, абгорніце праект у <BrowserRouter> ўнутры src/main.tsx, празаўсёды ля прадастальніка Redux:
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import { Provider } from 'react-redux'
import { BrowserRouter } from 'react-router'
import { store } from './app/store'
import App from './App'
import './index.css'
createRoot(document.getElementById('root')!).render(
<StrictMode>
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>
</StrictMode>,
)
Рэзультатны ланцоўкі є main.tsx → <App /> → <AppRoutes /> → той <Route>, які падходзіць да URL. Redux і раутер ёсць незалежныя, таму порядак іх абгорткі не мае значэння; ўсё, што трэба — гэта ўбачыць <App> ўнутры якіх-небудзь з іх.
Перакананне ў праверцы працэсу
Заўядзіце npm run dev і ачыніце /. Якщо паказываецца тэкст-заместычнік, <BrowserRouter>, <Routes> і <Route> усе налажаны правільна.
Jest і React Testing Library: чатыры задачы, адзеўнаць пакетаў
Пакеты: jest, @testing-library/react, babel-jest і ўсё іншае
Гэты крок займае больш часу. Самыя концэпцыі не ўскладненыя, але «адагуванне тэстаў» нарадзілася значыць установку адзеўнаць пакетаў, якія виконваюць чатыры разныя задачы, а пасля — працэс пераканання ў тым, што хоць адзін тэст праходзіць з ужоўваным рутэрам. Групаванне пакетаў па задачах значна спрыяе розумэнню всіго процесу.
Група А: адпраўчык тэстаў і сімуляваны браузер
npm install -D jest jest-environment-jsdom
- jest — гэта запускач тэстаў. Ён вышукае файлы
*.test.tsx, запускае іх і адмаўляе пра успехі чы розбіяння. Нічога іншага ў гэтым раздзеле не можа працаваць без яго. - jest-environment-jsdom неабходны, таму што Jest запускаецца ў Node, дзе няма элемента
document. Ён стварае сімуляцыю DOM, каб компоненты мелі месца для адрасавання.
Група B: React Testing Library складаецца з трох пакетаў
npm install -D @testing-library/react
npm install -D @testing-library/jest-dom
npm install -D @testing-library/user-event
Тое, што людзі называюць "React Testing Library", на самай працоўцы ёсць тры бібліятэкі, кожная з якіх мае свою ролю:
- @testing-library/react адрасавае компонент на сімуляваную сторунку і апранае методы, такія як
screen.getByText(...).
toBeInTheDocument(), таму вам не трэба ручнае параболіваць результаты запыткаў з null.Корача: атрымліваеце дадзеныя, пераканальвайцеся і ведаце дзейнасць. Тры задачы, тры пакеты, і вы майже завжды хочаце ўсіх іх.
Група C: інструменты Babel, якія дазволяюць Jest чытаць TSX
Гэтая група існуе з адной прычыны: Jest сам по сабе не можа разумець файлы TypeScript чы JSX.
- babel-jest спаўнае з’еднанне між ямі. Jest праходзіць кожны файл через Babel першы чым яго выконваець.
- @babel/preset-typescript адзьяюе аназацыі типаў. Ён не пераглядае нічога з точкы зору типаў; ён проста адключае
: stringі падобную сынтаксіс. - @babel/preset-react кампілюе JSX у звычныя вызывы функцый.
- @babel/preset-env ператварае савэцкі сынтаксіс у тое, што падтрымае ваша версія Node.
У адзіну з групы B, іх трэба інсталаваць разам ў адным камандзе. Усія прэтэты чакаюць сумесны @babel/core, і іх постаўка па частях у проекте, які вже мае Jest (який запоўнюе сабе залежнасці Babel), можа заставіць npm прабаваць супрацаваць з несумеснымі версіямі. Адзнакай гэтага ёст тыпак ERESOLVE unable to resolve dependency tree пад час наступной інсталляцыі адзінага пакета. Інсталляцыя всей групы зараз можа дапамогчы npm супрацаваць з аднай сумесной комплектацыяй.
Другія, менш зразныя падступы выходзяць з копіювання дугих команд з PDF-файлаў або веб-сторанак. Тэкст, які прадставленаў у формате з адступамі, можа ператворыцца на справжнія розбіўкі па лініях пад час вставкі, таму назва пакета, такая як @babel/preset-typescript, раздзеляецца на два часты, і шэл выканае другую частку як околачную, безсэнсавую команду. Явныя розбіўкі па лініях дазволяюць ставіць розбіўкі самэ там, дзе вы хочаце. Наступны прыклад відпаведае синтаксу Командной панелі Windows:
npm install -D babel-jest ^
@babel/core ^
@babel/preset-env ^
@babel/preset-react ^
@babel/preset-typescript
Знак ^ у канцы паведамляе cmd.exe, што команда продовжаецца на наступной лініи. У PowerShell знакам для продовжэння ёсць апостроф, а ў bash або zsh — зворачны слэш. Незалежна ад шэлу, гэта заўсёды ёсць адна команда npm install.
Група D: тыпы толькі для вашага рэдагара
npm install -D @types/jest
Эты пакет не вплывае на спосаб запуску тэстоў; Babel ўжо да гэтага часу адмахнуў усія типы. Ён існуе ў тым, каб TypeScript і ваш рэдагар упазнавалі глобальныя элементы, такія як test(...) і expect(...), а не пазначалі іх як канфлікты.
Дадаць скрыпты тэстоў
Інсталяцыя Jest не дае команды npm test, таму самі дадзіце скрыпты ў package.json:
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"lint": "eslint .",
"test": "jest",
"test:watch": "jest --watch"
}
npm test запускае весь набор тэстоў адной час. npm run test:watch застаецца у роботе і запускае зноў толькі тыя тэсты, якія паўтароцься пасля захавання файлу; калі працюеце, трэба заставіць яго ачыненым у другай тэрмінале.
Еща две команды варта запамятаць на случай проблем:
npx jest src/App.test.tsx # run one file only
npx jest --clearCache # when Jest keeps showing an error
# you already fixed
Команда кэшавання мае большое значэнне, чым можа здавацца. Jest кэшуе ператвораныя файлы, таму пасля змены babel.config.cjs або jest.config.cjs ён можа і даўжына служыць старым выходам і паказваць адчуванне пра бягучыя проблемы, якія вы вже вылечылі. Калі здаецца, што парадакс не працуе, спачатку ачысціце кэш, перацягваючы выважваць, што парадакс неправільны.
Полная настройка тэстаў
Мяні ўсе файлы настройкі цэлымі, з адказамі пра тое, за шта адпаведае кожны з іх.
babel.config.cjs
Прытарэннія падражнаюць Групу C: нацэляюцца на текущую версію Node, выкарыстоўваюць аўтаматычны рантайм JSX, таму файлы не патрабуюць імпорту React, і адключаюць TypeScript. Вбудованы плагін карае тое, чаго не можа Jest: import.meta, які код Vite выкарыстоўвае для такіх рэчаў, як import.meta.env і гарячая замена модуляў, але які не ўзьямлівы у выходным формате CommonJS, які запускае Jest.
function stripImportMeta() {
return {
visitor: {
MetaProperty(path) {
path.replaceWithSourceString('({ url: "", hot: undefined })')
},
},
}
}
module.exports = {
presets: [
['@babel/preset-env', { targets: { node: 'current' } }],
['@babel/preset-react', { runtime: 'automatic' }],
'@babel/preset-typescript',
],
plugins: [stripImportMeta],
}
Это справжній плагін Babel, напісаны як функцыя-вставка заместо інсталаванага пакета; Babel прымея як варыянт. MetaProperty — гэты тип вузла AST, які Babel выкарыстоўвае для import.meta, а візітар заменяе кожны такі выражэння на просты об’ект, у якога url ў значэнні пусты, а hot — незначны. Зважайце, што гэта таксама закрывае ад відгледу будзь-якія значэння import.meta.env у теставаным кодзе, таму компонент, які чытае зменныя сераўісу, будзе вынужаны ўсё гэта імітаваць окрема.
jest.config.cjs
Гэты файл запоўнюе вазны ролі ў работе всей системы. Ён выбірае сераўіс jsdom, завантажвае файл налашчэння пасля таго, як сераўіс будзе готавы, праходзіць кроз кожны файл на JavaScript і TypeScript за дапамогою babel-jest, а таксама перакладае імпорты стылю і з’явоў у маскаваныя модулі.
module.exports = {
testEnvironment: 'jsdom',
setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'mjs', 'json'],
transform: {
'^.+\\.(ts|tsx|js|jsx|mjs)