Hola Soy Vanya, el líder del equipo de plataforma en Tinkoff Business.
Mi pasatiempo favorito es abrir la pestaña DevTools y verificar cuánto pesan los artefactos del sitio web. En este artículo, le contaré cómo redujimos el peso de la aplicación en un 30% con la ayuda del equipo de front-end de la plataforma en un día sin cambiar el código del sitio. Sin trucos ni registros: solo nginx, docker y node.js (opcional).

Porque
Ahora las aplicaciones de front-end pesan mucho. Los artefactos recolectados pueden pesar 2-3 MB, o incluso más. Sin embargo, los algoritmos de compresión ayudan a los usuarios.
Hasta hace poco, solo usábamos Gzip, que se introdujo al mundo en 1992. Este es probablemente el algoritmo de compresión más popular en la web, es compatible con
todos los navegadores superiores a IE 6.Permítame recordarle que el nivel de compresión de Gzip varía en el rango de 1 a 9 (más es más eficiente), y puede comprimirlo sobre la marcha o estáticamente.
- “Sobre la marcha” (dinámicamente): los artefactos se almacenan en la forma recibida después del ensamblaje, su compresión se produce durante la entrega al cliente. En nuestro caso, a nivel nginx.
- Estático: los artefactos se comprimen después del ensamblaje y el servidor HTTP los envía al cliente "tal cual".
Obviamente, la primera opción requiere más recursos del servidor para cada solicitud. El segundo está en la etapa de montaje y preparación de la aplicación.
Nuestro frontend fue comprimido dinámicamente por el cuarto nivel. Demostraré la diferencia entre un artefacto comprimido y el original:
¡Puede notar que incluso el cuarto nivel reduce el tamaño del artefacto en 4 veces! Y la diferencia entre el cuarto nivel y el noveno es de 35 Kb, es decir, el 1.3% del original, pero el tiempo de compresión es 2 veces más largo.
Y recientemente, pensamos: ¿por qué no cambiar a Brotli? ¡Sí, y al nivel de compresión más potente!
Por cierto, este algoritmo fue introducido por Google en 2015 y tiene 11 niveles de compresión. Al mismo tiempo, el cuarto nivel de Brotli es más efectivo que el noveno en Gzip. Me motivé y rápidamente lancé código para comprimir artefactos con el algoritmo Brotli. Los resultados se presentan a continuación:
Sin embargo, la tabla muestra que incluso el primer nivel de compresión Brotli tarda más que el noveno nivel en Gzip. Y el último nivel, ¡hasta 8,3 segundos! Me alertó
Por otro lado, el resultado es claramente impresionante. Luego, traté de transferir la compresión a nginx -
google la documentación . Todo resultó ser extremadamente simple:
brotli on; brotli_comp_level 11; brotli_types text/plain text/css application/javascript;
Reunió la imagen de la ventana acoplable, lanzó el contenedor y quedó terriblemente sorprendido:

El tiempo de descarga de mi archivo se multiplicó por diez, de 100 ms a 5 segundos. La aplicación se ha vuelto imposible de usar.
Después de estudiar la documentación más a fondo, me di cuenta de que puede distribuir estáticamente. Utilicé un script previamente escrito, comprimí los mismos artefactos, lo puse en un contenedor y lo lancé. Descargar tiempos de vuelta a la normalidad - victoria! Sin embargo, es demasiado pronto para alegrarse, porque la proporción de navegadores que admiten este tipo de compresión es de
aproximadamente el 80% .
Esto significa que debe mantener la compatibilidad con versiones anteriores, mientras que además desea utilizar el nivel más efectivo de Gzip. Entonces surgió la idea de crear una utilidad de compresión de archivos, que luego recibió el nombre de "Chacal".

