Тридцать минут, чтобы освоить оптимизацию производительности Webpack

JavaScript CDN React.js Webpack

Webpack теперь является основным и мощным модульным инструментом упаковки.При использовании Webpack, если вы не обращаете внимание на оптимизацию производительности, могут возникнуть проблемы с производительностью.Проблемы производительности в основном делятся на медленную упаковку и сборку во время разработки, а также проблемы во время разработки и отладки. Повторяющаяся работа и качество выходных файлов невысокие, поэтому оптимизация производительности в основном анализируется с этих аспектов. Эта статья в основном резюмирует книгу «Введение в Webpack», основанную на моем собственном понимании, и охватывает большинство методов оптимизации, которые можно использовать в качестве справочника и контрольного списка для оптимизации производительности Webpack. На основе Webpack 3.4 чтение этой статьи требует от вас знакомства с основами использования Webpack. Чтение занимает около 30 минут.

by MaryTien from supermaryy.com

1. Оптимизируйте скорость сборки

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

1.1 Сузить поиск файлов

К методам оптимизации процесса поиска относятся:

  1. resolveПоле сообщает webpack, как искать файлы, поэтому в первую очередь обратите внимание на настройку поля разрешения:

    1. настраиватьresolve.modules:[path.resolve(__dirname, 'node_modules')]Избегайте послойного поиска.

      resolve.modulesСообщите webpack, в каких каталогах искать сторонние модули, значение по умолчанию равно['node_modules'], будет искать ./node_modules, ../node_modules, ../../node_modules.

    2. настраиватьresolve.mainFields:['main'], установка как можно меньшего количества значений может сократить шаги поиска файла входа

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

    3. Настройка для огромных сторонних модулейresolve.alias, Заставьте веб-пакет напрямую использовать минимальный файл библиотеки, чтобы избежать синтаксического анализа в библиотеке.

      Что касается реакции:

      resolve.alias:{
      	'react':patch.resolve(__dirname, './node_modules/react/dist/react.min.js')
      }
      

      Это повлияет на Tree-Shaking, который подходит для библиотек с относительно сильной целостностью.Если это относительно разрозненная библиотека, такая как lodash, она больше подходит для Tree-Shaking и избегайте использования этого метода.

    4. Разумная конфигурацияresolve.extensions, сокращение поиска файлов

      По умолчанию:extensions:['.js', '.json'], Если оператор импорта не имеет суффикса файла, Webpack будет искать файлы в соответствии со списком суффиксов, определенным расширениями, поэтому:

      • Перечислите как можно меньше значений
      • Суффикс типа файла с высокой частотой пишется впереди
      • Оператор импорта в исходном коде должен указывать суффикс файла как можно чаще, напримерrequire(./data)быть записано какrequire(./data.json)
  2. module.noParseПоле сообщает Webpack, какие файлы не нужно анализировать, может использоваться для исключения анализа файлов немодульной библиотеки.

    Такие как jQuery, ChartJS, и если в react.min.js настроено разрешение.alias, разрешение также следует исключить, поскольку react.min.js уже создан и является немодульным файлом, который может запускаться непосредственно в браузер. . Значение noParse может быть RegExp, [RegExp], функцией

    module:{ noParse:[/jquery|chartjs/, /react\.min\.js$/] }

  3. При настройке загрузчика сузьте область поиска с помощью проверки, исключения и включения.

1.2 Используйте DllPlugin, чтобы уменьшить количество компиляций базовых модулей

Плагин библиотеки динамической компоновки DllPlugin,ПринципОсновные модули, от которых зависят веб-страницы, извлекаются и упаковываются в файлы dll.Когда импортируемый модуль существует в dll, модуль больше не упаковывается, а получается из dll. **Почему скорость сборки увеличивается? **Причина в том, что большинство dll содержат распространенные сторонние модули, такие как react и react-dom, поэтому, пока версии этих модулей не обновляются, их нужно скомпилировать только один раз. Я думаю, что это имеет тот же эффект, что и настройка resolve.alias и module.noParse.

Инструкции:

  1. Используйте DllPlugin для настройки webpack_dll.config.js для создания файла dll:

    // webpack_dll.config.js
    const path = require('path');
    const DllPlugin = require('webpack/lib/DllPlugin');
    module.exports = {
     entry:{
         react:['react','react-dom'],
         polyfill:['core-js/fn/promise','whatwg-fetch']
     },
     output:{
         filename:'[name].dll.js',
         path:path.resolve(__dirname, 'dist'),
         library:'_dll_[name]',  //dll的全局变量名
     },
     plugins:[
         new DllPlugin({
             name:'_dll_[name]',  //dll的全局变量名
             path:path.join(__dirname,'dist','[name].manifest.json'),//描述生成的manifest文件
         })
     ]
    }
    

    Следует отметить, что значение имени в параметре DllPlugin должно соответствовать значению output.library, а значение output.library будет указано в сгенерированном файле манифеста.

    Окончательный собранный файл:

     |-- polyfill.dll.js
     |-- polyfill.manifest.json
     |-- react.dll.js
     └── react.manifest.json
    

    Среди них xx.dll.js содержит упакованные n модулей, эти модули хранятся в массиве, а в качестве идентификатора используется индекс массива, предполагается, что _xx_dll выставляется на глобальную через переменную, и эти модули могут быть доступ через window._xx_dll. Файл xx.manifest.json описывает, какие модули содержит файл dll, путь и идентификатор каждого модуля. Затем используйте подключаемый модуль DllReferencePlugin, чтобы импортировать файл xx.manifest.json в основной файл конфигурации проекта.

  2. Используйте подключаемый модуль DllReferencePlugin для импорта файла xx.manifest.json в основной файл конфигурации:

    //webpack.config.json
    const path = require('path');
    const DllReferencePlugin = require('webpack/lib/DllReferencePlugin');
    module.exports = {
        entry:{ main:'./main.js' },
        //... 省略output、loader等的配置
        plugins:[
            new DllReferencePlugin({
                manifest:require('./dist/react.manifest.json')
            }),
            new DllReferenctPlugin({
                manifest:require('./dist/polyfill.manifest.json')
            })
        ]
    }
    

    окончательная сборкаmain.js

1.3 Используйте HappyPack, чтобы открыть конвертацию многопроцессорного загрузчика

Во всем процессе построения наиболее трудоемким является преобразование файлов Loader, тогда как Webpack, работающий на Node.js, является однопоточной моделью, то есть может обрабатывать файлы только один за другим, и не может обрабатываться в параллельно. HappyPack может разбивать задачи на несколько подпроцессов и, наконец, отправлять результаты в основной процесс. JS является однопоточной моделью и может повысить производительность только за счет многопроцессорного подхода.

HappyPack используется следующим образом:

npm i -D happypack
// webpack.config.json
const path = require('path');
const HappyPack = require('happypack');

module.exports = {
    //...
    module:{
        rules:[{
                test:/\.js$/,
                use:['happypack/loader?id=babel']
                exclude:path.resolve(__dirname, 'node_modules')
            },{
                test:/\.css/,
                use:['happypack/loader?id=css']
            }],
        plugins:[
            new HappyPack({
                id:'babel',
                loaders:['babel-loader?cacheDirectory']
            }),
            new HappyPack({
                id:'css',
                loaders:['css-loader']
            })
        ]
    }
}

Помимо id и загрузчиков, HappyPack также поддерживает эти три параметра:threads、verbose、threadpool, threadpool означает общий пул процессов, то есть несколько экземпляров HappyPack используют подпроцессы в одном пуле процессов для обработки задач, чтобы предотвратить чрезмерное использование ресурсов.

1.4 Используйте ParallelUglifyPlugin для открытия многопроцессорных сжатых JS-файлов

При использовании плагина UglifyJS для сжатия кода JS необходимо преобразовать код в AST (абстрактное синтаксическое дерево), представленное объектом, а затем применить различные правила для анализа и обработки AST, поэтому этот процесс требует большого объема вычислений. и требует много времени. ParallelUglifyPlugin может открывать несколько подпроцессов, каждый подпроцесс использует UglifyJS для сжатия кода, который может выполняться параллельно, что может значительно сократить время сжатия.

Его также очень просто использовать, просто замените оригинальный плагин UglifyJS на плагин стоимости и используйте его следующим образом:

npm i -D webpack-parallel-uglify-plugin

// webpack.config.json
const ParallelUglifyPlugin = require('wbepack-parallel-uglify-plugin');
//...
plugins: [
    new ParallelUglifyPlugin({
        uglifyJS:{
            //...这里放uglifyJS的参数
        },
        //...其他ParallelUglifyPlugin的参数,设置cacheDir可以开启缓存,加快构建速度
    })
]

