Знакомство с Webpack

Наверно, уже каждый разработчик хотя бы мало-мальски интересующийся новостями в своей профессиональной сфере слышал про webpack. Что это за зверь, и для чего он нужен, мы с вами разберём сегодня?

Начнём с определения. Webpack — это невероятно мощный, гибкий и популярный сборщик модулей JavaScript. Он уже успел не раз удивить JS-сообщество своими возможностями, завоевав сердца многих разработчиков.

Вся конфигурация Webpack представляет из себя обычный CommonJS-модуль, расположенный в файле webpack.config.js. Для того, чтобы познакомиться с этим инструментом, необходимо понимать базовые термины и концепции, лежащие в его основе, четыре кита, на которых всё держится. Верхнеуровневых понятий, на которых всё это работает, всего четыре: точка входа (Entry), место назначения, куда будет производиться вывод результатов (Output), загрузчики (Loaders) и плагины (Plugins). Расскажу о каждом из них подробнее.

Точка входа (Entry)

В ходе своей работы Webpack строит граф всех зависимостей нашего приложения. Начало этого графа и называют точкой входа (entry point). Эта точка говорит Webpack, откуда начинать обход графа зависимостей, чтобы собрать всё в один bundle — результат сборки модулей в один файл. Точкой входа можно считать тот самый файл, который надо дёрнуть, чтобы ваше приложение заработало.

Указать точку входа можно при помощи свойства entry в объекте конфигурации webpack.

module.exports = {
  entry: './app/index.js'
};

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

Вывод результата (Output)

Как только мы собрали все, что хотели, в один пакет, возникает необходимость где-то это всё разместить. Для этого надо указать свойство webpack-конфигурации output, которое показывает, где и как располагать результат сборки.

var path = require('path');

module.exports = {
  entry: './app/index.js',
  output: {
    path: path.resolve(__dirname, 'build'),
    filename: 'my-bundle.js'
  }
};

В этом примере через свойства output.filename и output.path мы говорим webpack, в какой bundle и в какой директории выгрузить получившийся код нашего приложения.

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

Загрузчики (Loaders)

Наша цель — чтобы все статические файлы в нашем проекте стали заботой webpack’а, а не браузера. Но это не значит, что все они должны быть объединены в один файл. Webpack обрабатывает каждый файл (.css, .html, .scss, .jpg и т.д.) как модуль. При этом сам webpack понимает только JavaScript.

Загрузчики webpack трансформируют эти файлы в модули согласно тому, как они добавлены в граф зависимостей. По своей сути, загрузчики — это трансформации, которые производятся над ресурсом зависимости вашего приложения. Они представляют из себя функции, запускаемые на NodeJS, принимающие на вход в качестве параметра содержимое файла зависимости и возвращающие новое содержимое.

На самом верхнем уровне у загрузчиков есть две задачи:

  • Определить файлы, которые следует трансформировать этим загрузчиком, с помощью свойства test;
  • Трансформировать этот файл так, чтоб он мог быть добавлен в наш граф зависимостей и, в конечном счёте, в наш bundle, с помощью свойства use.
var path = require('path');

module.exports = {
  entry: './app/index.js',
  output: {
    path: path.resolve(__dirname, 'build'),
    filename: 'my-bundle.js'
  },
  module: {
    rules: [
      {test: /\.(js|jsx)$/, use: 'babel-loader'}
    ]
  }
};

В этой конфигурации мы определили правило в соответствующем списке правил модуля с двумя обязательными свойствами: test и use. Это говорит webpack-компилятору примерно следующее:

«Привет, компилятор Webpack! Если ты при просмотре моего кода вдруг повстречаешь пути, в которых содержатся файлы с расширением ‘.js’ или ‘.jsx’ внутри вызовов require() или в выражении import, используй, пожалуйста, babel-loader для того, чтоб трансформировать его перед добавлением в сборку. Спасибо, друг!»

Важно помнить, когда определяете правила в конфиге webpack, что определять их нужно в module.rule, а не в rules. Если вы сделаете это неправильно, webpack будет на вас орать и ругаться красными буквами.

Конечно, настройка загрузчиков этими свойствами не ограничивается. Но давайте перейдём к плагинам.

Плагины (Plugins)

Поскольку загрузчики выполняют только трансформацию и только по каждому файлу в отдельности, плагины чаще всего используются (но этим не ограничиваются) в операциях и специальной функциональности над «компиляциями» или «кусочками» наших собранных модулей. Webpack’овская система плагинов очень мощна и хорошо настраиваема.

Чтобы использовать плагин, нам нужно только получить его через require() и добавить в массив плагинов. Большинство плагинов можно настроить с помощью опций. Поскольку мы можем использовать плагин несколько раз в одной конфигурации для разных целей, нам нужно создать его экземпляр, вызвав его с оператором new.

const HtmlWebpackPlugin = require('html-webpack-plugin'); // устанавливается отдельно через npm
const webpack = require('webpack'); // для доступа к встроенным плагинам
const path = require('path');

module.exports = {
  entry: './app/index.js',
  output: {
    path: path.resolve(__dirname, 'build'),
    filename: 'my-bundle.js'
  },
  module: {
    rules: [
      {test: /\.(js|jsx)$/, use: 'babel-loader'}
    ]
  },
  plugins: [
    new webpack.optimize.UglifyJsPlugin(),
    new HtmlWebpackPlugin({template: './app/index.html'})
  ]
};

В webpack есть встроенные плагины! Посмотреть их можно на странице «Plugins» в официальной документации.

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

Заключение

Вот и всё! Мы с вместе вами познакомились с webpack, разобрались в его основных концепциях, увидели примеры конфигурации и попробовали простые случаи использования. Как вы видите, ничего в webpack страшного нет, всё достаточно просто! Поэтому не бойтесь и не ленитесь! Берите на своё вооружение этот новый для вас инструмент, учитесь, и вы увидите, что спектр его возможностей очень широк!

До новых статей!