4 совета для оптимизации webpack-приложения

от автора

Всем привет!

За время моей работы с вебпаком у меня накопилась пара интересных советов, которые помогут вам приготовить отлично оптимизированное приложение. Приступим!

Кот-фронтендер смотрит на webpack и говорит 'Белиссимо'

1. Используйте fast-async вместо regenerator-runtime

Обычно, разработчики используют @babel/preset-env, чтобы преобразовывать весь современный синтаксис в ES5.

С этим пресетом пайплайн преобразований асинхронных функций выглядит так:
Исходная асинхронная функция -> Генератор -> Функция, использующая regenerator-runtime

Пример

1. Исходная асинхронная функция

const test = async () => {   await fetch('/test-api/', { method: 'GET' }); } 

2. Генератор

function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }  const test = (() => {   var _ref = _asyncToGenerator(function* () {     yield fetch('/test-api/', { method: 'GET' });   });    return function test() {     return _ref.apply(this, arguments);   }; })(); 

3. Функция, использующая regenerator-runtime

'use strict';  function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }  var test = function () {   var _ref = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {     return regeneratorRuntime.wrap(function _callee$(_context) {       while (1) {         switch (_context.prev = _context.next) {           case 0:             _context.next = 2;             return fetch('/test-api/', { method: 'GET' });            case 2:           case 'end':             return _context.stop();         }       }     }, _callee, undefined);   }));    return function test() {     return _ref.apply(this, arguments);   }; }(); 

С fast-async пайплайн упрощается до:
Исходная асинхронная функция -> Функция, использующая промисы

Пример

1. Исходная асинхронная функция

const test = async () => {   await fetch('/test-api/', { method: 'GET' }); } 

2. Функция, использующая промисы

var test = function test() {   return new Promise(function ($return, $error) {     return Promise.resolve(fetch('/test-api/', {       method: 'GET'     })).then(function ($await_1) {       try {         return $return();       } catch ($boundEx) {         return $error($boundEx);       }     }, $error);   }); }; 

Благодаря этому, теперь у нас нет regenerator-runtime на клиенте и лишних оберток от трансформаций.

Чтобы подвести fast-async в свой проект, надо:

1. Установить его

npm i fast-async

2. Обновить конфиг бабеля:

// .babelrc.js module.exports = {   "presets": [     ["@babel/preset-env", {       /* ... */       "exclude": ["transform-async-to-generator", "transform-regenerator"]     }]   ],   /* ... */   "plugins": [     ["module:fast-async", { "spec": true }],     /* ... */   ] } 

У меня эта оптимизация уменьшила размер js файлов на 3.2%. Мелочь, а приятно 🙂

2. Используйте loose трансформации

Без специальной настройки @babel/preset-env пытается сгенерировать как можно более близкий к спецификации код.

Но, скорее всего, ваш код не настолько плох и не использует все возможные крайние случаи ES6+ спецификации. Тогда весь лишний оверхед можно убрать, включив loose трансформации для preset-env:

// .babelrc.js module.exports = {   "presets": [     ["@babel/preset-env", {       /* ... */       "loose": true,     }]   ],   /* ... */ } 

Пример того, как это работает, можно найти тут.

В моем проекте это уменьшило размер бандла на 3.8%.

3. Настройте минификацию js и css руками

Дефолтные настройки для минификаторов содержат только те трансформации, которые не смогут ничего сломать у программиста. Но мы ведь любим доставлять себе проблемы?
Попробуйте почитать настройки минификатора js и своего минификатора css (я использую cssnano).

Изучив доки, я сделал такой конфиг:

// webpack.config.js const webpackConfig = {   /* ... */   optimization: {     minimizer: [       new UglifyJsPlugin({         uglifyOptions: {           compress: {             unsafe: true,             inline: true,             passes: 2,             keep_fargs: false,           },           output: {             beautify: false,           },           mangle: true,         },       }),       new OptimizeCSSPlugin({         cssProcessorOptions: {           "preset": "advanced",           "safe": true,           "map": { "inline": false },         },       }),     ],   }, }; /* ... */ 

В результате размер js файлов уменьшился на 1.5%, а css — на 2%.

Может, у вас получится лучше?

4. Используйте null-loader для удаления ненужных зависимостей

У разработчиков gsap получилась отличная библиотека для создания анимаций. Но из-за того, что она берет свое начало еще из 2008 года, в ней остались некоторые особенности.

А именно вот эта. Благодаря ней TweenMax тянет за собой 5 плагинов и easePack, которые юзать совершенно необязательно.

У себя я заметил три лишних плагина и выпилил их с помощью null-loader:

// webpack.config.js const ignoredGSAPFiles = ['BezierPlugin', 'DirectionalRotationPlugin', 'RoundPropsPlugin'];  const webpackConfig = {   /* ... */   module: {     rules: [       /* ... */       {         test: /\.js$/,         include: ignoredGSAPFiles.map(fileName => resolve('node_modules/gsap/' + fileName)),         loader: 'null-loader',       },     ]   }, }; /* ... */ 

И 106 кб превращаются в 86. Та-да!

Null-loader еще можно использовать для удаления ненужных полифиллов, которые авторы библиотек заботливо нам подложили.


ссылка на оригинал статьи https://habr.com/post/425215/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *