Webpack — это статический сборщик модулей JavaScript в единый JS-файл (инструмент, позволяющий скомпилировать несколько модулей в один файл), содержащий все необходимое для запуска приложения.
Webpack применяют как при frontend, так и в backend разработке на Node.js. Он анализирует модули приложения, создает на основе операторов import и/или require() граф зависимостей модулей и собирает модули в правильном порядке в один или более бандл (bundle, узел), на который может ссылаться файл «index.html».
Официальный сайт проекта: https://webpack.js.org/
Для работы сборщика webpack необходимо установить (возможны другие варианты используемых программ):
- платформу Node.JS (https://nodejs.org) - подробнее читай Node.js как среда выполнения JS;
- терминал Git Bash (приложение для сред Microsoft Windows, которое предоставляет эмуляцию bash (командной оболочки), используемую для запуска Git из командной строки) (https://git-scm.com/) - подробнее читай Git Bash в VS Code.
- создать директорию src для хранения файлов приложения:
- src/app для файлов JavaScript;
- src/public для ресурсов проекта и статических файлов;
- src/style для глобальных стилей проекта;
- инициализировать проект в среде Node.JS через терминал Git Bash командой npm init (в корне проекта);
- установить webpack (см. ниже);
- проверить настройки в разделах файла package.json (раздел "scripts" должен содержать строку (как минимум) со свойством { "build": "webpack" });
- создать в корне проекта конфигурационный файл webpack.config.js (является вспомогательным инструментом сборщика webpack, в основное приложение включен не будет):
- вручную или
- командой npx webpack-cli init (быстрая генерация файла конфигурации webpack.config.js для вашего проекта, задаст несколько вопросов перед созданием файла конфигурации), при необходимости откорректировать;
- запустить webpack из командной строки командой npm run build (команда build имеет вариации в зависимости от настроек, указанных в разделе "scripts" файла package.json;
- после работы сборщика проверить создание результирующей директории и выходного файла по указанному в webpack.config.js пути.
Установка Webpack
Перед установкой webpack необходимо для инициализации проекта и создания файла package.json, определяющего настройки проекта (зависимости, скрипты, название и т.д.), запустить npm в корневой папке проекта командой npm init:
- npm init -y (флаг -y - настройки по умолчанию, для быстрой инициализации).
Webpack может быть установлен с помощью npm (node package manager) в рабочую папку в составе двух пакетов (webpack и webpack-cli):
- глобально, командой npm i -g webpack webpack-cli ;
- локально для каждого проекта (рекомендуется), командой npm i webpack webpack-cli --save-dev.
webpack - собственно сборщик модулей и ресурсов (функционал сборщика);
webpack-cli - интерфейс командной строки (отвечает за доступ к webpack через команды консоли (терминала).
Посмотреть версию установленного webpack можно с помощью команд:
npm list webpack
webpack --version (или webpack -v)
Подробнее по флагам https://docs.npmjs.com/cli/v7/commands/npm-install
Указанные флаги при установке пакета влияют на раздел файла package.json, в который пропишутся его имя и версия:
- -S или, --save, пакет будет отображается в разделе dependencies:{};
- -P, --save-prod: сохранит в "dependencies": { }. Это код для продакшена, он будет включен в конечный продукт. Добавляйте сюда только те библиотеки, которые будут использованы при работе вашего конечного продукта (вэб-страницы, например).
- -D, --save-dev: сохранит пакет в "devDependencies": { }. Это пакеты, которые вы используете в процессе девелопмента, препроцессоры LESS, SASS, валидаторы кода, JShint Slint, препроцессоры JS: Babel. Эти пакеты не будут включены в конечный продукт.
- -O, --save-optional: пакет будет добавлен в "optionalDependencies": { }. Эти пакеты могут быть использованы в работе, но если они будут недоступны или произойдет ошибка при их установке, то npm просто пропустит их и продолжит работу.
- --no-save: запрещает сохранять пакет в package.json.
Дополнительные флаги:
- -E, --save-exact: сохранит версию пакета точно, как указано.
- -B, --save-bundle: сохранит пакет в "bundleDependencies": { }.
До установки webpack:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
{ "name": "modules", "version": "1.0.0", "description": "webpack course", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [ "js", "javascript" ], "author": "NAV", "license": "ISC" } |
После установки webpack с флагом -D:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
{ "name": "modules", "version": "1.0.0", "description": "webpack course", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [ "js", "javascript" ], "author": "NAV", "license": "ISC", "devDependencies": { // (<em>добавился раздел "devDependencies": {}</em>) "webpack": "^5.53.0", "webpack-cli": "^4.8.0" } } |
Начальная настройка сборщика webpack
Подробнее на https://webpack.js.org
Если по какой-то причине вы хотите использовать другой файл конфигурации, то вы можете указать его через строку файла package.json с помощью флага --config:
1 2 3 |
"scripts": { "build": "webpack --config prod.config.js" } |
Начальная настройка сборщика webpack осуществляется через конфигурационный файл webpack.config.js (созданный вручную или с помощью webpack-cli) в корневой директории проекта, в котором необходимо определить свойства в разделах:
- entry – точку входа, начальный файл, который webpack будет использовать для построения внутреннего графа зависимостей модулей и библиотек (все параметры по ссылке https://webpack.js.org/configuration/entry-context/);
- output – вывод указывает путь, по которому webpack должен размещать сборку созданных бандлов (узлов или пакетов) и как он будет называть эти файлы (по умолчанию этот путь ./dist) (все параметры по ссылке https://webpack.js.org/configuration/output/);
- module – загрузчики (лоадеры), позволяют webpack обрабатывать не только файлы JavaScript, но и трансформировать другие типы файлов в модули, которые затем можно добавить в граф зависимостей приложения (а значит, и в бандл);
- plugins – плагины (используются для выполнения широкого круга задач).
Минимально файл может иметь вид:
1 2 3 4 5 6 7 8 9 |
const path = require("path"); // подключаем встроенный модуль path Node.JS module.exports = { entry: "./src/main.js", // точка входа output: { // результирующий файл filename: "bundle.js", path: path.resolve(__dirname, "dist"), }, }; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
// Generated using webpack-cli https://github.com/webpack/webpack-cli const path = require('path'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const WorkboxWebpackPlugin = require('workbox-webpack-plugin'); const isProduction = process.env.NODE_ENV == 'production'; const stylesHandler = isProduction ? MiniCssExtractPlugin.loader : 'style-loader'; const config = { entry: './src/index.js', output: { path: path.resolve(__dirname, 'dist'), }, plugins: [ // Add your plugins here // Learn more about plugins from https://webpack.js.org/configuration/plugins/ ], module: { rules: [ { test: /\.(js|jsx)$/i, loader: 'babel-loader', }, { test: /\.css$/i, use: [stylesHandler,'css-loader'], }, { test: /\.(eot|svg|ttf|woff|woff2|png|jpg|gif)$/i, type: 'asset', }, // Add your rules for custom modules here // Learn more about loaders from https://webpack.js.org/loaders/ ], }, }; module.exports = () => { if (isProduction) { config.mode = 'production'; config.plugins.push(new MiniCssExtractPlugin()); config.plugins.push(new WorkboxWebpackPlugin.GenerateSW()); } else { config.mode = 'development'; } return config; }; |
Подробнее о модуле path https://nodejs.org
Модуль path предоставляет методы для работы с путями к файлам и каталогам. Доступ к нему можно получить, подключив его с помощью строки:
const path = require('path');
Метод path.resolve () преобразует последовательность путей или сегментов пути в абсолютный путь, например:
1 2 3 4 5 6 7 |
path.resolve('/foo/bar', './baz'); // '/foo/bar/baz' path.resolve('/foo/bar', '/tmp/file/'); // '/tmp/file' path.resolve('/a', '/b') // '/b' path.resolve('a', 'b', 'c'); // C:\{current_working_directory}\a\b\c |
__dirname в качестве аргумента в любом случае является абсолютным путем.
path.resolve() всегда будет приводить к абсолютному URL и будет использовать рабочий каталог в качестве основы для разрешения этого пути.
Метод path.join () объединяет все заданные сегменты пути вместе с помощью разделителя, зависящего от платформы, в качестве разделителя, а затем нормализует полученный путь как относительный:
1 2 3 |
path.join('/a', '/b') // '/a/b' path.join('/foo', 'bar', 'baz/asdf', 'quux', '..'); // '/foo/bar/baz/asdf' |
Различия в обработке сегментов, начинающихся с / :
- join() просто объединит его с предыдущим аргументом;
- resolve() будет рассматривать его как корневой каталог и игнорировать все предыдущие пути.
Запуск webpack
webpack имеет следующие режимы:
- development (режим разработки);
- production (по умолчанию).
Режим development:
- качество оптимизации итогового файла хуже, чем в production;
- работает быстрее;
- не удаляет комментарии;
- предоставляет более подробные сообщения об ошибках и способы их решения;
- облегчает отладку приложения.
Режим production:
- работает медленнее, чем development;
- создает более оптимизированный бандл (файл меньше по размеру).
Если webpack установлен глобально, его можно вручную запустить из командной строки.
Если файл package.json содержит раздел "scripts" следующего наполнения:
1 2 3 4 5 |
"scripts": { "build": "webpack --mode=production --node-env=production", "build:dev": "webpack --mode=development", "build:prod": "webpack --mode=production --node-env=production", }, |
то запустить webpack в соответствующем режиме можно из командной строки командами:
- npm run build
- npm run build:dev
- npm run build:prod.
Если указанного раздела нет, то его можно создать вручную.
Просмотр изменений бандла
Webpack может автоматически перестраивать бандл, когда в вашем приложении происходят изменения. Для этого в файл package.json необходимо добавить строки:
1 2 3 |
"scripts": { "watch": "webpack --watch" } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
{ "name": "my-webpack-project", "version": "1.0.0", "description": "My webpack project", "main": "main.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "webpack --mode=production --node-env=production", "build:dev": "webpack --mode=development", "build:prod": "webpack --mode=production --node-env=production", "watch": "webpack --watch" }, "keywords": [ "js", "javascript" ], "author": "NAV", "license": "ISC", "devDependencies": { "@babel/core": "^7.15.5", "@babel/plugin-proposal-class-properties": "^7.14.5", "@babel/preset-env": "^7.15.6", "@webpack-cli/generators": "^2.3.0", "babel-loader": "^8.2.2", "css-loader": "^6.3.0", "html-webpack-plugin": "^5.3.2", "mini-css-extract-plugin": "^2.3.0", "style-loader": "^3.2.1", "webpack": "^5.53.0", "webpack-cli": "^4.8.0", "workbox-webpack-plugin": "^6.3.0" } } |
Запуск осуществляется в командной строке командой:
npm run watch
Бандл изменяется только в том случае, если в сборке нет ошибок. Если же ошибки присутствуют, watch покажет их и продолжит следить за изменениями.
Генерация Source Maps (для просмотра исходного кода сгенерированных файлов)
Подробнее...
Транспилированный webpack код JavaScript становится трудночитаемым и затрудняет поиск и исправление ошибок.
Source Map - это JSON-файл, который содержит информацию о том, как транспилировать код обратно в исходный код.
Source Maps можно сгенерировать, используя свойство конфигурации devtool в файле webpack.config.js, например:
1 2 3 4 5 6 7 |
module.exports = { /*...*/ devtool: "source-map", /*...*/ }; |
devtool имеет множество возможных значений, из которых наиболее часто используются:
- none - не добавляет Source Maps;
- source-map - для режима production, предоставляет отдельную Source Map, которую можно свернуть и добавляет ссылку в бандл;
- inline-source-map - для режима development, встраивает Source Maps в качестве data:URL.