Que necesitamos
Nginx, Docker y Node.js, aunque también puede usar bash si lo desea.
Con Nginx, casi todo está claro:
brotli off; brotli_static on; gzip_static on;
¿Pero qué hacer con las aplicaciones que aún no han logrado actualizar la imagen del acoplador? Derecha, agregue compatibilidad con versiones anteriores:
gzip on; gzip_level 4; gzip_types text/plain text/css application/javascript;
Explicaré el principio de funcionamiento:
En cada solicitud, el cliente envía un encabezado Accept-Encoding, que enumera los algoritmos de compresión compatibles, separados por comas. Por lo general, se desinfla, gzip, br.
Si el cliente tiene br en la línea, entonces nginx busca archivos con la extensión .br, si no hay tales archivos y el cliente admite Gzip, entonces busca .gz. Si no hay tales archivos, se sacudirá "sobre la marcha" y lo devolverá con el cuarto nivel de compresión.
Si el cliente no admite ningún tipo de compresión, el servidor emitirá artefactos en su forma original.
Sin embargo, surgió un problema: nuestra imagen nginx docker no es compatible con el módulo Brotli. Como base, tomé la
imagen de docker terminada .
Dockerfile para "empaquetar" nginx en un proyecto FROM fholzer/nginx-brotli # RUN rm -rf /usr/share/nginx/html/ # COPY app/nginx /etc/nginx/conf.d/ # COPY dist/ /usr/share/nginx/html/ # CMD nginx -c /etc/nginx/conf.d/nginx.conf
Descubrimos el equilibrio del tráfico, pero ¿de dónde obtener los artefactos? Aquí es donde el Chacal viene al rescate.
El chacal
Esta es una utilidad para comprimir la estática de su aplicación.
Ahora, estos son tres scripts de node.js envueltos en una imagen acoplable con nodo: alpine. Repasemos los guiones.
compresor base : un script que implementa una lógica básica de compresión.
Argumentos de entrada:
- Función de compresión: cualquier función de JavaScript, puede implementar su propio algoritmo de compresión.
- Parámetros de compresión: un objeto con parámetros necesarios para la función transferida.
- Extensión: expansión de artefactos de compresión. Debe especificarse comenzando con un carácter de punto.
gzip.js : un archivo con una llamada de compresor base con la función Gzip pasada del paquete
zlib e indicando el noveno nivel de compresión.
brotli.js : archivo con una llamada de compresor base con la función Brotli pasada desde el
mismo paquete npm e indicando el nivel 11 de compresión.
Dockerfile creando la imagen del Chacal FROM node:8.12.0-alpine # COPY scripts scripts # package.json package-lock.json COPY package*.json scripts/ # WORKDIR scripts # # node_modules/ # , RUN npm ci # CMD node gzip.js | node brotli.js
Descubrimos cómo funciona, ahora puede ejecutar de forma segura:
docker run \ -v $(pwd)/dist:/scripts/dist \ -e 'dirs=["dist/"]' \ -i mngame/shakal
- -v $ (pwd) / dist: / scripts / dist - especifica qué directorio local considerar el directorio en el contenedor (enlace al montaje). Se requiere especificar el directorio de scripts, ya que funciona dentro del contenedor.
- -e 'dirs = ["dist /"]' - especifica los parámetros de entorno dirs - una matriz de líneas que describen los directorios dentro de los scripts / que se comprimirán.
- -i mngame / shakal: especificando una imagen con docker.io.
En los directorios especificados, el script comprime recursivamente todos los archivos con las extensiones especificadas .js, .json, .html, .css y guarda los archivos con las extensiones .br y .gz al lado. En nuestro proyecto, este proceso lleva aproximadamente dos minutos y el peso de todos los artefactos es de aproximadamente 6 MB.
En este punto, y tal vez incluso antes, podría haber pensado: “¿Qué acoplador? Cual nodo? ¿Por qué no simplemente agregar dos paquetes a usted mismo en el package.json del proyecto y llamar directamente en postbuild?
Es muy doloroso para mí ver cuándo, en aras de ejecutar linters en CI, el proyecto instala más de 100 paquetes, de los cuales necesita un máximo de 10 en la etapa de linting. Este es el tiempo del agente, su tiempo, después de todo, el tiempo de comercialización.
En el caso de la ventana acoplable, obtenemos una imagen premontada en la que se instala todo lo necesario para la compresión. Si no necesita comprimir nada ahora, no lo comprima. Necesita una pelusa, solo hágalo, necesita pruebas, solo hágalo. Además, obtenemos una buena versión de Jackal: no necesitamos actualizar sus dependencias en cada proyecto; simplemente publique una nueva versión y use la última etiqueta para el proyecto.
Resultado:
- El tamaño de los artefactos ha cambiado de 636 Kb a 446 Kb.
- El porcentaje de tamaño disminuyó en un 30%.
- El tiempo de descarga disminuyó en un 10-12%.
- El tiempo de descompresión, según el artículo , sigue siendo el mismo.
Total
Puede ayudar a sus usuarios ahora mismo, en el próximo PR: agregue un paso después del ensamblaje: compresión “Jackal” y luego entregue artefactos a su contenedor. Después de media hora, sus usuarios se sienten un poco mejor.
Logramos reducir el peso del front-end en un 30%, ¡tendrá éxito! Todos los sitios fáciles.
Referencias