2. Оптимизируйте опыт разработки

После изменения исходного кода в процессе разработки вам необходимо автоматически собрать и обновить браузер, чтобы увидеть эффект. Этот процесс можно автоматизировать с помощью Webpack: Webpack отвечает за мониторинг изменений файлов, а DevServer отвечает за обновление браузера.

2.1 Использование автоматического обновления

2.1.1 Файлы прослушивания Webpack

Webpack может включить мониторинг двумя способами: 1. Добавить параметр --watch при запуске webpack 2. Установить watch: true в файле конфигурации. Кроме того, имеются следующие параметры конфигурации. Разумная настройка watchOptions может оптимизировать прослушивание.

module.exports = {
    watch: true,
    watchOptions: {
        ignored: /node_modules/,
        aggregateTimeout: 300,  //文件变动后多久发起构建,越大越好
        poll: 1000,  //每秒询问次数,越小越好
    }
}

ignored: Установите каталог, который не следует слушать.После исключения node_modules память, потребляемая Webpack, может быть значительно уменьшена.

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

опрос: определить, изменился ли файл, путем опроса системы на наличие изменений в файле, опрос — это количество запросов в секунду, чем меньше, тем лучше

2.1.2 DevServer обновляет браузер

DevServer может обновить браузер двумя способами.:

  1. Вставьте код прокси-клиента на веб-страницу и инициируйте обновление через клиент.
  2. Загрузите iframe на веб-страницу и обновите iframe, чтобы добиться эффекта обновления.

по умолчанию иdevserver: {inline:true}Все используют первый метод для обновления страницы. В первом методе DevServer внедряет клиентский код в каждый чанк, потому что он не знает, от каких чанков зависит веб-страница.Когда нужно вывести много чанков, сборка будет медленной. И странице нужен только один клиент,Таким образом, отключение встроенного режима может сократить время сборки., чем больше кусков, тем лучше месяц. Метод закрытия:

  1. Начните с webpack-dev-server --inline false
  2. настроитьdevserver:{inline:false}

После закрытия строки URL-адрес записи становится http://localhost:8080/webpack-dev-server/.

Кроме тогоdevServer.compressПараметр может указать, следует ли использовать сжатие Gzip, по умолчанию — false.

2.2 Включить горячую замену модуля HMR

Горячая замена модуля не обновляет всю веб-страницу, а только перекомпилирует измененные модули и заменяет старые модули новыми модулями, поэтому предварительный просмотр выполняется быстрее, время ожидания короче, а рабочее состояние текущей веб-страницы может сохраняться без обновления страницы. Принцип также заключается во внедрении прокси-клиента в каждый фрагмент для подключения DevServer и веб-страниц. Открытый метод:

  1. webpack-dev-server --hot
  2. Использование HotModuleReplacementPlugin более проблематично

После открытия, если вы измените подмодуль, вы можете добиться частичного обновления, но если вы измените корневой файл JS, будет обновлена ​​​​вся страница, Причина в том, что при обновлении подмодуля события передаются слой за слоем, пока файл определенного слоя получает текущее изменение модуля, а затем выполняет функцию обратного вызова. Если слои выбрасываются наружу до тех пор, пока на самом внешнем слое не будут получены файлы, вся страница будет обновлена.

использоватьNamedModulesPluginВы можете заставить консоль печатать имя заменяемого модуля вместо числового идентификатора.Кроме того, поскольку веб-пакет прослушивает, игнорирование файлов в каталоге node_modules может повысить производительность.

3. Оптимизируйте качество вывода - размер сжатого файла

3.1 Дифференцируйте среду — уменьшите размер кода производственной среды

Среда выполнения кода делится на среду разработки и производственную среду.Код должен выполнять разные операции в зависимости от разных сред.Многие сторонние библиотеки также имеют большое количество кодов if else, оцениваемых в соответствии со средой разработки.Конструкция также необходимо выводить разные коды в соответствии с разными средами, поэтому необходим механизм для различения среды в исходном коде, и после различения среды размер кода выходной производственной среды может быть уменьшен. Плагин DefinePlugin используется в Webpack для определения среды, для которой применяется файл конфигурации.

