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

为何
现在,前端应用程序很重要。 收集的工件可能重2-3 MB,甚至更多。 但是,压缩算法可以帮助用户。
直到最近,我们仅使用Gzip,而Gzip于1992年问世。 这可能是网络上最流行的压缩算法
,IE 6之上的
所有浏览器均支持该算法
。让我提醒您,Gzip的压缩级别在1到9的范围内变化(效率更高),您可以动态或静态压缩它。
- “动态”(动态)-工件以组装后收到的形式存储,其压缩发生在交付给客户的过程中。 在我们的例子中,在nginx级别。
- 静态-工件在组装后被压缩,并且HTTP服务器将它们“按原样”发送给客户端。
显然,第一个选项为每个请求需要更多的服务器资源。 第二个是在组装和准备应用程序的阶段。
第四层动态压缩了我们的前端。 我将演示压缩的工件与原始工件之间的区别:
您可能会注意到,即使第四个级别,工件的大小也减少了4倍! 第四级和第九级之间的差是35 Kb,即原始值的1.3%,但压缩时间长了2倍。
最近,我们想到:为什么不切换到Brotli? 是的,并且是最强大的压缩级别!
顺便说一下,该算法由Google在2015年推出,具有11种压缩级别。 同时,Brotli的第四级比Gzip的第九级更有效。 我很有动力,并迅速使用Brotli算法抛出代码来压缩工件。 结果如下:
但是,该表显示,即使第一个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。 让我们来看一下脚本。
基本压缩器 -一种实现基本压缩逻辑的脚本。
输入参数:
- 压缩功能-任何javascript功能,您都可以实现自己的压缩算法。
- 压缩参数-具有传递函数所需参数的对象。
- 扩展-压缩工件的扩展。 必须以句点字符开头。
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%-您将成功! 所有简易站点。
参考文献: