Оптимизация размера сборки webpack
Недавно я создал приложение React.js, которое можно оценить как умеренно сложное одностраничное приложение. Я пытался оптимизировать время загрузки страницы для различных клиентов и попытался профилировать сайт с помощью одного из доступных инструментов, чтобы проверить, как у нас идут дела.
Наткнулся на testmysite от Google, проверил веб-страницу и получил следующие результаты:
Сайт был оценен как очень отзывчивый в плане дизайна, но буквально очень «медленный» по времени загрузки. Я изучил различные части кода для определения времени загрузки страницы, и этот пост служит руководством для тех, кто хочет оптимизировать то же самое.
Первым шагом для проверки является текущий размер пакета и проверьте, являются ли все зависимые пакеты абсолютно необходимыми.
$ webpack -p --progress Hash: dbce3735c9520e2dc682 Version: webpack 1.14.0 Time: 54264ms Asset Size Chunks Chunk Names dist/index.js 3.29 MB 0 [emitted] main dist/index.js.map 13.7 MB 0 [emitted] main [0] multi main 40 bytes {0} [built] + 1374 hidden modules
У меня текущий размер пакета составил более 3 мегабайт, и это объясняет ужасные оценки с инструмента профилирования.
1. Проанализируйте зависимости вашего пакета
Я использовал webpack-bundle-analyzer, который анализирует статистику webpack и дает отличную визуализацию, чтобы просмотреть сравнение размеров зависимостей!
Установите пакет с помощью следующей команды
$ npm install --save-dev webpack-bundle-analyzer
Измените ваш webpack.config.js, чтобы включить плагин. Если у вас есть несколько профилей для каждой среды, лучше сделать это в рабочей конфигурации и создать приложение для этого профиля.
var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; // ... plugins: [new BundleAnalyzerPlugin()] // ...
Теперь при запуске сервера должна отображаться визуализация по адресу http://localhost:8888. Вы должны увидеть что-то похожее ниже, и вы можете перейти на любой уровень, чтобы узнать, какие пакеты нужно обрезать или удалить.
Это должно помочь найти тяжелые зависимости. Также при импорте зависимостей лучше импортировать только необходимые функции/компоненты из библиотек как показано ниже.
//1. Импорт всей библиотеку lodash import lodash from 'lodash' lodash.groupBy(rows, 'id') //2. Импорт только необходимой функции import groupBy from 'lodash/groupBy' groupBy(rows, 'id')
2. Правильная среда в сборке
Указание подходящей среды в webpack гарантирует, что все артефакты разработки и тестирования не будут входит в сборку. Для этого вы можете определить NODE_ENV как продакт в конфигурации плагинов
plugins: [... new webpack.DefinePlugin({ 'process.env.NODE_ENV': '"production"' }), ..]
3. Включить минимизированный source map
Когда вы создаете сборку для продакт, наряду с минимизацией и объединением ваших JavaScript файлов, вы генерируете исходную карту (source map), которая содержит информацию о ваших исходных файлах. Исходная карта с максимальным уровнем детализации может быть сгенерирована для среды разработки или подготовки. Но мы можем выбрать наиболее оптимизированную форму исходных карт для среды продакт.
Проверьте конфигурацию вашего webpack, часто можно увидеть devtool: ‘eval’, который является одним из самых быстрых способов создания приложений, в которых большая часть информации о коде разработки включена в вывод. Давайте переключим этот параметр на eval-source-map или cheap-module-source-map. Обратитесь к этой документации, чтобы узнать больше о каждом из этих параметров конфигурации.
Давайте еще раз проверим размер пакета на этом этапе, чтобы увидеть, сколько мы сэкономили.
$ webpack -p --progress Hash: 68a52fddbcc2898a5899 Version: webpack 1.14.0 Time: 29757ms Asset Size Chunks Chunk Names dist/index.js 1.71 MB 0 [emitted] main dist/index.js.map 464 bytes 0 [emitted] main [0] multi main 40 bytes {0} [built] + 1365 hidden modules
С 3.29 МБ мы уменьшили до 1.71 МБ, а также стоит отметить, что уменьшился размер source map!
4. Другие известные плагины для оптимизации размера сборки
Я перечисляю другие плагины, которые я использовал для дальнейшего уменьшения размера. Рассмотрите подходящие для вашего варианта использования и используйте их по мере необходимости:
- compression-webpack-plugin: плагин для сжатия ресурсов, который будет генерировать файлы .gz вместе с assets, и в зависимости от клиента сервера ресурсов может быть использован по мере необходимости.
- dedupe-plugin: ищет одинаковые или похожие файлы и дедуплицирует их в выходных данных. Это связано с некоторыми накладными расходами, но может эффективно уменьшить размер файла. (доступно по умолчанию в Webpack v.2)
- uglifyjs-plugin: минимизирует весь код JavaScript. Обратитесь к документации по множеству опций
- ignore-plugin: удобен, когда вам нужно импортировать отдельные модули из библиотеки. Например, при использовании moment.js необязательно включать все локали, которые поставляются с библиотекой, а только те, которые необходимы. Это также показано в примере кода ниже.
Окончательная конфигурация веб-пакета может выглядеть следующим образом:
... var CompressionPlugin = require("compression-webpack-plugin"); ... let config = { entry: path.join(__dirname, '../app/index'), cache: false, devtool: 'cheap-module-source-map', plugins: [ new webpack.DefinePlugin({ 'process.env.NODE_ENV': '"production"' }), new webpack.optimize.DedupePlugin(), new webpack.optimize.UglifyJsPlugin({ mangle: true, compress: { warnings: false, // Suppress uglification warnings pure_getters: true, unsafe: true, unsafe_comps: true, screw_ie8: true }, output: { comments: false, }, exclude: [/\.min\.js$/gi] // skip pre-minified libs }), new webpack.IgnorePlugin(/^\.\/locale$/, [/moment$/]), new webpack.NoErrorsPlugin(), new CompressionPlugin({ asset: "[path].gz[query]", algorithm: "gzip", test: /\.js$|\.css$|\.html$/, threshold: 10240, minRatio: 0 }) ... ],
Давайте еще раз проверим размер пакета с окончательной конфигурацией …
$ webpack -p --progress Hash: 68a52fddbcc2898a5899 Version: webpack 1.14.0 Time: 29757ms Asset Size Chunks Chunk Names dist/index.js 1.54 MB 0 [emitted] main dist/index.js.gz 390 KB 0 [emitted] main dist/index.js.map 464 bytes 0 [emitted] main [0] multi main 40 bytes {0} [built] + 1365 hidden modules
Обратите внимание на размер сжатого js-файла, он уменьшился до 390 КБ. Это должно значительно сократить время загрузки страницы. Давайте еще раз запустим тест гугл-профилировщика и проверим, как теперь работает сайт с последним пакетом сборки.
5. Разделение кода (Code Splitting)
Так же я хотел бы в этой статье упомянуть code splitting , как важный шаг к оптимизированной сборке webpack. Идея довольно проста. Если вы используете что-то вроде react-router для определения нескольких страниц в вашем приложении, легко создать дерево зависимостей с компонентами, определенными в маршруте в качестве отправной точки, и связать все ресурсы (js, css, images), необходимые для этого. Если вы используете динамический импорт в своем коде, webpack сможет разумно разделить фрагменты кода, требуемые для каждой страницей.
Более подробное описание code splitting для React вы сможете найти по этой ссылки, а для Vue найдете здесь.
После внесения изменений при запуске сборки вы должны увидеть что типа такого. Webpack создает несколько фрагментов сценариев загрузки для каждой страницы, которую посещает пользователь, что значительно сокращает время загрузки каждой страницы!
Если вам понравился этот пост, пожалуйста, следуйте за мной в twitter для получения дополнительных обновлений на подобные темы ..
Оригинальная статья: Optimising your application bundle size with webpack