const DefinePlugin = require('webpack/lib/DefinePlugin');
//...
plugins:[
    new DefinePlugin({
        'process.env': {
            NODE_ENV: JSON.stringify('production')
        }
    })
]

Уведомление,JSON.stringify('production')Причина в том, что для значения переменной среды требуется строка, заключенная в двойные кавычки, а значение после stringify равно'"production"'

Затем вы можете использовать определенную среду в исходном коде:

if(process.env.NODE_ENV === 'production'){
    console.log('你在生产环境')
    doSth();
}else{
    console.log('你在开发环境')
    doSthElse();
}

Когда процесс используется в коде, Webpack автоматически упаковывает код в модуль процесса для поддержки сред выполнения, отличных от Node.js.Функция этого модуля состоит в том, чтобы имитировать процесс в Node.js для поддержкиprocess.env.NODE_ENV === 'production'утверждение.

3.2 Сжатый код — JS, ES, CSS

  1. Сжатие JS: встроенный в Webpack плагин UglifyJS, ParallelUglifyPlugin

    Он проанализирует синтаксическое дерево кода JS и поймет значение кода, чтобы удалить недопустимые коды, удалить коды ввода журнала, сократить имена переменных и другие оптимизации. Общие параметры конфигурации следующие:

    const UglifyJSPlugin = require('webpack/lib/optimize/UglifyJsPlugin');
    //...
    plugins: [
        new UglifyJSPlugin({
            compress: {
                warnings: false,  //删除无用代码时不输出警告
                drop_console: true,  //删除所有console语句,可以兼容IE
                collapse_vars: true,  //内嵌已定义但只使用一次的变量
                reduce_vars: true,  //提取使用多次但没定义的静态值到变量
            },
            output: {
                beautify: false, //最紧凑的输出,不保留空格和制表符
                comments: false, //删除所有注释
            }
        })
    ]
    

    использоватьwebpack --optimize-minimizeЗапустите webpack, вы можете внедрить конфигурацию по умолчанию UglifyJSPlugin

  2. Минимизированный ES6: сторонний плагин UglifyJS

    Поскольку все больше и больше браузеров поддерживают прямое выполнение кода ES6, вы должны стараться как можно больше запускать нативный код ES6, чтобы объем кода был меньше, чем преобразованный код ES5, а производительность кода ES6 была выше. При прямом запуске кода ES6 также требуется сжатие кода, сторонний uglify-webpack-plugin предоставляет функцию сжатия кода ES6:

    npm i -D uglify-webpack-plugin@beta //要使用最新版本的插件
    //webpack.config.json
    const UglifyESPlugin = require('uglify-webpack-plugin');
    //...
    plugins:[
        new UglifyESPlugin({
            uglifyOptions: {  //比UglifyJS多嵌套一层
                compress: {
                    warnings: false,
                    drop_console: true,
                    collapse_vars: true,
                    reduce_vars: true
                },
                output: {
                    beautify: false,
                    comments: false
                }
            }
        })
    ]
    

    Кроме того, чтобы предотвратить преобразование кода ES6 загрузчиком babel, удалите babel-preset-env в .babelrc, поскольку за преобразование ES6 в ES5 отвечает babel-preset-env.

  3. Сжатие CSS: css-loader?minimize, PurifyCSSPlugin

    cssnano основан на PostCSS, который не только убирает пробелы, но и понимает смысл кода, например, поставитьcolor:#ff0000Перевести вcolor:red, css-loader имеет встроенный cssnano, просто используйтеcss-loader?minimizeВы можете включить сжатие cssnano.

    Другой способ сжатия CSS — использоватьPurifyCSSPlugin, нужно сотрудничатьextract-text-webpack-pluginИспользуйте, его основная функция заключается в удалении неиспользуемого кода CSS, подобно Tree Shaking в JS.

3.3 Используйте Tree Shake для устранения мертвого кода JS

Tree Shaking может устранить неиспользуемый мертвый код.Он основан на модульном синтаксисе импорта и экспорта ES6.Он впервые появился в Rollup и был представлен в Webpack 2.0. Он подходит для файлов с разрозненными инструментами, такими как Lodash и utils.js.Предпосылкой для правильной работы является то, что код должен использовать модульный синтаксис ES6., поскольку модульный синтаксис ES6 является статическим (пути в операторах импорта и экспорта должны быть статическими строками и не могут быть помещены в другие блоки кода). Если принята модульность в ES5, например, module.export = {...}, require( x+y ), if (x) { require( './util' ) }, Webpack не может анализировать, какой код можно исключить .

