Ясной инструкции по сборке webpack для продакшена я не нашел. Поэтому решил написать эту статью. Надеюсь, пригодится.
Существует множество сборщиков скриптов. Я выбрал для себя Webpack по таким критериям:
- Гибкость настройки
- Большое количество плагинов и лоадеров
- Lazy loading
- Использование es6 и es7 синтаксиса с помощью babel-loader
Из недостатков я бы выделил отсутствие ясной документации. Для тех, кто никогда не сталкивался с Webpack, я рекомендую скринкаст от Ильи Кантора. В данной статье хочу рассказать о настройках сборки проекта, написанного на React + Redux.
Я не буду углубляться в основы, а расскажу, какие плагины использую для сборки.
NoErrorsPlugin — это стандартный плагин Webpack, который не дает перезаписать скрипты при наличии в них ошибок. Это уберегает от уничтожения старой сборки как следствие нерабочего кода в продакшене. Подключается стандартно в массив с плагинами:
new webpack.NoErrorsPlugin()
EnvironmentPlugin — плагин для экспорта окружения в клиентских скриптах, что очень удобно для отладки и логирования. Подключение:
new webpack.EnvironmentPlugin("NODE_ENV")
Использование в коде:
var env = process.env.NODE_ENV;
DefinePlugin — плагин для объявления своих переменных при сборке. Например, для вырезания кусков кода общего конфига с сервером.
Подключение:
new webpack.DefinePlugin({
cutCode: JSON.stringify(true)
})
Использование:
if (typeof cutCode === 'undefined') {
// Ваш код
}
CommonsChunkPlugin — выносит общие библиотеки для чанков в отдельный чанк. Удобно для кеширования внешних библиотек и уменьшения веса чанков. Что такое чанки и Lazy loading доступно описано здесь. Подключение:
new webpack.optimize.CommonsChunkPlugin({
children: true,
async: true,
})
DedupePlugin — находит общие зависимости библиотек и обобщает их. Подключение:
new webpack.optimize.DedupePlugin()
UglifyJsPlugin — плагин, который сжимает скрипты. Параметры для этого плагина можно посмотреть здесь.
Подключение:
new webpack.optimize.UglifyJsPlugin({
// ваши настройки здесь
}
})
Мой вариант:
new webpack.optimize.UglifyJsPlugin({
beautify: false,
comments: false,
compress: {
sequences : true,
booleans : true,
loops : true,
unused : true,
warnings : false,
drop_console: true,
unsafe : true
}
})
OccurrenceOrderPlugin — плагин, который минимизирует id, которые используются webpack для подгрузки чанков и прочего. Подключение:
new webpack.optimize.OccurrenceOrderPlugin()
CompressionPlugin — сторонний плагин для компрессии скриптов, например, в gzip формат. Большинство браузеров принимает gzip файли при установлению в headers для ответа переменной Content-Encoding:gzip. Параметры здесь.
Установка:
npm install compression-webpack-plugin
Подключение:
CompressionPlugin = require("compression-webpack-plugin");
plugins: [
// твои плагины
new CompressionPlugin({
asset: "[path].gz[query]",
algorithm: "gzip",
test: /\.js$|\.html$/,
threshold: 10240,
minRatio: 0.8
})
]
WebpackShellPlugin — сторонний плагин для запуска команд до и после сборки. Например, для очистки старых файлов после сборки.
Установка:
npm install webpack-shell-plugin
Подключение:
new WebpackShellPlugin({
onBuildStart: ['echo "Webpack Start"'],
onBuildEnd: [
`node ./node_modules/clean-scripts-after-build --path ${__dirname + '/public/js/'} --bundleName bundle_${config.jsVersion}.js`
]
})
Отдельно хочу выделить подключение babel-loader. Он транспилит jsx, es6, es7 в es5 синтаксис.
Установка:
npm install babel-loader babel-preset-es2015 babel-preset-react babel-preset-stage-0
//babel плагины для минификации react компонент
npm install babel-plugin-transform-react-constant-elements
npm install babel-plugin-transform-react-inline-elements
npm install babel-plugin-transform-react-remove-prop-types
Подключение:
wpConfig = {
entry : ....,
output : {
//.......
}
module : {
loaders: [
{
loader : 'babel',
//не анализирует код в папке node_modules, там код уже переведен в es5 синтаксис
exclude: /node_modules/,
query: {
plugins: [
'transform-runtime',
'transform-react-remove-prop-types',
'transform-react-constant-elements',
'transform-react-inline-elements'
],
presets: ['es2015', 'stage-0', 'react'],
}
}
]
},
}
И да, не забудьте использовать окружение production. Код React и Redux написан так, что куски кода, которые не нужны в продакшене, вырезаются Webpack.
P.S. Я ужал свой бандл с 2.6 mb до 160 kb. Буду рад посмотреть все замечания, так как вариаций настройки может быть очень много.
Комментарии (30)
vovkvlad
31.08.2016 16:04Я выбрал для себя Webpack по таким критериям:
- …
- Использование es6 и es7 синтаксиса с помощью babel-loader
Не то что бы я придирался, просто, насколько мне известно, то возможность подключить babel есть почти во всех сборщиках (если не во всех), потому сразу бросился в глаза данный пункт в сторону выбора webpack-aBoryaMogila
31.08.2016 16:06Согласен у многих есть, мне понравилось удобство подключения. Но у многих и нету.
hell0w0rd
01.09.2016 01:07Но у многих и нету.
Например?
BoryaMogila
01.09.2016 01:21babel можно прекрутить куда угодно, вопрос стоит в удобсве натройки и предпочтении разработчика.
hell0w0rd
01.09.2016 01:31таки куда угодно. А где неудобно настраивать? Вроде везде babelrc поддерживается одинаково, не?
kashey
01.09.2016 11:47В https://github.com/yandex/ymb никакого бабеля нету, как и возможности использовать es2015 модули.
А сам сборщик не плохой, особенно в плане минимизации передачи данных.
agabidullin
31.08.2016 16:06+6Статья именуется «Webpack + React. Как уменьшить бандл в 15 раз». Под катом — список плагинов и "...P.S. Я ужал свой бандл с 2.6 mb до 160 kb".
Как-то не связано получилось. Хотелось бы прочесть историю от начала до конца: как подключается webpack, как работает и т.п.
Либо стоит поменять название статьи на «Какие плагины я использую для webpack»BoryaMogila
31.08.2016 16:12-3Имеется ввиду, что используя эти плагины можно уменьшить размер бандла в 15 раз.
remnev
31.08.2016 16:39+4Как NoErrorsPlugin, EnvironmentPlugin, WebpackShellPlugin, babel-loader помогают уменьшить размер бандла в 15 раз?
BoryaMogila
31.08.2016 16:59-3Я согласен не имеют, изначально планировалась статья с названием типа «webpack для продакшн зборки».
Laney1
31.08.2016 16:43библиотеки вроде react можно вообще не включать в бандл, а загружать отдельно из CDN
magmoro
31.08.2016 16:55+1кстати есть интересная статья, правда не про реакт, а ангуляр 2 уменьшение кода до 20кб (1.6mb без компресии и минификации) http://blog.mgechev.com/2016/07/21/even-smaller-angular2-applications-closure-tree-shaking/ используя precompiled templates, tree shaking, google closure compiler и brotli (вместо gzip, хотя brotli не все браузеры поддерживают).
shir
31.08.2016 16:59Из недостатков я бы выделил отсутствие ясной документации. Для тех, кто никогда не сталкивался с Webpack, я рекомендую
Немножко устаревший туториал, но узнал много полезного. http://survivejs.com/webpack/introduction/
alemiks
31.08.2016 22:35если ещё выкинуть реакт и вместо него преакт, то можно еще раз в 5 уменьшить )
BoryaMogila
31.08.2016 22:50я думаю что профита будет не много так как реакт весит около 50 kb. Это до gzip. Тем более что все варнинги console.log и прочие вещи выкидеваются при зборке. Хотя заменить на преакт не пробовал, наверняка утверждать не могу.
batya15
Вода!
BoryaMogila
А что не вода по webpack? Это моя первая статья, хотелось бы увидеть замечания поконкретней, если можно.
13luck
Расскажите, пожалуйста, что-нибудь про tree-shaking в webpack.
BoryaMogila
tree-shaking доступно только для webpack 2. Буду переходить на второй, напишу похожую статью
Dreyk
я собственно зашел в статью только ради того, чтоб почитать про tree-shaking...
Сама по себе статья неплоха, но советую переходить на webpack2, уже можно, есть совместимые версии react-hot-loader и webpack-dev-server
iLikeKoffee
Нормальная статья, не обращайте внимания. Особенно, с учетом того, что материала по теме на русском кот наплакал. У меня, кстати, есть boilerplate для проектов на react + redux (с webpack, сборкой, минификацией и т.д.). Однозначно, почерпну у вас пару приемов.
BoryaMogila
Спасибо