- PVSM.RU - https://www.pvsm.ru -

10 особенностей Webpack

Webpack [1] считается лучшим инструментом для сборки приложений на React и Redux. Полагаю, многие из тех, кто сегодня использует Angular 2 и другие фреймворки, не обходят вниманием и Webpack. И поскольку начинать работу с данным инструментом всегда непросто, я решил посвятить этой теме несколько публикаций в надежде облегчить старт другим разработчикам и заодно продемонстрировать некоторые особенности Webpack.

10 особенностей Webpack - 1

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

Философия Webpack

Можно выделить 2 основных принципа философии Webpack:

  1. Что угодно может быть модулем. Модулями могут быть как JS-файлы, так и CSS-файлы, HTML-файлы или изображения. То есть можно использовать и require(“myJSfile.js”), и require(“myCSSfile.css”). Таким образом, вы можете разбивать любой артефакт на меньшие удобоуправляемые части, использовать их повторно и так далее.
  2. Загружайте только то, что вам нужно и когда вам нужно. Обычно сборщики модулей берут все модули и генерируют из них один большой файл bundle.js. Но во многих приложениях размер такого файла может достигать 10–15 MB – а это слишком много. Потому Webpack оснащен рядом функций, позволяющих делить код и генерировать множество bundle-файлов, а также асинхронно загружать необходимые части приложения тогда, когда это нужно.

А теперь давайте наконец перейдем к особенностям Webpack.

1. Development и production

Прежде всего нужно понять, что Webpack имеет множество функций, часть которых ориентирована на development, другая – на production, а третья – на то и на другое.

10 особенностей Webpack - 2

Пример Webpack-файлов для development и production

Большинство проектов используют так много функций, что у них, как правило, есть 2 больших файла конфигурации Webpack.

Для создания бандлов вам, скорее всего, потребуется писать скрипты в package.json, примерно так:

 “scripts”: {
  //npm run build to build production bundles
  “build”: “webpack --config webpack.config.prod.js”,
  //npm run dev to generate development bundles and run dev. server
  “dev”: “webpack-dev-server”
 }

2. webpack CLI и webpack-dev-server

Важно отметить что Webpack, как сборщик модулей, предоставляет 2 интерфейса:

  1. Инструмент webpack CLI – интерфейс по умолчанию (установлен как часть самого Webpack).
  2. Инструмент webpack-dev-server – сервер Node.js (нужно устанавливать отдельно).

Webpack CLI (подходит для production-сборок)

Этот инструмент берет опции через инструмент CLI, а также через файл конфигурации (по умолчанию – webpack.config.js) и передает их в Webpack для сборки.

И хотя вы можете начать изучение Webpack, используя CLI-инструмент, он по большей части пригодится вам только для последующей генерации production-сборок.

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

OPTION 1: 
//Install it globally
npm install webpack --g
//Use it at the terminal 
$ webpack //<--Generates bundle using webpack.config.js

OPTION 2 :
//Install it locally & add it to package.json
npm install webpack --save
//Add it to package.json's script 
“scripts”: {
 “build”: “webpack --config webpack.config.prod.js -p”,
 ...
 }
//Use it by running the following:
"npm run build"

Webpack-dev-server (подходит для development-сборок)

Это Express Node.js сервер, который работает на порту 8080. Этот сервер вызывает Webpack изнутри, что дает дополнительные возможности вроде перезагрузки браузера (Live Reloading) и/или замены только что измененного модуля (Hot Module Replacement, или HMR).

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

OPTION 1:
//Install it globally
npm install webpack-dev-server --save
//Use it at the terminal
$ webpack-dev-server --inline --hot
OPTION 2:
// Add it to package.json's script 

“scripts”: {
 “start”: “webpack-dev-server --inline --hot”,
 ...
 }
// Use it by running 
$ npm start
Open browser at:
http://localhost:8080

Webpack и опции инструмента webpack-dev-server

Стоит отметить, что некоторые опции, такие как inline и hot, используются только для инструмента webpack-dev-server, в то время как, скажем, hide-modules подходят только для CLI.

Опции webpack-dev-server CLI и опции config

Стоит также отметить, что существует 2 способа передачи опций в webpack-dev-server:

  1. через объект devServer файла webpack.config.js;
  2. через опции CLI.

//Via CLI
webpack-dev-server --hot --inline
//Via webpack.config.js
devServer: {
 inline: true,
 hot:true
 }

Я обнаружил, что devServer config (hot:true и inline:true) иногда не работает. Поэтому я предпочитаю передавать опции как CLI-опции внутри package.json, вот так:

//package.json
{
scripts: 
   {“start”: “webpack-dev-server --hot --inline”}
}

Примечание: убедитесь, что не передаете hot:true и -hot вместе.

Опции hot и inline для webpack-dev-server

Опция inline добавляет Live Reloading для всей страницы. Опция hot включает Hot Module Reloading – горячую перезагрузку модуля, которая перезагружает только измененный компонент (а не всю страницу). Если передать обе опции, то при изменении источника webpack-dev-server запустит прежде всего HMR и, только если это не сработает, перезагрузит всю страницу.

//When the source changes, all 3 options generates new bundle but,
 
//1. doesn't reload the browser page
$ webpack-dev-server
//2. reloads the entire browser page
$ webpack-dev-server --inline
//3. reloads just the module(HMR), or the entire page if HMR fails
$ webpack-dev-server  --inline --hot

3. entry–  строка, массив и объект

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

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

10 особенностей Webpack - 3
Разные типы entry с одинаковым результатом

entry  –  массив

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

Например, если вам понадобится googleAnalytics.js в вашем HTML, можно сделать так, чтобы Webpack добавил этот файл в конец bundle.js:

10 особенностей Webpack - 4

entry  – объект

Предположим, у вас настоящее многостраничное приложение, не SPA с мультипросмотром, а несколько HTML-файлов (index.html и profile.html). С помощью Webpack вы можете сразу сгенерировать множество бандлов, используя объект entry.

Файл конфигурации на примере ниже будет генерировать 2 JS-файла: indexEntry.js и profileEntry.js, которые можно использовать в index.html и profile.html соответственно.

10 особенностей Webpack - 5

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

//profile.html
<script src=”dist/profileEntry.js”></script>
//index.html
<script src=”dist/indexEntry.js”></script>

Примечание: название файла происходит от ключей объекта entry

entry  –  комбинация

Вы также можете использовать entry-массивы внутри entry-объекта. К примеру, следующий файл конфигурации сгенерирует 3 файла: index.js, profile.js и vendor.js, содержащий 3 vendor-файла.

10 особенностей Webpack - 6

4. output  –  path и publicPath

output сообщает Webpack, где и как хранить результирующие файлы. У output есть 2 свойства, path и publicPath, поначалу это может немного смутить.

Свойство path сообщает Webpack, где хранить результат, тогда как свойство publicPath используется в нескольких плагинах Webpack для обновления URL внутри CSS- и HTML-файлов во время генерации production-сборок.

10 особенностей Webpack - 7
Использование свойства publicPath для development и production

Предположим, в вашем CSS-файле содержится URL для загрузки ./test.png на localhost. Но на production файл test.png может быть расположен на CDN, тогда как ваш сервер Node.js может работать на Heroku [2]. Значит, работая на production, вам придется вручную обновлять URL во всех файлах, чтобы они указывали на CDN.

Но вместо этого можно применить свойство publicPath, а также целый ряд сопряженных плагинов, чтобы автоматически обновлять все URL при генерации production-сборок.

10 особенностей Webpack - 8
Пример publicPath production

// Development: Both Server and the image are on localhost
.image { 
  background-image: url(‘./test.png’);
 }