Включить встряхивание дерева:

  1. Измените .babelrc, чтобы сохранить модульные операторы ES6:

    {
        "presets": [
            [
                "env", 
                { "module": false },   //关闭Babel的模块转换功能,保留ES6模块化语法
            ]
        ]
    }
    
  2. Добавьте --display-used-exports при запуске веб-пакета, чтобы распечатать подсказки об отбраковке кода в оболочке.

  3. Используйте UglifyJSPlugin или начните с --optimize-minimize

  4. При использовании сторонних библиотек необходимо настроитьresolve.mainFields: ['jsnext:main', 'main']Чтобы указать, что при анализе кода сторонней библиотеки используйте запись модульного кода ES6.

В-четвертых, оптимизируйте качество вывода — ускорьте сетевые запросы

4.1 Используйте CDN для ускорения загрузки статических ресурсов

  1. Принцип ускорения CND

    Размещая ресурсы по всему миру, CDN позволяет пользователям получать доступ к ближайшим ресурсам и ускоряет доступ. Чтобы получить доступ к CDN, вам необходимо загрузить статические ресурсы веб-страницы в службу CDN и использовать URL-адрес, предоставленный службой CDN, при доступе к этим ресурсам.

    Поскольку CDN обеспечивает долгосрочное кэширование ресурсов, например, если пользователь получает index.html из CDN, даже если index.html в CDN будет заменен позже, пользователь все равно будет использовать предыдущую версию, пока кэш время истекает. Отраслевая практика:

    • HTML-файл: поставить на свой сервер и закрыть кеш, не подключаться к CDN
    • Статические JS, CSS, картинки и другие ресурсы: включите CDN и кеш, и в то же время имя файла содержит значение хэша, вычисленное из содержимого., поэтому при изменении содержимого будет меняться хэш, имя файла и он будет повторно загружен независимо от того, как долго он кэшируется.

    Кроме того, в версии протокола HTTP1.x браузер ограничивает количество одновременных запросов к одному и тому же доменному имени от 4 до 8. Затем вы столкнетесь с этим ограничением, если поместите все статические ресурсы в службу CDN под одним и тем же доменным именем, чтобы вы могли поместить ихРазбросаны по разным сервисам CDNНапример, поместите файлы JS в папку js.cdn.com, файлы CSS — в папку css.cdn.com и т. д. Это принесет новую проблему: увеличьте время разрешения доменного имени, это можно сделать с помощьюdns-prefetchрешать<link rel='dns-prefetch' href='//js.cdn.com'>Сократить время разрешения доменного имени. В форме**//xx.comТакой URL-адрес пропускает протокол**. Преимущество этого заключается в том, что браузер автоматически решит использовать протокол HTTP или HTTPS в соответствии с режимом, принятым текущим URL-адресом при доступе к ресурсу.

  2. Таким образом, сборка должна соответствовать следующим пунктам:

    • URL-адрес, импортированный из статических ресурсов, должен быть изменен на URL-адрес, указывающий на абсолютный путь службы CDN.
    • Имя файла статического ресурса должно содержать значение хэша, рассчитанное в соответствии с содержимым.
    • Различные типы ресурсов размещаются на CDN с разными доменными именами.
  3. Окончательная конфигурация:

    const ExtractTextPlugin = require('extract-text-webpack-plugin');
    const {WebPlugin} = require('web-webpack-plugin');
    //...
    output:{
     filename: '[name]_[chunkhash:8].js',
     path: path.resolve(__dirname, 'dist'),
     publicPatch: '//js.cdn.com/id/', //指定存放JS文件的CDN地址
    },
    module:{
     rules:[{
         test: /\.css/,
         use: ExtractTextPlugin.extract({
             use: ['css-loader?minimize'],
             publicPatch: '//img.cdn.com/id/', //指定css文件中导入的图片等资源存放的cdn地址
         }),
     },{
        test: /\.png/,
        use: ['file-loader?name=[name]_[hash:8].[ext]'], //为输出的PNG文件名加上Hash值 
     }]
    },
    plugins:[
      new WebPlugin({
         template: './template.html',
         filename: 'index.html',
         stylePublicPath: '//css.cdn.com/id/', //指定存放CSS文件的CDN地址
      }),
     new ExtractTextPlugin({
         filename:`[name]_[contenthash:8].css`, //为输出的CSS文件加上Hash
     })
    ]
    

