- PVSM.RU - https://www.pvsm.ru -
Webpack [1] считается лучшим инструментом для сборки приложений на React и Redux. Полагаю, многие из тех, кто сегодня использует Angular 2 и другие фреймворки, не обходят вниманием и Webpack. И поскольку начинать работу с данным инструментом всегда непросто, я решил посвятить этой теме несколько публикаций в надежде облегчить старт другим разработчикам и заодно продемонстрировать некоторые особенности Webpack.
Когда я впервые увидел его файл конфигурации, он показался мне крайне странным и путанным. Но спустя некоторое время я понял, что всё дело в уникальном синтаксисе Webpack и несколько иной философии, которая может поначалу немного сбить с толку. Но, с другой стороны, именно эта новая философия и делает Webpack таким популярным.
Можно выделить 2 основных принципа философии Webpack:
А теперь давайте наконец перейдем к особенностям Webpack.
Прежде всего нужно понять, что Webpack имеет множество функций, часть которых ориентирована на development, другая – на production, а третья – на то и на другое.
Пример 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”
}
Важно отметить что Webpack, как сборщик модулей, предоставляет 2 интерфейса:
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:
//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
Entry передает в Webpack данные о том, где находится корневой модуль или точка входа. Это может быть строка, массив или объект – причем разные типы используются для разных целей.
Если у вас всего одна точка входа (как в большинстве приложений), вы можете выбрать любой формат, и результат будет тот же.
Разные типы entry с одинаковым результатом
entry – массив
Но, если вы хотите добавить несколько файлов, не зависящих друг от друга, можно использовать формат массива.
Например, если вам понадобится googleAnalytics.js в вашем HTML, можно сделать так, чтобы Webpack добавил этот файл в конец bundle.js:
entry – объект
Предположим, у вас настоящее многостраничное приложение, не SPA с мультипросмотром, а несколько HTML-файлов (index.html и profile.html). С помощью Webpack вы можете сразу сгенерировать множество бандлов, используя объект entry.
Файл конфигурации на примере ниже будет генерировать 2 JS-файла: indexEntry.js и profileEntry.js, которые можно использовать в index.html и profile.html соответственно.
Пример использования:
//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-файла.
output сообщает Webpack, где и как хранить результирующие файлы. У output есть 2 свойства, path и publicPath, поначалу это может немного смутить.
Свойство path сообщает Webpack, где хранить результат, тогда как свойство publicPath используется в нескольких плагинах Webpack для обновления URL внутри CSS- и HTML-файлов во время генерации production-сборок.
Использование свойства publicPath для development и production
Предположим, в вашем CSS-файле содержится URL для загрузки ./test.png на localhost. Но на production файл test.png может быть расположен на CDN, тогда как ваш сервер Node.js может работать на Heroku [2]. Значит, работая на production, вам придется вручную обновлять URL во всех файлах, чтобы они указывали на CDN.
Но вместо этого можно применить свойство publicPath, а также целый ряд сопряженных плагинов, чтобы автоматически обновлять все URL при генерации production-сборок.
Пример 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’);
}
Загрузчики – это дополнительные узловые модули, которые помогают загружать или импортировать файлы разных типов в совместимых с браузерами форматах – 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)
}]
Вот как это работает:
Загрузчики можно настраивать так, чтобы они работали по-разному в зависимости от параметров передачи.
В следующем примере url-loader настроен таким образом, чтобы использовать DataURL для изображений размером менее 1024 байт и URL для изображений размером более 1024 байт. Это можно осуществить, передав параметр limit одним из двух способов:
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”]
}
Плагины – это дополнительные узловые модули, которые работают с результирующим бандлом.
К примеру, 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)
}]
Как вы успели заметить, загрузчики работают на отдельном файловом уровне во время генерации бандла или перед ней.
В свою очередь, плагины работают на уровне бандла или фрагмента по окончании генерации бандла. А некоторые плагины вроде commonsChunksPlugins [6] пошли еще дальше и изменили способ создания самих бандлов.
Многие файлы конфигурации 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
Нажмите здесь для печати.