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. Буду рад посмотреть все замечания, так как вариаций настройки может быть очень много.
    Поделиться публикацией
    Комментарии 31
      +1
      Вода!
        +3
        А что не вода по webpack? Это моя первая статья, хотелось бы увидеть замечания поконкретней, если можно.
          +2
          Расскажите, пожалуйста, что-нибудь про tree-shaking в webpack.
            0
            tree-shaking доступно только для webpack 2. Буду переходить на второй, напишу похожую статью
              0

              я собственно зашел в статью только ради того, чтоб почитать про tree-shaking...


              Сама по себе статья неплоха, но советую переходить на webpack2, уже можно, есть совместимые версии react-hot-loader и webpack-dev-server

              +2
              Нормальная статья, не обращайте внимания. Особенно, с учетом того, что материала по теме на русском кот наплакал. У меня, кстати, есть boilerplate для проектов на react + redux (с webpack, сборкой, минификацией и т.д.). Однозначно, почерпну у вас пару приемов.
          0
          Есть еще очень классная штука — babel-react-optimize
            0
            Обезательно посмотрю, спасибо.
            0
            Я выбрал для себя Webpack по таким критериям:
            • Использование es6 и es7 синтаксиса с помощью babel-loader



            Не то что бы я придирался, просто, насколько мне известно, то возможность подключить babel есть почти во всех сборщиках (если не во всех), потому сразу бросился в глаза данный пункт в сторону выбора webpack-a
              0
              Согласен у многих есть, мне понравилось удобство подключения. Но у многих и нету.
                0
                Но у многих и нету.

                Например?

                  0
                  babel можно прекрутить куда угодно, вопрос стоит в удобсве натройки и предпочтении разработчика.
                    0

                    таки куда угодно. А где неудобно настраивать? Вроде везде babelrc поддерживается одинаково, не?

                    0
                    В https://github.com/yandex/ymb никакого бабеля нету, как и возможности использовать es2015 модули.
                    А сам сборщик не плохой, особенно в плане минимизации передачи данных.
                      0

                      Он же поверх gulp сделан, так что добавить babel можно средствами gulp

                +6
                Статья именуется «Webpack + React. Как уменьшить бандл в 15 раз». Под катом — список плагинов и "...P.S. Я ужал свой бандл с 2.6 mb до 160 kb".
                Как-то не связано получилось. Хотелось бы прочесть историю от начала до конца: как подключается webpack, как работает и т.п.
                Либо стоит поменять название статьи на «Какие плагины я использую для webpack»
                  –3
                  Имеется ввиду, что используя эти плагины можно уменьшить размер бандла в 15 раз.
                    +4
                    Как NoErrorsPlugin, EnvironmentPlugin, WebpackShellPlugin, babel-loader помогают уменьшить размер бандла в 15 раз?
                      +1
                      вообще никак, к уменьшению никакого отношения не имеют
                        –3
                        Я согласен не имеют, изначально планировалась статья с названием типа «webpack для продакшн зборки».
                    0

                    библиотеки вроде react можно вообще не включать в бандл, а загружать отдельно из CDN

                      0
                      Можно, но опасно при збоях работы CDN.
                      +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 не все браузеры поддерживают).
                      0
                      Из недостатков я бы выделил отсутствие ясной документации. Для тех, кто никогда не сталкивался с Webpack, я рекомендую

                      Немножко устаревший туториал, но узнал много полезного. http://survivejs.com/webpack/introduction/

                        0
                        устаревший, но понятный. Лутше пока не встречал.
                        0
                        если ещё выкинуть реакт и вместо него преакт, то можно еще раз в 5 уменьшить )
                          0
                          я думаю что профита будет не много так как реакт весит около 50 kb. Это до gzip. Тем более что все варнинги console.log и прочие вещи выкидеваются при зборке. Хотя заменить на преакт не пробовал, наверняка утверждать не могу.
                            0
                            Расскажите глупому, что за перекат оО?!
                            0
                            Преакт, минифицированый реакт

                            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                            Самое читаемое