Проект на Vite: от исходников к готовым файлам
Зачем это нужно
Компоненты писать умеем. Но открыть файл с расширением .tsx в браузере нельзя: браузер не знает ни типов, ни записи с разметкой внутри кода, ни того, откуда брать библиотеку.
Между исходниками и работающей страницей стоит сборка. Она проверяет типы, превращает запись в обычный код, склеивает всё в один файл и кладёт результат в отдельную папку — ровно то, что потом уезжает на сервер.
Инструмент для этого — тот же по роли, что Hardhat для контрактов: он берёт на себя всю механику. Эта глава — про то, что именно он делает, какие файлы создаёт и что из проекта попадает к пользователю, а что остаётся у вас.
Создать проект
npm create vite@latest webapp -- --template react-ts
Scaffolding project in …/webapp...
Done. Now run:
cd webapp
npm install
npm run dev
Дальше — обычная установка:
added 27 packages, and audited 28 packages in 17s
установка: 17.7 c
пакетов: 24, размер 80M
Двадцать семь пакетов против двухсот девяноста трёх у проекта с контрактами. Разница объяснима: там был компилятор, симулятор сети и набор инструментов; здесь — сборщик и библиотека интерфейсов.
Что появилось
index.html
package.json
vite.config.ts
tsconfig.json tsconfig.app.json tsconfig.node.json
src/main.tsx
src/App.tsx
src/App.css
src/index.css
public/favicon.svg
index.html лежит в корне, а не в папке исходников. Это не случайность: он и есть точка входа, с него сборка начинает обход.
src/ — всё, что пишет человек.
public/ — файлы, которые копируются в результат как есть, без обработки.
Три файла настроек типов. Один общий, один для кода страницы, один для кода сборки: у них разные условия работы.
vite.config.ts — четыре строки:
import react from '@vitejs/plugin-react'
import { defineConfig } from 'vite'
export default defineConfig({
plugins: [react()],
})
Знакомая форма: подключаемая часть добавляет обработку записи с разметкой и быстрое обновление страницы при правке. Ровно тот же приём, что в настройках Hardhat.
Как всё запускается
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.tsx'
createRoot(document.getElementById('root')!).render(
<StrictMode>
<App />
</StrictMode>,
)
Два режима: разработка и сборка
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"preview": "vite preview"
}
Разработка. Поднимается свой сервер, страница открывается в браузере. Правка файла — и изменение видно без перезагрузки, с сохранением состояния: набранное в поле остаётся на месте. Работает это потому, что современный браузер умеет подключать модули сам, и сборщику не надо каждый раз склеивать всё заново.
Сборка. Всё проверяется, склеивается и ужимается. Результат — папка готовых файлов.
Просмотр. Поднять локальный сервер уже для собранных файлов. Пригождается, чтобы убедиться, что сломалось не только «в разработке».
Разница между режимами — источник самой обидной породы ошибок: «у меня всё работало». В разработке типы не проверяются вовсе, адреса файлов другие, а строгий режим включён. Собирать проект стоит не в последний час, а как только он начал работать.
Сборка: числа
✓ 20 modules transformed.
dist/index.html 0.45 kB │ gzip: 0.29 kB
dist/assets/index-D64VDMd1.css 4.10 kB │ gzip: 1.47 kB
dist/assets/index-jOB7hSkO.js 222.53 kB │ gzip: 69.28 kB
✓ built in 497ms
Двадцать модулей превратились в один файл. Ни одного обращения к папке пакетов в результате нет: всё нужное уже внутри.
222 килобайта — и 69 при передаче. Второе число важнее: сервер отдаёт файлы сжатыми. Из этих 222 почти всё — сама библиотека; ваш код в маленьком проекте занимает единицы килобайт.
Случайные буквы в именах. Изменился код — изменилось имя. Это способ заставить браузер взять новую версию: старое имя у него в запасе, новое он обязан скачать.
Полсекунды. Сборка фронтенда — не то, из-за чего стоит нервничать на чемпионате.
dist/ 288K
Типы как гейт сборки
Обратите внимание на команду сборки: это две команды подряд.
"build": "tsc -b && vite build"
Первая проверяет типы во всём проекте и ничего не собирает. Вторая собирает. Две амперсанда означают «вторую запускать, только если первая прошла».
Прогон ломает типы намеренно:
── написали: const amount: number = 'пять' ──
src/App.tsx(8,9): error TS2322: Type 'string' is not assignable to type 'number'.
Сборка не состоялась, папка результата осталась прежней. Это ровно то, чего мы хотим: сломанный код физически некуда выложить.
И обратная сторона: в режиме разработки такой ошибки не видно. Там типы просто срезаются — как при прямом запуске файла из главы про запуск кода. Работает то же правило: проверку типов запускают отдельно и регулярно.
Переменные окружения и почему туда не кладут ключи
Адрес узла не пишут в коде: у проверяющего он может быть другим. Для таких значений есть отдельный файл.
VITE_RPC_URL=http://127.0.0.1:8545
SECRET_NOT_EXPOSED=не должно попасть в сборку
const rpc = import.meta.env.VITE_RPC_URL;
Прогон собирает проект и ищет оба значения в получившемся файле:
адрес узла попал в собранный файл : true
переменная без приставки : не попала
Правило: в сборку попадают только переменные с приставкой. Остальные не видны коду страницы вовсе.
Но главное здесь другое. Переменная с приставкой попадает в собранный файл в открытом виде — её видно каждому, кто откроет исходный код страницы. Значит:
- адрес узла, номер сети, адрес контракта — можно и нужно;
- приватный ключ, пароль, ключ платного сервиса — никогда.
«Спрятать ключ во фронтенде» невозможно в принципе. Весь код страницы приезжает к пользователю и целиком доступен для чтения. Всё, что должно остаться тайным, живёт на сервере — или, как в нашем случае, в кошельке пользователя, который подписывает транзакции сам.
Типичные ошибки
Забыли разделитель в команде создания. Ключ уходит менеджеру пакетов, а не создателю проекта, и сообщение получается непонятным.
Собирают в последний час. В разработке работало, при сборке — десяток ошибок типов, которых никто не видел.
Пути к файлам, которые работают только в разработке. Проверяется просмотром собранного.
Секрет в переменной с приставкой. Он уезжает к пользователю в открытом виде.
Правят файлы в папке результата. Следующая сборка их сотрёт. Правят исходники.
Кладут папку результата в репозиторий. Как и папку пакетов, её создают командой — в исключениях она уже перечислена.
Тяжёлая библиотека ради одной функции. Размер результата виден в отчёте сборки; если он вырос вдвое, стоит посмотреть, из-за чего.
Слова главы
- Сборщик — превращает исходники в файлы, понятные браузеру; для фронтенда то же, чем Hardhat был для контрактов.
- Точка входа — файл страницы в корне проекта, с него начинается обход зависимостей.
- Корневой узел — единственный элемент в теле; всё остальное создаёт библиотека.
- Режим разработки — свой сервер, обновление без перезагрузки, типы не проверяются.
- Сборка — проверка типов, склейка, сжатие; результат в отдельной папке.
- Имя с отпечатком — случайные буквы в имени файла, чтобы браузер взял новую версию.
- Папка «как есть» — файлы, которые копируются в результат без обработки.
- Переменная с приставкой — единственные, что попадают в код страницы; секретам там не место.
Тренажёр: набрать вслепую
Цель: скорость ≥ 100 зн/мин, точность ≥ 88%
npm create vite@latest webapp -- --template react-ts
На чемпионате
Соберите проект в первый же час. Пустая заготовка собирается за полсекунды; убедиться, что это работает, стоит до того, как в ней появится тысяча строк.
Адрес узла и адрес контракта — в переменных. У проверяющего сеть поднята у себя, и менять их правкой кода — плохой знак.
Проверьте собранную версию, а не только разработку. Отличий достаточно, чтобы потерять на них полчаса.
В репозиторий — исходники и файл точных версий. Папки пакетов и результата — нет; они создаются командами.
И про интернет: создание проекта и установка тянут из сети восемьдесят мегабайт. В модуле интернета нет — значит, проект должен быть создан заранее, а папка пакетов должна лежать на месте. Проверять это надо первым делом, а не тогда, когда до сдачи два часа.
Куда углубиться
- Псевдонимы путей — писать от корня проекта вместо длинных цепочек точек.
- Разделение сборки на части — когда страниц много и грузить всё сразу не нужно.
- Обращение к чужому серверу в разработке — как обойти запрет браузера на запросы к другому адресу.
- Оформление по компонентам — способ не дать именам классов столкнуться.
- Готовая сборка на сервере — чем отдача статических файлов отличается от запуска приложения.
Сводная проверка по всей главе: 8 вопросов, 5:00 на всё, без подсказок по ходу. Вопросы показываются по одному, ответ изменить нельзя. Если время выйдет — экзамен завершится с тем, что успел ответить. Пересдавать можно сколько угодно раз.
Куда дальше: проверенные ресурсы
- Vite: начало работы — создание проекта, режимы, структура.
- Vite: переменные окружения — приставка, файлы, режимы.
- Vite: сборка для продакшена — что происходит при сборке и как настроить.
- React: установка — с чего начинают проект на React сегодня.
- TypeScript: tsconfig — зачем в проекте три файла настроек типов.
Комментарии
Обсуждение живёт в GitHub Discussions и грузится с чужого домена — поэтому только по нажатию.