Запуск проекта и базовая конфигурация
Базовый обзор структуры проекта
После выполнения предыдущей лабораторной у вас сгенерировался стартовый шаблон. Прежде чем переходить к написанию собственных компонентов, давайте разберёмся, что именно лежит в проекте и зачем нужен каждый файл.
-
-
- vite.svg — статика, отдаётся как есть
-
-
- react.svg — пример ассета в исходниках
- App.css
- App.tsx
- index.css
- main.tsx — точка входа React-приложения
- vite-env.d.ts — типы для import.meta/env и импорта ассетов
-
- index.html — входная HTML-страница (entrypoint)
- package.json — скрипты, зависимости
- tsconfig.json — базовый TS-конфиг
- tsconfig.app.json — TS-конфиг для клиентского кода
- tsconfig.node.json — TS-конфиг для Node-окружения
- vite.config.ts — конфигурация Vite + плагин React
- .gitignore
- README.md
-
.gitattributes и переводы строк. Чтобы не получить хаос из CRLF/LF между Windows и Linux, добавьте .gitattributes с нормализацией строк (* text=auto). Подробности — в документации GitHub.В Vite основной точкой входа служит файл index.html. Браузер получает эту страницу, а Vite уже инжектит туда ваши скрипты и стили. Во время разработки именно он обслуживается dev-сервером, здесь подключается src/main.tsx и создаётся контейнер для React.
Алиас @ на src
Чтобы не писать длинные относительные пути вроде ../../components/Button (обращение к компоненту «Кнопка», который находится в директории с компонентами), заведём алиас @ на src. Для этого надо будет произвести правки в файлах vite.config.ts (файл с настройками Vite) и tsconfig.app.json (файл настройки окружения TypeScript для файлов внутри директории src).
Для начала применим необходимые правки внутри vite.config.ts:
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'path';
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'), // теперь можно import '@/components/Button'
},
},
});Нюанс. Чтобы не выдавало ошибок, не забудьте поставить типы Node при помощи команды:
npm i -D @types/nodeНо этого будет недостаточно: при проверке синтаксиса TypeScript будет выдавать ошибки, т.к. он такого синтаксиса на текущий момент ещё не знает. Чтобы у нас не выдавались ошибки при резолве импортов, необходимо дополнить tsconfig.app.json (а не перезаписать целиком — внутри compilerOptions уже есть набор опций от шаблона Vite, мы только добавляем baseUrl и paths):
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
}
}В данном случае baseUrl и paths — это стандартный механизм для резолва импортов.
У нас в директории осталось ещё два файла — tsconfig.json и tsconfig.node.json, для чего тогда нужны они? На самом деле в современных проектах часто используется принцип разделения конфигурации TS:
tsconfig.json— базовый;tsconfig.app.json— настройки для клиентского кода вsrc/;tsconfig.node.json— настройки для Node-окружения (например, дляvite.config.ts).
Переменные окружения
Далее разберёмся с переменными окружения, что это такое и для чего это нужно. Переменная окружения — это значение, которое передаётся снаружи (машина разработчика, CI, сервер), чтобы не хардкодить чувствительные или зависящие от среды аргументы: URL API, флаги, ключи тестовых сервисов.
Во фронтенде это всегда превращается в компромисс: всё, что попадёт в бандл, видно в браузере. Поэтому в Vite действует правило: к клиентскому коду попадают только переменные с префиксом VITE_ (например, VITE_API_URL). Их читают через import.meta.env (подробнее про этот механизм можно прочитать в официальной документации Vite):
VITE_APP_TITLE=Room & Assets
VITE_API_URL=/apiexport const APP_TITLE = import.meta.env.VITE_APP_TITLE;
export const API_URL = import.meta.env.VITE_API_URL;Альтернатива: runtime-конфигурация без пересборки образа
Ещё один способ, с которым вы можете иногда встретиться — генерация runtime-конфигурации, которая уже в свою очередь считывается собранным Vite-образом. Благодаря такому подходу отпадает необходимость пересборки всего образа фронтенда, если необходимо изменить одно из значений.
window.__APP_CONFIG__ = {
captchaEnabled: "true",
captchaSiteKey: "ysc1_Vf415QomO7JMtVYTnUVkqXdfo4F2hBaeOxjECRch3d45b583",
cookiePreferencesEnabled: "false",
gaId: "G-XXXXXXXXXX",
ymId: "987654321",
webHost: "caplag.ru",
baseUrl: "${PUBLIC_BASE_URL}"
};У вас генерируется открытый конфиг-файл (либо от бэкенда, либо при помощи механизма templates и ENVSUBST у NGINX), который уже передаётся на чтение самому фронтенду.
Vite поддерживает режимы (development, production, свои кастомные), и под каждый можно положить файл вида .env.production или .env.staging. Выбор делается флагом --mode у команды, например: vite build --mode staging. Для строгой типизации import.meta.env можно завести src/vite-env.d.ts и описать свои ключи.
package.json — манифест проекта
Базовая конфигурация в каком-то виде настроена, но как это всё дело запустить? Здесь обращаем внимание на package.json и его товарища package-lock.json. Для чего они нужны?
package.json — это центральный конфигурационный файл проекта, не менее важный, чем vite.config.ts или tsconfig. Это манифест проекта, который содержит: имя, версию, список зависимостей, команды (скрипты), технические флаги и метаданные. Файл обязан быть валидным JSON — без комментариев и лишних запятых. NPM и Node читают его, чтобы понять, что ставить, как запускать, и какие правила окружения соблюдать.
После генерации проекта с предложенным шаблоном его содержимое у вас (скорее всего) будет выглядеть следующим образом:
{
"name": "room-assets",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"lint": "eslint .",
"preview": "vite preview"
},
"engines": {
"node": ">=20.19 <21 || >=22.12"
},
"packageManager": "npm@10.9.2",
"dependencies": {
"react": "^19.1.1",
"react-dom": "^19.1.1"
},
"devDependencies": {
"@eslint/js": "^9.33.0",
"@types/react": "^19.1.10",
"@types/react-dom": "^19.1.7",
"@vitejs/plugin-react": "^5.0.0",
"eslint": "^9.33.0",
"eslint-plugin-react-hooks": "^5.2.0",
"eslint-plugin-react-refresh": "^0.4.20",
"globals": "^16.3.0",
"typescript": "~5.8.3",
"typescript-eslint": "^8.39.1",
"vite": "^7.1.2"
}
}Что за что отвечает
private: true— защита от случайной публикации пакета в общий реестр. Для приложений это принято держать включённым.type: "module"— говорит Node.js, что.jsвнутри проекта интерпретируются как ES-модули (а не CommonJS). Это влияет наimport/exportи расширения файлов.engines.node— фиксирует минимальный Node. С Vite 7 требуется Node 20.19+ или 22.12+ — запишем это в явном виде. В CI мы будем использовать Node 20, а в Docker —node:24-alpine(текущая LTS-линия на момент написания), поэтому диапазон допускает обе версии. Если хотите запретить Node 24, оставьте поле как есть и переключите Dockerfile-образы наnode:22-alpine.packageManager— закрепление выбора конкретного пакетного менеджера (npm/pnpm/yarn) с точной версией. Этим занимается Corepack, входящий в Node: он читает поле и подтягивает нужный менеджер, чтобы локально и в CI все использовали один и тот же инструмент.
Скрипты npm run <имя>
В секции scripts мы видим короткие имена командам. Запускаются они в консоли с использованием команды npm run <имя>. Список стандартных команд отвечает за:
dev— запускает Vite-dev-server для разработки: быстрый старт и HMR (горячая замена модулей без перезагрузки страницы). Это не урезанная имитация продакшена, а максимально комфортная среда для правки кода.build— собирает приложение для продакшена (директорияdist/). Также в созданном по умолчанию файле мы видим, что подключён type-check (tsc -b) перед сборкой — это хорошая привычка, поскольку Vite сам по себе типы не проверяет.preview— поднимает локальный сервер, который отдаёт уже собранныйdist/. Удобно проверить поведение приложения в продакшн-сборке, если для этого не используется отдельный хостинг.
dependencies vs devDependencies
Также, я думаю, возникает логичный вопрос: чем отличаются dependencies и devDependencies (по крайней мере, надеюсь, что возникает)? Рабочие библиотеки приложения (React, date-fns и т.п.) попадают в dependencies. Инструменты сборки, типы, линтеры — в devDependencies.
package.json обычно находится ещё один файл — package-lock.json. Он фиксирует точные версии всей зависимой цепочки, чтобы при сборке в различных средах не возникало проблем, что у одного работает, а у другого нет. Этот файл нужно коммитить в репозиторий. В CI полезно использовать npm ci — тогда при установке модулей он будет строго следовать lock-файлу, находящемуся в репозитории.Теперь смело запускаем проект npm run dev и переходим по ссылке из консоли на стартовую страницу. В следующей лабораторной мы возьмём этот шаблон за основу и начнём строить собственную архитектуру и компоненты.