После команды npm run build в проекте появляется папка dist или build. Кажется, будто сборщик просто склеил исходники в один файл. На деле production-сборка включает анализ зависимостей, преобразование кода, оптимизацию, разделение на чанки и подготовку ресурсов для браузера.
Что запускает npm run build
npm запускает скрипт build из файла package.json.
Сама команда npm не является сборщиком
Примеры скриптов
В зависимости от проекта внутри может запускаться Vite, Webpack или Next.js.
{ "scripts": { "build": "vite build" } } // Webpack: webpack --mode production // Next.js: next build
Исходный проект
До сборки приложение состоит из компонентов, страниц, стилей, типов и утилит.
Шаг 1. Поиск точки входа
Сборщик находит entry point — файл, с которого начинается приложение. В Vite это часто src/main.tsx.
import { createRoot } from "react-dom/client"; import App from "./App"; createRoot(document.getElementById("root")!).render(<App />);
Шаг 2. Граф зависимостей
От точки входа сборщик проходит по импортам и строит dependency graph. В него попадают компоненты, страницы, стили, утилиты и используемые пакеты из node_modules. Если приложение импортирует axios, нужный код библиотеки также становится частью графа.
Шаг 3. TypeScript и JSX
Браузер не понимает TypeScript и JSX напрямую. Babel, SWC, esbuild или другой трансформер удаляет типы и превращает JSX в JavaScript.
// Было const title: string = "Привет"; const view = <h1>{title}</h1>; // После преобразования — условно const title = "Привет"; const view = React.createElement("h1", null, title);
Шаг 4. Поддержка браузеров
Современный JavaScript может преобразовываться под заданный target браузеров. Конкретный результат зависит от сборщика, транспайлера и конфигурации проекта.
Шаг 5. Tree shaking
Сборщик пытается удалить неиспользуемый код. Если модуль экспортирует несколько функций, а приложение импортирует только одну, остальные могут не попасть в итоговый бандл. Результат зависит от формата модулей и наличия побочных эффектов.
// utils.ts export function formatDate(value) { /* ... */ } export function formatCurrency(value) { /* ... */ } export function parseDate(value) { /* ... */ } // app.ts import { formatDate } from "./utils"
Шаг 6. Code splitting
Большое приложение можно разделить на чанки. Отдельно загружаются основной код, страницы, административный раздел и динамические части.
Шаг 7. Минификация
В production JavaScript и CSS обычно минифицируются: удаляются пробелы и комментарии, сокращаются имена и упрощаются выражения. Размер файлов уменьшается, но читать их вручную становится сложнее.
Шаг 8. Хэши в именах файлов
Файлы получают имена вроде main.8f31a2.js. Хэш зависит от содержимого. Если файл изменился, хэш обычно тоже меняется, поэтому браузер может кэшировать неизменившиеся ресурсы.
Что находится в dist или build
После сборки можно увидеть HTML, JavaScript, CSS, изображения, шрифты, favicon и дополнительные чанки.
Весь процесс целиком
Упрощённая схема production-сборки:
Что получает браузер
Браузер уже не видит структуру папки src, TypeScript-типы и JSX. Он получает готовые HTML, JavaScript, CSS и другие ресурсы, загружает их, выполняет JavaScript, запускает React и формирует интерфейс.
Вместо заключения
npm run build — это не просто сборка всего в один файл. Это подготовка приложения к реальному использованию: с оптимизацией размера, разделением кода, кэшированием и учётом особенностей целевых браузеров. Чем больше приложение, тем важнее понимать каждый этап: от этого зависят скорость загрузки, размер бандлов, обновления и пользовательский опыт.
Вопрос к читателям
Когда вы в последний раз заглядывали внутрь папки dist или build после production-сборки?
Что вас больше всего удивляло: количество чанков, размер зависимостей, работа tree shaking, source maps или что-то другое?
Расскажите, каким инструментом сборки вы пользуетесь — Webpack, Vite, Next.js, Rollup или другим — и какие интересные особенности замечали.