“ Jackal”:压缩前端

你好 我是Vanya,是Tinkoff Business平台团队的负责人。

我最喜欢的消遣是打开DevTools选项卡,并检查网站工件的重量。 在本文中,我将告诉您如何在平台前端团队的帮助下,在一天之内将应用程序的权重降低30%,而无需更改站点代码。 没有技巧和注册-只有nginx,docker和node.js(可选)。




为何


现在,前端应用程序很重要。 收集的工件可能重2-3 MB,甚至更多。 但是,压缩算法可以帮助用户。

直到最近,我们仅使用Gzip,而Gzip于1992年问世。 这可能是网络上最流行的压缩算法,IE 6之上所有浏览器均支持该算法

让我提醒您,Gzip的压缩级别在1到9的范围内变化(效率更高),您可以动态或静态压缩它。

  • “动态”(动态)-工件以组装后收到的形式存储,其压缩发生在交付给客户的过程中。 在我们的例子中,在nginx级别。
  • 静态-工件在组装后被压缩,并且HTTP服务器将它们“按原样”发送给客户端。

显然,第一个选项为每个请求需要更多的服务器资源。 第二个是在组装和准备应用程序的阶段。

第四层动态压缩了我们的前端。 我将演示压缩的工件与原始工件之间的区别:
压缩等级
工件重量, Kb
压缩时间,毫秒
0
2522
--
1个
732
42
2
702
44
3
683
48
4
636
55
5
612
65岁
6
604
77
7
604
80
8
603
104
9
601
102

您可能会注意到,即使第四个级别,工件的大小也减少了4倍! 第四级和第九级之间的差是35 Kb,即原始值的1.3%,但压缩时间长了2倍。

最近,我们想到:为什么不切换到Brotli? 是的,并且是最强大的压缩级别!

顺便说一下,该算法由Google在2015年推出,具有11种压缩级别。 同时,Brotli的第四级比Gzip的第九级更有效。 我很有动力,并迅速使用Brotli算法抛出代码来压缩工件。 结果如下:
压缩等级
工件重量, Kb
压缩时间,毫秒
0
2522
--
1个
662
128
2
612
155
3
601
156
4
574
202
5
526
227
6
512
249
7
501
303
8
496
359
9
492
420
10
452
3708
11
446
8257

但是,该表显示,即使第一个Brotli压缩级别也比Gzip中的第九个级别花费更长的时间。 最后一级-多达8.3秒! 它提醒了我。

另一方面,结果显然令人印象深刻。 接下来,我尝试将压缩传递给nginx- Google文档 。 一切都变得非常简单:

brotli on; brotli_comp_level 11; brotli_types text/plain text/css application/javascript; 

他组装了泊坞窗映像,启动了容器,并非常惊讶:



我文件的下载时间增加了十倍-从100毫秒增加到5秒! 该应用程序变得无法使用。

对文档进行了更深入的研究之后,我意识到您可以静态分发。 我使用了以前编写的脚本,压缩了相同的工件,将其放入容器中并启动了它。 下载时间恢复正常-胜利! 但是,现在还太高兴了,因为支持这种压缩方式的浏览器的比例约为80%

这意味着您必须保持向后兼容性,同时还希望使用最有效的Gzip级别。 因此,提出了制作文件压缩实用程序的想法,该实用程序后来被命名为“ Jackal”。



我们需要什么?


Nginx,Docker和Node.js,尽管您也可以根据需要使用bash。
使用Nginx,几乎所有事情都是清楚的:

 brotli off; brotli_static on; gzip_static on; 

但是如何处理尚未设法更新docker映像的应用程序呢? 正确,添加向后兼容性:

 gzip on; gzip_level 4; gzip_types text/plain text/css application/javascript; 

我将解释操作原理:


在每次请求时,客户端都会发送一个Accept-Encoding标头,其中列出了受支持的压缩算法,以逗号分隔。 通常是deflate,gzip,br。

如果客户端在行中带有br,则nginx会查找扩展名为.br的文件,如果没有此类文件并且客户端支持Gzip,则它将查找.gz。 如果没有这样的文件,则它将“动态”抖动并以第四级压缩将其返回。

如果客户端不支持任何类型的压缩,则服务器将以其原始形式发布工件。

但是,出现了一个问题:我们的nginx docker映像不支持Brotli模块。 作为基础,我拍摄了完成的码头工人形象

用于在项目中“打包” nginx的Dockerfile
 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 


我们发现了流量平衡,但是从哪里获得工件呢? 这就是the狼来营救的地方。

Jack狼


这是一个用于压缩应用程序静态变量的实用程序。

现在,这是三个打包在docker映像中的node.js脚本,其节点为:alpine。 让我们来看一下脚本。

基本压缩器 -一种实现基本压缩逻辑的脚本。

输入参数:

  1. 压缩功能-任何javascript功能,您都可以实现自己的压缩算法。
  2. 压缩参数-具有传递函数所需参数的对象。
  3. 扩展-压缩工件的扩展。 必须以句点字符开头。

gzip.js-一个带有基本压缩程序调用的文件,该文件具有从zlib软件包传递来的Gzip函数,并指示第九级压缩。

brotli.js-具有从同一npm包传递来的Brotli函数的基本压缩程序调用的文件,并指示第11级压缩。

Dockerfile创建Jackal映像
 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 


我们弄清楚了它是如何工作的,现在您可以安全地运行:

 docker run \ -v $(pwd)/dist:/scripts/dist \ -e 'dirs=["dist/"]' \ -i mngame/shakal 

  • -v $(pwd)/ dist:/ scripts / dist-指定要考虑容器中目录的本地目录(链接到安装)。 需要指定脚本目录,因为它在容器内运行。
  • -e'dirs = [“ dist /”]'-指定环境参数dirs-描述脚本/中将被压缩的目录的行的数组。
  • -i mngame / shakal-使用docker.io指定映像

在指定的目录中,脚本以递归方式压缩所有具有指定扩展名.js,.json,.html,.css的文件,并保存其旁边具有扩展名.br和.gz的文件。 在我们的项目中,此过程大约需要2分钟,而所有工件的重量大约为6 MB。

此时,甚至可能更早,您可能已经想到:“什么码头工人? 哪个节点? 为什么不只是在项目的package.json中添加两个包,然后直接在postbuild上调用呢?”

就个人而言,看到这个项目是为了在CI中运行短毛绒,何时为自己安装100个以上的软件包,这在代理阶段是您的时间,也就是您最终的上市时间。

对于docker,我们得到了一个预组装的映像,其中安装了压缩所需的一切。 如果您现在不需要压缩任何内容-不要压缩。 需要一个皮棉-仅运行它,需要测试-仅运行它们。 另外,我们得到了Jackal的一个很好的版本:我们不需要在每个项目中都更新其依赖项-只需发布一个新版本,并为该项目使用最新标签即可。

结果:


  • 伪影的大小已从636 Kb更改为446 Kb。
  • 百分比大小减少了30%。
  • 下载时间减少了10-12%。
  • 根据文章 ,减压时间保持不变。

合计


您可以立即通过下一个PR帮助您的用户:组装后添加一个步骤-“ Jackal”压缩,然后将工件交付到您的容器中。 半小时后,您的用户会感觉好一些。

我们设法将前端的重量减少了30%-您将成功! 所有简易站点。

参考文献:


Source: https://habr.com/ru/post/zh-CN474632/


All Articles