// Production: Server is on Heroku but the image is on a CDN
.image { 
  background-image: url(‘https://someCDN/test.png’);
 }

5. Загрузчики и цепочки загрузчиков

Загрузчики – это дополнительные узловые модули, которые помогают загружать или импортировать файлы разных типов в совместимых с браузерами форматах – JS, CSS и т. д. Последующие загрузчики также позволяют импортировать такие файлы в JS, используя require или import в ES6.

Например, вы можете использовать babel-loader для конвертации JS-файла, написанного на ES6, в совместимый с браузером ES5:

module: {
 loaders: [{
  test: /.js$/, ←Test for ".js" file, if it passes, use the loader
  exclude: /node_modules/, ←Exclude node_modules folder
  loader: ‘babel’ ←use babel (short for ‘babel-loader’)
 }]

Цепочки загрузчиков (работают справа налево)

Несколько загрузчиков для одного типа файлов можно объединить в цепочку. Формирование цепочек осуществляется справа налево, а загрузчики отделяются восклицательным знаком: «!».

Предположим, у нас есть CSS-файл myCssFile.css, и мы хотим выгрузить его содержимое в тег внутри HTML. Это можно сделать, используя 2 загрузчика: css-loader и style-loader.

module: {
 loaders: [{
  test: /.css$/,
  loader: ‘style!css’ <--(short for style-loader!css-loader)
 }]

Вот как это работает:

10 особенностей Webpack - 9

  1. Webpack осуществляет поиск взаимосвязей CSS-файлов внутри модулей. Иными словами, Webpack проверяет, имеет ли JS-файл require(myCssFile.css). Если обнаруживается взаимосвязь, Webpack сначала передает этот файл в css-loader.
  2. css-loader загружает в JSON все CSS-файлы и их собственные взаимосвязи (т. е. import [3] otherCSS). Затем Webpack передает результат в style-loader.
  3. style-loader берет JSON, добавляет его в стилевой тег  – – и вставляет этот тег в файл index.html.

6. Настройка загрузчиков

Загрузчики можно настраивать так, чтобы они работали по-разному в зависимости от параметров передачи.

В следующем примере url-loader настроен таким образом, чтобы использовать DataURL для изображений размером менее 1024 байт и URL для изображений размером более 1024 байт. Это можно осуществить, передав параметр limit одним из двух способов:

10 особенностей Webpack - 10

7. Файл .babelrc

babel-loader использует настройку presets, чтобы правильно конвертировать ES6 в ES5 и парсить React JSX в JS. Настройки можно передать через параметр query, как показано ниже:

module: {
  loaders: [
    {
      test: /.jsx?$/,
      exclude: /(node_modules|bower_components)/,
      loader: 'babel',
      query: {
        presets: ['react', 'es2015']
      }
    }
  ]
}

Тем не менее, во многих проектах настройки babel могут стать чересчур большими, потому лучше всего держать их в файле конфигурации babel-loader, который называется .babelrc. Загрузчик babel-loader автоматически загрузит файл .babelrc, если таковой существует.

Это должно выглядеть примерно так:

//webpack.config.js 
module: {
  loaders: [
    {
      test: /.jsx?$/,
      exclude: /(node_modules|bower_components)/,
      loader: 'babel'
    }
  ]
}

//.bablerc
{
 “presets”: [“react”, “es2015”]
}

8. Плагины

Плагины – это дополнительные узловые модули, которые работают с результирующим бандлом.

К примеру, uglifyJSPlugin [4] берет bundle.js, а затем минимизирует и обфусцирует его содержимое, чтобы уменьшить размер файла.

Аналогичным образом extract-text-webpack-plugin [5] внутренне использует css-loader и style-loader, чтобы собрать все CSS-файлы в одном месте. Этот плагин извлекает результат во внешний файл styles.css и добавляет ссылку на этот файл в index.html.

//webpack.config.js
//Take all the .css files, combine their contents and it extract them to a single "styles.css"
var ETP = require("extract-text-webpack-plugin");

module: {
 loaders: [
  {test: /.css$/, loader:ETP.extract("style-loader","css-loader") }
  ]
},
plugins: [
    new ExtractTextPlugin("styles.css") //Extract to styles.css file
  ]
}

Примечание: если вы хотите просто встроить CSS как элемент стиля в HTML, это можно сделать без плагина extract-text-webpack-plugin [5], а за счет CSS и загрузчиков стилей, как показано ниже:

module: {
 loaders: [{
  test: /.css$/,
  loader: ‘style!css’ <--(short for style-loader!css-loader)
 }]

9. Загрузчики и плагины

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

В свою очередь, плагины работают на уровне бандла или фрагмента по окончании генерации бандла. А некоторые плагины вроде commonsChunksPlugins [6] пошли еще дальше и изменили способ создания самих бандлов.

10. Разрешение файловых расширений

Многие файлы конфигурации Webpack имеют свойство разрешения расширений с пустой строкой, как показано ниже. Пустая строка нужна, чтобы способствовать импорту без расширений вроде require(“./myJSFile”) или импортировать myJSFile из ./myJSFile без файловых расширений.

{
 resolve: {
   extensions: [‘’, ‘.js’, ‘.jsx’]
 }
}

Вот и всё!

Автор: Plarium

Источник [7]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/javascript/183660

Ссылки в тексте:

[1] Webpack: https://webpack.github.io/

[2] Heroku: https://www.heroku.com/

[3] import: https://habrahabr.ru/users/import/

[4] uglifyJSPlugin: https://webpack.github.io/docs/list-of-plugins.html#uglifyjsplugin

[5] extract-text-webpack-plugin: https://github.com/webpack/extract-text-webpack-plugin

[6] commonsChunksPlugins: https://webpack.github.io/docs/list-of-plugins.html#commonschunkplugin

[7] Источник: https://habrahabr.ru/post/309230/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best