Bundle Size: insight
Tags: react, deploy
Published: 2019-09-23 21:30:31

No se si hay suficientes artículos de como optimizar el tamaño del _bundle_, en casi todos los que he visto encuentro algo más para agregar a mi proceso y es por eso que quiero empezar con la conclusión a la que llegué.

El _bundle_ es un conjunto de _assets_ agrupados en base a un análisis de dependencias deducido del código fuente (imports) que resuelven el problema de la integración de las dependencias de un proyecto. Teniendo una gama de _assets_ distintos, tanto en tipo como en funcionalidad, algunos incluidos explicitamente como en el código y otros implicitos que ayudan al proceso de desarrollo (webpack, react, dev mode) es evidente que la complejidad sea proporcional a la dimensión del bundle.

El producto final no es unicamente el contenido también incluye la experiencia de interacción y esta empieza cuando el usuario decide darle click al link y espera su respuesta. Si bien el bundle simplificó la complejidad de las dependencias, es necesario evidenciar unas suposiciones para mejorar la experiencia, como la que todo el código debe estar presente al mismo tiempo (splitting), o que deba cargarse secuencialmente (paralelismo) y por último que los fuentes sean bonitos y entendibles (minify).

En resumen, mi conclusión es que para reducir el bundle se deben tomar acciones en estas cuatro areas:

*   eliminar: código redundante o sub utilizado
*   extraer: assets y favorecer la paralelización
*   dividir: agrupar solo el código necesario
*   optimizar: cada uno de los assets, según su tipo

PROBLEMA
========

Hice una SPA simple para presentar unos proyectos y la hospedé en github, necesitaba agregar unos componentes dinámicos a la página por lo que use ReactJS implementándolo por medio de [portales](https://jmarroyave-blog.herokuapp.com/es/2019/09/11/reactjs-portales/). La cuestión es que para ser algo tan simple era demasiado pesado:

```
app.js 586.6KB  
  2.js 377.3KB  
  3.js  45.7KB  
--------------  
     1,009.6KB

polyfill.js  93.1KB
```

![](https://miro.medium.com/max/1798/0*pJL6BzvIgSKvqdtM.png)

Esta es la foto de la página y requiere de casi 1MB de código sin contar el HTML, CSS, imágenes. Mi hipótesis es “el bundle está empacando código que no utiliza” por lo que me puse a investigar un poco y a reducir cada una de las partes involucradas (aunque en este post me enfocaré en el código de javascript)

El resultado final, luego de revisar el bundle fue:

```
app.js 481.9KB  
--------------  
       481.9KB

polyfill.js  92.9KB
```

lo cual representa un **48%** del tamaño del original y aunque la hipótesis era correcta era solo una parte del problema.

ANÁLISIS Y HERRAMIENTAS
=======================

Para empezar necesitaba ver la composición del bundle

WEBPACK
-------

permite generar un [archivo](https://webpack.js.org/api/stats/) con el grafo de dependencias y assets, bastante grande y en json, mucha información pero poco manejable

webpack --profile --json > stats.json

[WEBPACK-BUNDLE-ANALYZER](https://www.npmjs.com/package/webpack-bundle-analyzer)
--------------------------------------------------------------------------------

analiza el grafo de dependencias que genera webpack, bueno para visualizar el conjunto pero no tan bueno para el detalle

\# package  
npm install webpack-bundle-analyzer -g\# analyze, generate report  
webpack-bundle-analyzer stats.json

![](https://miro.medium.com/max/1742/0*ftcIMlbtIdSU03i3.png)

[SOURCE-MAP-EXPLORER](https://www.npmjs.com/package/source-map-explorer)
------------------------------------------------------------------------

muy parecido al anterior, no tan bonito, pero con un mejor nivel de detalle

source-map-explorer script.js

![](https://miro.medium.com/max/1664/0*rTHZpAvZbmXDGKdG.png)

[BUNDLE-STATS](https://www.npmjs.com/package/bundle-stats)
----------------------------------------------------------

Este brinda una lista completa de la composición del bundle, los assets y los paquetes incluidos, es una visualización del stats.json generado por webpack

![](https://miro.medium.com/max/1664/0*os9jcfRGEtCBn8ZH.png)

SOLUCIÓN
========

Ya con la información de la composición

![](https://miro.medium.com/max/1742/0*2DrzfSIeip4hD4tG.png)

1\. REACT-DOM.DEVELOPMENT.JS
----------------------------

cambiando el modo a producción en webpack.config.js

```
mode: 'production'
```
```
all - 2.82MB   
app - 2.58MB   
polyfill - 248.1KB
```
2\. MOMENT.JS -> DATE-FNS
-------------------------

La biblioteca de moment.js a pesar de ser bastante completa es bastante grande, ademas de todas las localizaciones que incluye. La sustituí por [date-fns](https://date-fns.org/).
```
all - 2.32MB   
app - 2.08MB   
polyfill - 248.1KB
```
3\. LIMPIAR CÓDIGO NO UTILIZADO
-------------------------------

Hice una revisión de código muerto en algunos componentes la cual fue dejando imports sin utilizar
```
all - 2.27MB   
app - 2.02MB   
polyfill - 248.1KB
```
4\. HELMET -> DOCUMENT.TITLE
----------------------------

Utilizaba helmet unicamente para ponerle el título a la página, esto lo cambié por document.title = “title”
```
all - 2.22MB   
app - 1.98MB   
polyfill - 248.1KB
```
5\. AXIOS -> FETCH
------------------

Para el manejo de la comunicación utilizaba axios pero la funcionalidad que requería podía ser cubierta por fetch.
```
all - 2.03MB   
app - 1.79MB   
polyfill - 248.1KB
```
6\. LINT FIXES
--------------
```
all - 2.03MB   
app - 1.79MB   
polyfill - 248.1KB
```
7\. ELIMINAR JAVASCRIPT-TIME-AGO
--------------------------------

Estoy trabajando sobre un framework que he ido construyendo en el tiempo y en algún momento utilicé esta función la cual puede ser sustituida por date-fns
```
all - 1.62MB   
app - 1.38MB   
polyfill - 248.1KB
```
8\. MATERIAL-UI
---------------

alto costo en refactor, solo actualice la versión esperando que los devs atrás de la biblioteca también estuvieran haciendo lo suyo en esta materia

9\. REACT -> PREACT
-------------------

cambiar react por preact? suena bien aunque el proceso me resultó con varios errores en la migración.
```
all - 1.51MB   
app - 1.27MB   
polyfill - 248.1KB
```
10\. QUITAR HOT LOADER Y DEPENDENCIAS DE DEARROLLO
--------------------------------------------------

11\. EXTRAER ASSETS: CSS, FUENTES, IMÁGENES
-------------------------------------------

webpack - mini-css-extract-plugin
```
all - 1.43MB   
app - 1.19MB   
polyfill - 248.1KB
```
12\. DYNAMIC LOADING
--------------------
```
const { FixedSizeList } from 'react-window'; 

const { FixedSizeList } = Loadable({  
   loader: () => import('react-window'),  
       loading: Loading,  
}); 

const FixedSizeList = Loadable({  
   loader: () => import('react-window/FixedSizeList'),  
       loading: Loading,  
});
```
13\. TARGETING
--------------
```
devtool: false,  
target: "web",   
externals: {  
 React: 'react'  
}
```

14\. MINIMIZAR
--------------

Terser

![](https://miro.medium.com/max/1742/0*RGTAm__1lOQCL6sY.png)

Resumiendo, los 14 puntos anteriores los categoricé de la siguiente forma

ELIMINAR
--------

Apoyo a desarrollo

*   react-dom.development.js
*   removing hot loader

Refactoring

*   moment.js
*   helmet
*   axios
*   javascript-time-ago
*   material-ui
*   react

Revisión de código

*   código no utilizado
*   linting

EXTRAER
-------

css, imágenes, fuentes

DIVIDIR
-------

Dynamic loading

*   react-window
*   optimizations chunks

OPTIMIZAR
---------

targeting y minimize

Hasta aquí la lista por hoy, estoy consciente que puede ser más extensa. Me gustaría saber otros puntos que recomienden tomar en cuenta.

REFERENCIAS
===========

*   [https://lemoncode.net/lemoncode-blog/2018/5/7/webpack-poniendo-a-dieta-tus-bundles-ii](https://lemoncode.net/lemoncode-blog/2018/5/7/webpack-poniendo-a-dieta-tus-bundles-ii)
*   [https://dev.to/sheddy\_nathan/possible-ways-to-reduce-your-webpack-bundle-size-js-secrets-550](https://dev.to/sheddy_nathan/possible-ways-to-reduce-your-webpack-bundle-size-js-secrets-550)
*   [https://medium.com/@poshakajay/heres-how-i-reduced-my-bundle-size-by-90-2e14c8a11c11](/@poshakajay/heres-how-i-reduced-my-bundle-size-by-90-2e14c8a11c11)
*   [https://material-ui.com/guides/minimizing-bundle-size/](https://material-ui.com/guides/minimizing-bundle-size/)
*   [https://goenning.net/2018/11/26/how-we-reduced-initial-jscss-size/](https://goenning.net/2018/11/26/how-we-reduced-initial-jscss-size/)
*   [https://www.intercom.com/blog/reducing-intercom-messenger-bundle-size/](https://www.intercom.com/blog/reducing-intercom-messenger-bundle-size/)