4.2 Многостраничные приложения извлекают общий код между страницами, чтобы использовать кэширование

  1. принцип

    Большие веб-сайты обычно состоят из нескольких страниц, каждая из которых представляет собой независимое одностраничное приложение, а несколько страниц определенно будут полагаться на одни и те же файлы стилей, технологический стек и т. д. Если эти общедоступные файлы не будут извлечены, фрагменты каждой отдельной страницы будут содержать общедоступные коды, что эквивалентно передаче n повторяющихся кодов. Если общедоступный файл извлекается как файл, то когда пользователь посещает веб-страницу, загружает общедоступный файл, а затем посещает другие веб-страницы, которые зависят от общедоступного файла, кэш файла в браузере используется напрямую, поэтому что общедоступный файл используется только браузером. передать один раз.

  2. Способ применения

    1. Извлеките общий код, от которого зависят несколько страниц, в файл common.js. В настоящее время common.js содержит код базовой библиотеки.

      const CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin');
      //...
      plugins:[
          new CommonsChunkPlugin({
              chunks:['a','b'], //从哪些chunk中提取
              name:'common',  // 提取出的公共部分形成一个新的chunk
          })
      ]
      
    2. Найдите зависимую базовую библиотеку, напишите файл base.js, а затем извлеките общий код с помощью common.js в базу, common.js уберет код базовой библиотеки, а base.js останется без изменений

      //base.js
      import 'react';
      import 'react-dom';
      import './base.css';
      //webpack.config.json
      entry:{
          base: './base.js'
      },
      plugins:[
          new CommonsChunkPlugin({
              chunks:['base','common'],
              name:'base',
              //minChunks:2, 表示文件要被提取出来需要在指定的chunks中出现的最小次数,防止common.js中没有代码的情况
          })        
      ]
      
    3. Получите код базовой библиотеки base.js, общий код common.js без базовой библиотеки и соответствующий файл кода xx.js страницы.

      Порядок ссылок на страницы следующий: base.js-->common.js-->xx.js

4.3 Разделить код для загрузки по запросу

  1. принцип

    Одна из проблем одностраничных приложений заключается в том, что они используют одну страницу для выполнения сложных функций, а загружаемые файлы очень большие.Без оптимизации время загрузки первого экрана будет слишком долгим, что повлияет на пользователя опыт. Выполнение загрузки по требованию может решить эту проблему. Конкретный метод заключается в следующем:

    1. Разделите функции сайта на категории по степени их актуальности
    2. Каждый класс объединяется в фрагмент, и соответствующий фрагмент загружается по запросу.
    3. Например, поместите только функции, относящиеся к первому экрану, в фрагмент, где находится запись выполнения, чтобы небольшой объем кода загружался в первый раз, а затем загружался, когда потребуются другие коды. Лучше всего заранее предсказать следующую операцию пользователя и заранее загрузить соответствующий код, чтобы пользователь не мог воспринимать нагрузку на сеть.
  2. упражняться

    Самый простой пример: веб-страница только в первый раз загружает main.js, и на веб-странице отображается кнопка, при нажатии на кнопку загружается разделенный show.js, а функции в show.js выполняются после загрузка проходит успешно.

    //main.js
    document.getElementById('btn').addEventListener('click',function(){
        import(/* webpackChunkName:"show" */ './show').then((show)=>{
            show('Webpack');
        })
    })
    //show.js
    module.exports = function (content) {
        window.alert('Hello ' + content);
    }
    

    import(/* webpackChunkName:show */ './show').then()Это ключ к загрузке по запросу. Webpack имеет встроенную поддержку операторов импорта (*). Webpack будет использовать./show.jsРегенерируйте фрагмент для записи. Когда код выполняется в браузере, show.js будет загружаться только при нажатии кнопки, а оператор импорта вернет Promise.После успешной загрузки загруженный контент можно получить в методе then. Для этого браузер должен поддерживать Promise API, а для браузеров, которые его не поддерживают, необходимо внедрить полифилл Promise./* webpackChunkName:show */Является ли определение имени динамически генерируемого Чанка.Имя по умолчанию — [id].js, что удобно для отладки кода. Чтобы правильно выводить ChunkName для этой конфигурации, Webpack также необходимо настроить:

    //...
    output:{
        filename:'[name].js',
        chunkFilename:'[name].js', //指定动态生成的Chunk在输出时的文件名称
    }
    

    В книге также представлены более сложные реальные боевые сценарии для асинхронной загрузки компонентов в React-Router. P212

