4 dicas para otimizar seu aplicativo webpack

Olá pessoal!

Durante meu trabalho com o webpack, acumulei algumas dicas interessantes que ajudarão você a preparar um aplicativo perfeitamente otimizado. Vamos começar!

Gato front-end analisa webpack e diz 'Belíssimo'



1. Use fast-async em vez de regenerator-runtime


Normalmente, os desenvolvedores usam @ babel / preset-env para converter todas as sintaxes modernas em ES5.

Com essa predefinição, o pipeline de transformações de funções assíncronas fica assim:
Função assíncrona de origem -> Gerador -> Função usando regenerator-runtime

Exemplo
1. A função assíncrona original

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

2. Gerador

 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. Função usando 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); }; }(); 


Com a async rápida, o pipeline é simplificado para:
Função assíncrona de origem -> Função usando promessas

Exemplo
1. A função assíncrona original

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

2. Função usando promessas

 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); }); }; 


Devido a isso, agora não temos tempo de execução do regenerador no cliente e wrappers extras das transformações.

Para trazer a rápida assíncrona para o seu projeto, você deve:

1. Instale

 npm i fast-async 

2. Atualize a configuração do babel

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

Para mim, essa otimização reduziu o tamanho dos arquivos js em 3,2%. Um pouco, mas legal :)

2. Use transformações soltas


Sem configuração especial, o @ babel / preset-env tenta gerar o código o mais próximo possível da especificação.

Mas, provavelmente, seu código não é tão ruim e não usa todos os casos extremos possíveis da especificação ES6 +. Em seguida, toda a sobrecarga extra pode ser removida, permitindo transformações soltas para o preset-env:

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

Um exemplo de como isso funciona pode ser encontrado aqui .

No meu projeto, isso reduziu o tamanho do pacote em 3,8%.

3. Configure a minificação de js e css com as mãos


As configurações padrão para minificadores contêm apenas as transformações que não podem ser quebradas pelo programador. Mas gostamos de causar problemas?
Tente ler as configurações do js minifier e do seu css minifier (eu uso o cssnano ).

Tendo estudado as docas, fiz esta configuração:

 // 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 }, }, }), ], }, }; /* ... */ 

Como resultado, o tamanho dos arquivos js diminuiu 1,5% e css - 2%.

Talvez você possa fazer melhor?

UPD 01/11/2019: O UglifyJsPlugin está obsoleto, o webpack agora usa o TerserWebpackPlugin . Use-o.

4. Use null-loader para remover dependências desnecessárias


Os desenvolvedores do gsap têm uma ótima biblioteca para criar animações. Mas devido ao fato de ser originário de 2008, alguns recursos permaneceram nele.

Ou seja , este . Graças a ele, o TweenMax usa 5 plugins e o easPack, que são completamente opcionais.

Notei três plugins redundantes dentro de mim e os cortei usando o 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', }, ] }, }; /* ... */ 

E 106 kb se transformam em 86. Sim!

O carregador nulo ainda pode ser usado para remover polyfills desnecessários que os autores da biblioteca plantaram cuidadosamente para nós.

Source: https://habr.com/ru/post/pt425215/


All Articles