Webpack + React. Как уменьшить бандл в 15 раз

image

Ясной инструкции по сборке 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. Буду рад посмотреть все замечания, так как вариаций настройки может быть очень много.

Комментарии (2)

  • 31 августа 2016 в 15:25

    –1

    Вода!
    • 31 августа 2016 в 15:34 (комментарий был изменён)

      +1

      А что не вода по webpack? Это моя первая статья, хотелось бы увидеть замечания поконкретней, если можно.

© Habrahabr.ru