В-пятых, оптимизируйте качество вывода — повысьте эффективность выполнения кода.

5.1 Предварительная оценка с помощью Prepack

  1. принцип:

    Prepack — это частичный оценщик, который помещает результаты вычислений в скомпилированный код заранее при компиляции кода, а не оценивает их во время выполнения кода. Результат выполнения получается путем предварительного выполнения исходного кода в один этап, а затем результат выполнения выводится напрямую для повышения производительности. Но сейчас Prepack недостаточно зрелый, слишком рано для онлайн-среды.

  2. инструкции

    const PrepackWebpackPlugin = require('prepack-webpack-plugin').default;
    module.exports = {
        plugins:[
            new PrepackWebpackPlugin()
        ]
    }
    

5.2 Использование подъема области видимости

  1. принцип

    В переводе как «продвижение области» это функция, представленная в Webpack 3. Она анализирует зависимости между модулями и максимально объединяет разрозненные модули в функцию, но не может вызвать избыточность кода, поэтому на нее ссылаются только один раз. быть объединены. Из-за необходимости анализа зависимостей между модулями исходный код должен быть модульным с помощью ES6, иначе Webpack понизит версию и не будет использовать Scope Hoisting.

  2. инструкции

    const ModuleConcatenationPlugin = require('webpack/lib/optimize/ModuleConcatenationPlugin');
    //...
    plugins:[
        new ModuleConcatenationPlugin();
    ],
    resolve:{
    	mainFields:['jsnext:main','browser','main']
    }
    

    webpack --display-optimization-bailoutВ выходном журнале будет указано, какой файл вызвал процесс перехода на более раннюю версию.

6. Используйте инструменты анализа результатов

Когда вы запускаете Webpack с этими двумя параметрами, может быть сгенерирован файл json, и большинство инструментов анализа вывода используют этот файл для анализа:

webpack --profile --json > stats.jsonв--profileЗапишите отнимающую много времени информацию в процессе строительства,--jsonВывести результат сборки в формате JSON,>stats.jsonэто команда канала в системах UNIX/Linux, означающая, что содержимое выводится в файл stats.json через канал.

  1. Официальный инструмент Webpack Analyze

    Откройте официальный сайт инструмента http://webpack.github.io/analyse/ и загрузите stats.json, вы сможете получить результаты анализа

  2. webpack-bundle-analyzer

    Инструмент визуального анализа, более интуитивно понятный, чем Webapck Analyse. Он также очень прост в использовании:

    1. npm i -g webpack-bundle-analyzer установить глобально
    2. Создайте файл stats.json в соответствии с описанным выше методом.
    3. Выполнить в корневом каталоге проектаwebpack-bundle-analyzer, браузер автоматически откроет страницу анализа результатов.

7. Другие советы

  1. При настройке babel-loaderuse: [‘babel-loader?cacheDirectory’]cacheDirectory используется для кэширования результатов компиляции babel для ускорения перекомпиляции. Также обратите внимание на исключение папки node_modules, поскольку файлы используют синтаксис ES5, нет необходимости использовать преобразование Babel.

  2. Настройте внешние компоненты для исключения кода, который не нужно упаковывать, поскольку он был импортирован с помощью тега

  3. Настройте параметр производительности для вывода конфигурации проверки производительности файла.

  4. Настроить профиль: true, следует ли собирать информацию о производительности сборки Webpack для анализа причин низкой производительности сборки.

  5. Настроить кеш: true, включать ли кеширование для повышения скорости сборки.

  6. Вы можете использовать url-loader для преобразования небольших изображений в base64 и встраивания их в JS или CSS, чтобы сократить время загрузки.

  7. Сжимайте изображения с помощью плагина imagemin-webpack-plugin и создавайте изображения спрайтов с помощью webpack-spritesmith.

  8. В среде разработки установите для devtool значение Cheap-module-eval-source-map, потому что генерация этой исходной карты является самой быстрой и может ускорить сборку. Установите для devtool значение hidden-source-map в рабочей среде.