Выходные файлы (output)

Секция output определяет параметры генерации итоговых файлов Webpack. После обработки графа зависимостей, трансформации модулей через loaders и оптимизации через plugins, Webpack формирует один или несколько файлов. Именно output управляет:

  • именами файлов;
  • директорией сборки;
  • форматом загрузки чанков;
  • публичным URL ресурсов;
  • очисткой каталога;
  • структурой ассетов;
  • типом экспортируемой библиотеки;
  • генерацией source maps;
  • поведением runtime-файлов.

Без корректной настройки output сборка может работать нестабильно: браузер не найдёт чанки, CSS окажется в неверной папке, а кэширование станет бесполезным.

Базовая структура:

const path = require('path');

module.exports = {
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js'
    }
};

Свойство output.path

path задаёт абсолютный путь к каталогу сборки.

Пример:

const path = require('path');

module.exports = {
    output: {
        path: path.resolve(__dirname, 'dist')
    }
};

Webpack требует именно абсолютный путь.

Неправильно:

output: {
    path: './dist'
}

Правильно:

output: {
    path: path.resolve(__dirname, 'dist')
}

Почему требуется абсолютный путь

Webpack работает независимо от текущей директории запуска процесса Node.js. Абсолютный путь исключает неоднозначность.

Использование path.resolve() обеспечивает:

  • кроссплатформенность;
  • корректную работу на Windows/Linux/macOS;
  • предсказуемость структуры проекта.

Свойство output.filename

filename определяет имя итогового bundle-файла.

Пример:

output: {
    filename: 'main.js'
}

Результат:

dist/
└── main.js

Динамические шаблоны имени файла

Webpack поддерживает placeholders.

[name]

Имя entry point.

entry: {
    app: './src/app.js',
    admin: './src/admin.js'
},

output: {
    filename: '[name].js'
}

Результат:

dist/
├── app.js
└── admin.js

[id]

Уникальный идентификатор чанка.

filename: '[id].js'

Результат:

dist/
├── 123.js
├── 456.js
└── 789.js

Используется редко, поскольку имена становятся нечитаемыми.


[contenthash]

Хеш содержимого файла.

filename: '[name].[contenthash].js'

Результат:

app.a41d91c.js
vendor.b73e2ff.js

Изменение файла меняет хеш.

Это основа эффективного browser cache.


[chunkhash]

Хеш конкретного chunk.

filename: '[name].[chunkhash].js'

Используется в старых конфигурациях. В Webpack 5 чаще применяется contenthash.


[fullhash]

Хеш всей сборки.

filename: '[name].[fullhash].js'

При любом изменении проекта меняются все файлы.

Недостаток:

  • ухудшение кэширования;
  • лишняя инвалидизация браузерного cache.

Использование contenthash

Наиболее распространённая production-конфигурация:

output: {
    filename: '[name].[contenthash].js'
}

Преимущества:

  • долгосрочное кэширование;
  • браузер скачивает только изменённые файлы;
  • уменьшение сетевого трафика.

Свойство output.clean

Webpack 5 умеет автоматически очищать директорию сборки.

output: {
    clean: true
}

Перед новой сборкой каталог dist будет очищен.

Без этого могут накапливаться старые файлы:

dist/
├── app.111.js
├── app.222.js
├── app.333.js

Настройка структуры каталогов

Webpack позволяет создавать вложенные директории.

output: {
    filename: 'js/[name].[contenthash].js'
}

Результат:

dist/
└── js/
    ├── app.js
    └── vendor.js

Свойство chunkFilename

Используется для динамически загружаемых чанков.

output: {
    filename: '[name].js',
    chunkFilename: '[name].chunk.js'
}

Пример dynamic import:

import('./module');

Результат:

dist/
├── main.js
└── module.chunk.js

Разница между filename и chunkFilename

filename

Используется для:

  • entry points;
  • основных bundle-файлов.

chunkFilename

Используется для:

  • lazy loading;
  • code splitting;
  • dynamic imports.

Настройка production-чанков

Типичная production-конфигурация:

output: {
    filename: 'js/[name].[contenthash].js',
    chunkFilename: 'js/[name].[contenthash].chunk.js'
}

Свойство publicPath

publicPath определяет базовый URL для загрузки ресурсов.

Пример:

output: {
    publicPath: '/assets/'
}

Если chunk называется:

vendors.js

Webpack будет загружать:

/assets/vendors.js

Проблемы без publicPath

Без настройки динамические чанки могут загружаться относительно текущего URL.

Например:

/dashboard/settings

Тогда браузер попытается загрузить:

/dashboard/settings/chunk.js

Вместо:

/assets/chunk.js

CDN и publicPath

Webpack может работать с CDN.

output: {
    publicPath: 'https://cdn.example.com/assets/'
}

Результат:

https://cdn.example.com/assets/app.js

Автоматический publicPath

Webpack 5 поддерживает:

output: {
    publicPath: 'auto'
}

Webpack автоматически определяет путь загрузки ресурсов.

Особенно полезно:

  • в microfrontend-архитектуре;
  • при динамическом размещении приложения;
  • в Module Federation.

Свойство assetModuleFilename

Webpack 5 использует Asset Modules вместо многих legacy-loader’ов.

Настройка:

output: {
    assetModuleFilename: 'images/[hash][ext][query]'
}

Результат:

dist/
└── images/
    ├── a12b3.png
    └── c44d5.svg

Плейсхолдеры ассетов

[ext]

Расширение файла.

[query]

Строка query parameters.

[hash]

Хеш файла.


Настройка структуры ассетов

Пример:

output: {
    assetModuleFilename: 'assets/[name].[hash][ext]'
}

Результат:

assets/logo.3f1a2.svg
assets/bg.91de2.png

Свойство library

Webpack может собирать библиотеки.

output: {
    library: 'MyLibrary'
}

В браузере:

window.MyLibrary

Свойство libraryTarget

Определяет формат экспорта библиотеки.

var

output: {
    library: 'MyLib',
    libraryTarget: 'var'
}

Результат:

var MyLib = ...

umd

Universal Module Definition.

output: {
    libraryTarget: 'umd'
}

Поддерживает:

  • CommonJS;
  • AMD;
  • браузерные глобальные переменные.

Наиболее универсальный вариант.


commonjs

output: {
    libraryTarget: 'commonjs'
}

Используется в Node.js.


module

ES Modules.

output: {
    module: true
}

И:

experiments: {
    outputModule: true
}

Свойство globalObject

Определяет глобальный объект среды.

output: {
    globalObject: 'this'
}

Важно для универсальных библиотек.

Иначе в Node.js может отсутствовать window.


Свойство sourceMapFilename

Управляет именами source map файлов.

output: {
    sourceMapFilename: '[file].map'
}

Результат:

app.js
app.js.map

Свойство crossOriginLoading

Настройка crossorigin для chunk loading.

output: {
    crossOriginLoading: 'anonymous'
}

Используется при:

  • CDN;
  • загрузке с другого домена;
  • использовании SRI.

Свойство scriptType

Тип создаваемых script-тегов.

output: {
    scriptType: 'module'
}

Webpack будет генерировать:

<script type="module">

Свойство charset

Добавляет charset в script-теги.

output: {
    charset: true
}

Результат:

<script charset="utf-8">

Свойство environment

Позволяет сообщить Webpack о поддерживаемых возможностях JavaScript.

Пример:

output: {
    environment: {
        arrowFunction: true,
        const: true
    }
}

Webpack сможет генерировать более современный код.


Runtime-файлы

Webpack создаёт runtime-код:

  • загрузчик модулей;
  • систему chunk loading;
  • кеш модулей;
  • механизм dynamic import.

Настройка:

optimization: {
    runtimeChunk: 'single'
}

Результат:

runtime.js
app.js
vendors.js

Использование output в development

Development-конфигурация:

output: {
    filename: '[name].js',
    path: path.resolve(__dirname, 'dist'),
    publicPath: '/'
}

Особенности:

  • отсутствие hash;
  • читаемые имена;
  • быстрая пересборка.

Использование output в production

Production-конфигурация:

output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'js/[name].[contenthash].js',
    chunkFilename: 'js/[name].[contenthash].chunk.js',
    assetModuleFilename: 'assets/[name].[hash][ext]',
    publicPath: '/',
    clean: true
}

Практическая структура production-сборки

Конфигурация:

output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'js/[name].[contenthash].js',
    chunkFilename: 'js/[name].[contenthash].js',
    assetModuleFilename: 'assets/[name].[hash][ext]',
    clean: true
}

Результат:

dist/
├── js/
│   ├── app.21a1f.js
│   ├── vendor.99d2c.js
│   └── profile.7ab44.js
│
├── assets/
│   ├── logo.12f33.svg
│   ├── hero.9d123.png
│   └── font.ae22f.woff2
│
└── index.html

Ошибки при настройке output

Использование относительного пути

Неправильно:

path: './dist'

Отсутствие publicPath

Может ломать lazy loading.


Использование [fullhash]

Ухудшает кэширование.


Одинаковые имена chunk-файлов

Неправильно:

filename: 'bundle.js',
chunkFilename: 'bundle.js'

Возможна перезапись файлов.


Отсутствие clean

В каталоге остаются старые ассеты.


Рекомендуемый production-шаблон

const path = require('path');

module.exports = {
    output: {
        path: path.resolve(__dirname, 'dist'),

        filename: 'js/[name].[contenthash].js',

        chunkFilename: 'js/[name].[contenthash].chunk.js',

        assetModuleFilename: 'assets/[name].[hash][ext]',

        publicPath: '/',

        clean: true
    }
};

Такая конфигурация обеспечивает:

  • стабильную структуру проекта;
  • эффективное кэширование;
  • корректную загрузку чанков;
  • удобную организацию файлов;
  • совместимость с production-инфраструктурой.