После команды 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 или другим — и какие интересные особенности замечали.

Комментарии (0)