4 consejos para optimizar tu aplicación webpack

Hola a todos!

Durante mi trabajo con el paquete web, he acumulado un par de consejos interesantes que lo ayudarán a preparar una aplicación perfectamente optimizada. ¡Empecemos!

El gato front-end mira el paquete web y dice 'Belissimo'



1. Use fast-async en lugar de regenerator-runtime


Por lo general, los desarrolladores usan @ babel / preset-env para convertir toda la sintaxis moderna a ES5.

Con este preajuste, la tubería de transformaciones de funciones asincrónicas se ve así:
Fuente asíncrona de origen -> Generador -> Función usando regenerator-runtime

Ejemplo
1. La función asincrónica original

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

2. generador

 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. Función 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); }; }(); 


Con la sincronización rápida, la tubería se simplifica para:
Función asíncrona de origen -> Función usando promesas

Ejemplo
1. La función asincrónica original

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

2. Función usando promesas

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


Debido a esto, ahora no tenemos tiempo de ejecución de regenerador en el cliente y envoltorios adicionales de las transformaciones.

Para incorporar la sincronización rápida a su proyecto, debe:

1. Instalarlo

 npm i fast-async 

2. Actualice la configuración de babel

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

Para mí, esta optimización redujo el tamaño de los archivos js en un 3,2%. Un poco, pero agradable :)

2. Usa transformaciones sueltas


Sin una configuración especial, @ babel / preset-env intenta generar código lo más cerca posible de la especificación.

Pero, muy probablemente, su código no es tan malo y no utiliza todos los casos extremos posibles de la especificación ES6 +. Luego, se puede eliminar toda la sobrecarga adicional al habilitar transformaciones sueltas para preajuste-env:

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

Un ejemplo de cómo funciona esto se puede encontrar aquí .

En mi proyecto, esto redujo el tamaño del paquete en un 3,8%.

3. Configure la minificación de js y css con sus manos


La configuración predeterminada para los minificadores contiene solo aquellas transformaciones que el programador no puede romper. ¿Pero nos encanta causar problemas?
Intente leer la configuración del minificador js y su minificador css (uso cssnano ).

Después de estudiar los muelles, hice esta configuración:

 // 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, el tamaño de los archivos js disminuyó en un 1,5% y css, en un 2%.

¿Quizás puedas hacerlo mejor?

UPD 01/11/2019: UglifyJsPlugin está en desuso, webpack ahora usa TerserWebpackPlugin . Úsalo.

4. Use null-loader para eliminar dependencias innecesarias


Los desarrolladores de gsap tienen una gran biblioteca para crear animaciones. Pero debido al hecho de que se origina en 2008, algunas características permanecieron en él.

A saber , este . Gracias a él, TweenMax extrae 5 complementos y easyPack, que son completamente opcionales.

Noté tres complementos redundantes dentro de mí y los corté usando 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', }, ] }, }; /* ... */ 

Y 106 kb se convierten en 86. ¡Sí!

Null-loader todavía se puede utilizar para eliminar rellenos innecesarios que los autores de la biblioteca cuidadosamente plantaron para nosotros.

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


All Articles