Webpack - что это? Руководство по для новичков

В этом руководстве я познакомлю вас со всеми основными понятиями Webpack, которые помогут начать работу с этим сборщиком модулей.

В данном руководстве используется webpack 4.30.

Webpack-что это?

Webpack – это статический модульный сборщик. В проекте он обрабатывает все файлы и ресурсы как модули. При этом сборщик опирается на граф зависимостей, в котором описывается взаимосвязь модулей с помощью ссылок (операторы require и import).

Таким образом, webpack статически перемещается по всем модулям для построения графа и использует его для генерации одного бандла

Бандл – это файл JavaScript, содержащий код из всех модулей проекта и объединенных в правильном порядке. Когда webpack создает граф зависимостей, он не выполняет исходный код, а объединяет модули и их зависимости в бандл.

Базовые понятия Webpack

  • Entry – модуль, который используется для построения внутреннего графа зависимостей. С его помощью webpack определяет, от каких модулей и библиотек зависит точка входа (напрямую и не напрямую). Затем включает их в граф, пока не останется ни одной зависимости. По умолчанию для свойства entry установлено значение ./src/index.js. Но можно указать другой модуль в файле конфигурации сборщика.
  • Output – это свойство указывает, где webpack должен сохранять бандл и как называть его файл (или файлы). Значением по умолчанию является ./dist/main.js для основного бандла и ./dist для других сгенерированных файлов.
  • Загрузчики. По умолчанию webpack понимает только файлы JavaScript и JSON. Чтобы обработать другие типы файлов и конвертировать их в модули, сборщик использует загрузчики. Например, загрузчик может трансформировать файлы из языка CoffeeScript в JavaScript или встроенные изображения в URL-адреса. С помощью загрузчиков можно даже импортировать CSS-файлы прямо из модулей JavaScript.
  • Плагины. Используются для задач, которые не могут выполнять загрузчики.
  • Режимы. Webpack позволяет настроить режим на development, production или none. Благодаря этому он может использовать встроенные оптимизации для каждой среды. По умолчанию установлено значение Режим none означает, что все опции оптимизации по умолчанию будут отключены. Чтобы узнать больше об опциях, которые webpack использует в development и production, посетите страницу конфигурации режимов.

Как работает Webpack

В любом веб-проекте есть файлы HTML, CSS, JavaScript, ресурсы, как шрифты, изображения и т.д. Таким образом, рабочий процесс webpack включает в себя настройку файла index.html с соответствующими ссылками на CSS, JavaScript и необходимые ресурсы.

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

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

Если модуль содержит зависимости, процесс выполняется рекурсивно для каждой зависимости. Затем webpack объединяет все модули проекта в небольшое количество бандлов (обычно только один), чтобы их можно было загрузить в браузер.

Приступим

Файлы нашего проекта можно найти в репозитории на Github.

Сначала создадим новый каталог и перейдем в него. Затем инициализируем новый проект:

mkdir learn-webpack
cd learn-webpack
npm init -y

После этого нужно локально установить webpack и webpack CLI:

npm install webpack webpack-cli --save-dev

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

{
  "name": "learn_webpack",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo "Error: no test specified" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^4.30.0",
    "webpack-cli": "^3.3.0"
  }
}

Также webpack можно использовать в качестве менеджера задач. Для этого нужно разместить задачу и ее инструкции в разделе scripts файла package,json. Попробуем сделать это прямо сейчас. Откройте файл package.json и измените объект scripts следующим образом:

"scripts": {
  "test": "echo "Error: no test specified" && exit 1",
  "dev": "webpack --mode development",
  "build": "webpack --mode production"
},

Свойство scripts позволяет ссылаться на локально установленные пакеты npm по их именам. Мы используем его и флаг —mode для определения задач dev и build, которые будут запускать webpack в режиме разработки (npm run dev) и производства (npm run build) соответственно.

Создадим каталог src и поместим в него файл index.js. Теперь мы можем запустить задачу dev, чтобы webpack работал в режиме разработки:

$ npm run dev

> learn_webpack@1.0.0 dev C:UsersUserWebpacklearn_webpack
> webpack --mode development

Hash: 5bb3bdc1efd7b7f4b627
Version: webpack 4.30.0
Time: 226ms
Built at: 2019-04-16 17:48:32
  Asset     Size  Chunks             Chunk Names
main.js  3.8 KiB    main  [emitted]  main
Entrypoint main = main.js
[./src/index.js] 27 bytes {main} [built]

Отобразим результат работы сборщика в браузере. Для этого создадим файл index.html в каталоге dist:

<!doctype html>
<html>
  <head>
    <title>Getting Started</title>
  </head>
  <body>
    <script src="main.js"></script>
  </body>
</html>

Теперь, если мы откроем этот файл в браузере, то увидим сообщение Hello webpack.

В некоторых случаях создание файла index.html вручную может быть проблематичным. Например, если мы изменим имя точки входа, то сгенерированный пакет будет переименован. Но файл index.html по-прежнему будет ссылаться на старое имя. Поэтому нужно будет вручную обновлять HTML- файл каждый раз, когда понадобится переименовать точку входа или добавить новую. Этого можно избежать с помощью html-webpack-plugin. Установите этот плагин:

npm install html-webpack-plugin --save-dev

Чтобы активировать плагин, создайте файл webpack.config.js и поместите в него следующий код:

const HtmlWebpackPlugin = require("html-webpack-plugin");
const path = require('path');

module.exports = {
  plugins: [
    new HtmlWebpackPlugin({
      title: "Webpack Output",
    }),
  ],
};

Чтобы активировать плагин webpack, нужно включить его и добавить в массив plugins. При необходимости передаем плагину необходимые параметры.

Запустим сборку и посмотрим на результат:

$ npm run build

> learn_webpack@1.0.0 build C:UsersUserWebpacklearn_webpack
> webpack --mode production

Hash: e56a796f5ccfebcc8270
Version: webpack 4.30.0
Time: 1088ms
Built at: 2019-04-16 20:44:47
    Asset       Size  Chunks             Chunk Names
index.html  183 bytes          [emitted]
  main.js  956 bytes       0  [emitted]  main
Entrypoint main = main.js
[0] ./src/index.js 27 bytes {0} [built]
Child html-webpack-plugin for "index.html":
    1 asset
    Entrypoint undefined = index.html
    [2] (webpack)/buildin/global.js 472 bytes {0} [built]
    [3] (webpack)/buildin/module.js 497 bytes {0} [built]
        + 2 hidden modules

Откроем файл index.html. Как видим, плагин автоматически создает обновленный файл index.html, который использует параметр title из конфигурации:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Webpack Output</title>
  </head>
  <body>
  <script src="main.js"></script></body>
</html>

Теперь определим пользовательские имена для свойств input и output. В webpack.config.js перед свойством plugins добавляем следующий код:

entry: './src/app.js',
output: {
  filename: '[name].bundle.js',
  path: path.resolve(__dirname, 'dist')
},

После этого создадим файл src/component.js:

export default (text = "Hello webpack") => {
  const element = document.createElement("p");

  element.innerHTML = text;

  return element;
};

 Переименуем index.js в app.js, чтобы отразить внесенные изменения, и заменяем его содержимое следующим кодом:

import component from "./component";

document.body.appendChild(component());

Теперь запустим webpack:

$ npm run build

> learn_webpack@1.0.0 build C:UsersUserWebpacklearn_webpack
> webpack --mode production

Hash: 9f78936f8a2a21061f0b
Version: webpack 4.30.0
Time: 1689ms
Built at: 2019-04-17 23:43:40
        Asset       Size  Chunks             Chunk Names
    index.html  190 bytes          [emitted]
main.bundle.js   1.04 KiB       0  [emitted]  main
Entrypoint main = main.bundle.js
[0] ./src/app.js + 1 modules 227 bytes {0} [built]
    | ./src/app.js 79 bytes [built]
    | ./src/component.js 148 bytes [built]
Child html-webpack-plugin for "index.html":
    1 asset
    Entrypoint undefined = index.html
    [2] (webpack)/buildin/global.js 472 bytes {0} [built]
    [3] (webpack)/buildin/module.js 497 bytes {0} [built]
        + 2 hidden modules

Изучим и проясним для себя информацию из вывода, предоставляемого webpack. Вверху указаны хэш сборки, версия webpack и время выполнения сборки.

Далее идет перечень файлов, сгенерированных в каталоге dist (index.html и main.bundle.js). Под ним расположен модуль ввода (app.js) и его зависимость (component.js). Вывод после Child html-webpack-plugin for «index.html»: относится к работе html-webpack-plugin. Поэтому его игнорировать.

Теперь в папке dist есть новый сгенерированный пакетный файл main.bundle.js. Если открыть файл index.html в браузере, то мы увидим сообщение Hello webpack. Кроме этого в коде файла index.html изменилось значение атрибута src в теге script на main.bundle.js.

Работа со скриптами

Мы рассмотрим, как перенести ES6 в ES5-совместимый код, который работает во всех браузерах. Начнем с выполнения приведенной ниже команды:

npm run dev -- --devtools false

Затем откроем файл main.bundle.js:

/***/ "./src/component.js":
/*!**************************!*
  !*** ./src/component.js ***!
  **************************/
/*! обеспечение экспорта: по умолчанию */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* экспорт по умолчанию */ __webpack_exports__["default"] = ((text = "Hello webpack") => {
  const element = document.createElement("p");

  element.innerHTML = text;

  return element;
});

/***/ })

Современные функции из стандарта JavaScript ES6 (стрелочная функция и объявление const) из модуля component.js по умолчанию не преобразованы в ES5-совместимый код. Чтобы код работал в более старых браузерах, необходимо добавить загрузчик Babel:

npm install babel-loader @babel/core @babel/preset-env --save-dev

Затем в файле webpack.config.js добавьте module после свойства output:

module: {
  rules: [
    {
      test: /.js$/,
      exclude: /node_modules/,
      use: {
        loader: 'babel-loader',
        options: {
          presets: ['@babel/preset-env']
        }
      }
    }
  ]
},

При определении правил для загрузчика webpack нужно установить три основных свойства:

  • test – описывает, какие файлы следует трансформировать.
  • exlude – определяет, какие файлы из загрузчика не следует обрабатывать.
  • use – указывает, какой загрузчик следует использовать для сопоставленных модулей.

Еще раз введите приведенную ниже команду:

npm run dev -- --devtools false

На этот раз код в файле main.bundle.js компилируется в следующий:

/***/ "./src/component.js":
/*!**************************!*
  !*** ./src/component.js ***!
  **************************/
/*! exports provided: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* экспорт по умолчанию */ __webpack_exports__["default"] = (function () {
  var text = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "Hello webpack";
  var element = document.createElement("p");
  element.innerHTML = text;
  return element;
});

/***/ })

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

Работа со стилями

Чтобы добавить CSS в проект, потребуются два загрузчика:

npm install css-loader style-loader --save-dev

css-loader преобразует CSS-код в JavaScript и разрешает любые зависимости, а style-loader выводит CSS в теге <style> в HTML- документе.

Добавим в файл webpack.config.js необходимую конфигурацию:

{
  test: /.css$/,
  use: [{ loader: 'style-loader' }, { loader: 'css-loader' }],
},

Создадим файл src/style.css:

p {
  color: red;
}

Затем импортируем его в файл app.js:

import './style.css'

Когда мы запустим webpack, а затем откроем файл index.html, сообщение «Hello webpack будет красного цвета.

Управление ресурсами

Далее мы рассмотрим пример с изображениями. Сначала нужно установить загрузчик файлов:

npm install file-loader --save-dev

Затем добавить новое правило в файл webpack.config.js:

{
  test: /.(png|jpg|gif)$/,
  use: [
    {
      loader: 'file-loader'
    },
  ],
},

Чтобы протестировать загрузчик, создадим файл image-component.js в каталоге src со следующим кодом:

import image from "./image.png"

const img = document.createElement("img")
img.src = image
document.body.appendChild(img)

Здесь мы  импортируем изображение как модуль и используем его в теге <img/>. Нужно поместить это изображение в каталог src.

После этого импортируем компонент изображения в файл app.js:

import './image-component'

Теперь, когда мы запустим webpack и откроем страницу, над сообщением Hello webpack будет выводиться изображение.

Ускорение процесса разработки с помощью webpack-dev-server

Нам приходиться перестраивать проект всякий раз, когда вносим какие-то изменения в код. К счастью, webpack предоставляет веб-сервер, который автоматически создает и обновляет страницу. Чтобы установить его, запустите приведенную ниже команду:

npm install webpack-dev-server --save-dev

Чтобы использовать сервер, нужно обновить dev-скрипт в файле package.json:

"dev": "webpack-dev-server --mode development"

А затем настроить сервер в файле webpack.config.js, добавив следующее свойство:

devServer: {
  contentBase: './dist',
  open: true
},

После этого webpack-dev-server начинает обслуживать файлы из каталога dist и автоматически открывать страницу входа.

Теперь при запуске webpack (npm run dev) мы увидим, как страница открывается в браузере автоматически на localhost: 8080:

i 「wds」: Project is running at http://localhost:8080/
i 「wds」: webpack output is served from /
i 「wds」: Content not from webpack is served from ./dist

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

Очистка вывода

По мере расширения проекта папка dist становится дольно объемной. При каждой сборке webpack будет генерировать бандлы, и помещать их в папку dist. Но при этом сборщик не отслеживает, какие файлы используются в проекте по факту. Поэтому рекомендуется очищать папку dist перед каждой сборкой, чтобы генерировались только используемые файлы. Для этого нужно установить и настроить clean-webpack-plugin:

npm install --save-dev clean-webpack-plugin

В webpack.config.js:

const CleanWebpackPlugin = require('clean-webpack-plugin');

...

plugins: [
  ...
  new CleanWebpackPlugin()
],

Затем запустите webpack (npm run build) и проверьте папку dist. Теперь вы увидите в ней только файлы, сгенерированные из сборки. В нашем случае файл, который следует удалить, это main.js.

Заключение

Webpack – это полезный и мощный инструмент. В данном руководстве представлены только его базовые возможности. Но webpack способен на большее. Вот список ресурсов для дальнейшего изучения возможностей сборщика:

  • Официальная документация webpack.

Пожалуйста, оставьте ваши комментарии по текущей теме материала. За комментарии, лайки, отклики, дизлайки, подписки низкий вам поклон!

Пожалуйста, оставьте ваши мнения по текущей теме материала. Мы очень благодарим вас за ваши комментарии, дизлайки, лайки, отклики, подписки!

Ангелина Писанюкавтор-переводчик статьи «A Beginner’s Guide to Webpack»