Формат и расположение webpack.config.js

Файл webpack.config.js является центральной точкой конфигурации сборщика Webpack и определяет структуру всего процесса сборки. Несмотря на то, что Webpack допускает альтернативные способы конфигурирования через CLI или программный API, именно конфигурационный файл формирует основу большинства реальных проектов. Его формат, расположение и организация напрямую влияют на читаемость, масштабируемость и поддержку сборочной системы.

Webpack поддерживает несколько форматов конфигурации: CommonJS, ESM и функцию, возвращающую конфигурационный объект. На практике наиболее распространён CommonJS-вариант, поскольку он исторически связан с Node.js и обеспечивает максимальную совместимость с экосистемой инструментов.

Типичная структура файла выглядит следующим образом:

module.exports = {
  mode: 'development',
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: __dirname + '/dist'
  }
};

Конфигурация представляет собой обычный JavaScript-объект, где каждый ключ отвечает за определённый аспект сборки: входные точки, выходные файлы, загрузчики, плагины и режим работы.

ESM-вариант используется реже, но становится актуальным в современных проектах:

export default {
  mode: 'production',
  entry: './src/index.js'
};

Функциональный формат применяется при необходимости динамической генерации конфигурации, например, в зависимости от окружения:

module.exports = (env, argv) => ({
  mode: argv.mode || 'development',
  entry: './src/index.js'
});

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

Стандартное расположение webpack.config.js

По умолчанию Webpack ищет файл конфигурации в корне проекта. Это означает, что файл должен находиться на одном уровне с package.json:

project/
 ├── src/
 ├── dist/
 ├── package.json
 └── webpack.config.js

Такое расположение считается стандартным и обеспечивает автоматическое обнаружение конфигурации при запуске команды:

npx webpack

При наличии файла в корне Webpack использует его автоматически без дополнительных параметров.

Альтернативное расположение конфигурации

Webpack позволяет задавать произвольный путь к конфигурационному файлу через CLI-флаг --config. Это используется в проектах с несколькими конфигурациями или нестандартной структурой директорий.

Пример:

npx webpack --config build/webpack.config.js

Структура проекта в этом случае может быть следующей:

project/
 ├── build/
 │    └── webpack.config.js
 ├── src/
 ├── dist/
 └── package.json

Такой подход часто применяется для разделения конфигураций по окружениям:

build/
 ├── webpack.dev.js
 ├── webpack.prod.js
 └── webpack.common.js

Каждый файл отвечает за отдельную часть сборочного процесса, а объединение выполняется через функцию или утилиты вроде webpack-merge.

Разделение конфигурации по окружениям

При росте проекта единый файл конфигурации становится перегруженным. Поэтому часто используется модульная структура, где базовая конфигурация выделяется отдельно, а окружения наследуют её.

Базовый файл:

// webpack.common.js
module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: __dirname + '/dist'
  }
};

Конфигурация разработки:

const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');

module.exports = merge(common, {
  mode: 'development',
  devtool: 'source-map'
});

Конфигурация продакшена:

const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');

module.exports = merge(common, {
  mode: 'production',
  optimization: {
    minimize: true
  }
});

Такое разделение повышает управляемость конфигурации и снижает риск ошибок при внесении изменений.

Использование TypeScript для конфигурации

Webpack поддерживает конфигурацию на TypeScript через предварительную трансляцию или использование ts-node. В этом случае файл может называться webpack.config.ts:

import { Configuration } from 'webpack';

const config: Configuration = {
  mode: 'development',
  entry: './src/index.ts'
};

export default config;

Для запуска требуется соответствующая настройка среды выполнения, но такой подход обеспечивает строгую типизацию и автодополнение.

Условная конфигурация внутри одного файла

Вместо разделения файлов иногда используется логика внутри одного конфигурационного файла. Это упрощает структуру, но может усложнить чтение при увеличении объёма настроек.

Пример:

const isProd = process.env.NODE_ENV === 'production';

module.exports = {
  mode: isProd ? 'production' : 'development',
  devtool: isProd ? false : 'source-map',
  entry: './src/index.js'
};

Такой подход позволяет поддерживать единый файл при условии умеренной сложности проекта.

Подключение вспомогательных модулей

Конфигурационный файл Webpack является полноценным JavaScript-модулем, что позволяет использовать любые возможности Node.js: импортировать модули, читать файловую систему, вычислять пути.

Пример использования path:

const path = require('path');

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

Использование path.resolve предпочтительнее строковой конкатенации, поскольку обеспечивает корректную работу на разных операционных системах.

Особенности загрузки конфигурации

При запуске Webpack процесс поиска конфигурации происходит в следующем порядке:

  1. Проверка параметра --config
  2. Поиск webpack.config.js в корне проекта
  3. Использование встроенной конфигурации (если указана через CLI)

Если файл отсутствует, Webpack работает в режиме с минимальной конфигурацией, что подходит только для простых сценариев.

Множественные конфигурации

Webpack поддерживает экспорт массива конфигураций, что позволяет собирать несколько бандлов за один запуск.

Пример:

module.exports = [
  {
    name: 'client',
    entry: './src/client.js',
    output: {
      filename: 'client.bundle.js',
      path: __dirname + '/dist'
    }
  },
  {
    name: 'admin',
    entry: './src/admin.js',
    output: {
      filename: 'admin.bundle.js',
      path: __dirname + '/dist'
    }
  }
];

Каждая конфигурация обрабатывается независимо, но в рамках одного процесса сборки.

Влияние структуры проекта на расположение конфигурации

Расположение webpack.config.js часто отражает архитектуру проекта. В монорепозиториях файл может находиться в каждом пакете:

packages/
 ├── app/
 │    └── webpack.config.js
 ├── admin/
 │    └── webpack.config.js

В таких случаях каждая часть системы имеет собственный процесс сборки, адаптированный под конкретные задачи.

Интеграция с инструментами сборки

При использовании систем вроде npm scripts или CI/CD конфигурация Webpack часто указывается явно:

{
  "scripts": {
    "build": "webpack --config build/webpack.prod.js",
    "dev": "webpack --config build/webpack.dev.js"
  }
}

Такой подход фиксирует используемую конфигурацию и исключает неоднозначность между окружениями.

Организация больших конфигурационных файлов

При увеличении объёма webpack.config.js его структура обычно разбивается на логические блоки:

  • entry
  • output
  • module
  • plugins
  • optimization
  • resolve

Каждый блок отвечает за отдельную часть процесса сборки, а их порядок в файле влияет только на читаемость, но не на выполнение. Webpack обрабатывает объект конфигурации как единое целое, не зависящее от порядка ключей.

В крупных проектах часто выделяют отдельные модули для каждого блока:

config/
 ├── entry.js
 ├── output.js
 ├── module.js
 ├── plugins.js
 └── optimization.js

И затем собирают их в общий конфигурационный файл через импорт и объединение объектов.

Роль относительных путей и контекста

Расположение webpack.config.js влияет на значение __dirname, которое используется для вычисления путей сборки. Это особенно важно при настройке output.path и других файловых операций.

Контекст выполнения всегда определяется расположением самого конфигурационного файла, поэтому перемещение webpack.config.js в поддиректорию требует пересмотра всех относительных путей внутри него.

Поведение при нестандартных сценариях запуска

При запуске Webpack через сторонние инструменты, такие как Webpack Dev Server или интеграции с фреймворками, конфигурационный файл может быть обёрнут или расширен. В таких случаях фактическое расположение файла сохраняет значение, но доступ к нему осуществляется через промежуточные слои.

Некоторые фреймворки генерируют временные конфигурации на основе пользовательских настроек, однако базовый webpack.config.js остаётся отправной точкой для всех преобразований.