[译]未雨绸缪之:静态资源处理

原文地址: secure.phabricator.com/book/phabfl…

译者水平有限,如果有错误欢迎指正!

未来你会编写越来越多的 JS 和 CSS ,并且最终将找到一个合适的系统来管理它们。

这个是未雨绸缪专栏,汇总了一些web工程化问题,你应该在遇到它们之前就思考它们。

自动化处理依赖

在页面中添加静态资源最简单的办法,就是在页面渲染之前,在页面顶部一个个的引入它们,看 Facebook 之前的方式:

<?php

require_js('js/base.js');
require_js('js/utils.js');
require_js('js/ajax.js');
require_js('js/dialog.js');
// ...
复制代码

这样做在早期是可行的,但从 2007 年开始情况变得不可控了。因为你需要按正确的顺序逐条手动列出这些静态文件,导致其他人需要把这一坨文件复制粘贴到各个页面。这样页面需要加载大量的 JS,影响了前端性能。

于是我们转向了一个被称作 Haste 的系统,该系统使用类似 docblock 的头部声明 JS 依赖:

/**
 * @provides dialog
 * @requires utils ajax base
 */
复制代码

我们给每个文件手动添加注释,虽然理论上可以用静态分析工具代替(我们没有真正这么做是因为我们的 JS 是非结构化的)。这样我们可以通过一次调用请求组件的所有依赖链:

require_static('dialog');
复制代码

...而不是复制粘贴那一大坨依赖文件。

按需加载

早期的方法带来的另一个问题是,所有的静态资源都在页面顶部引入,而不是在实际需要的时候引用。这意味着2点:

  • 你需要引入所有可能在页面上出现的资源;
  • 如果你要在2个及以上的页面添加新内容,你最好把它放到 base.js 里。

这样每个页面都会有一坨蠢代码,例如 CAPTCHA(因为某些工作流涉及未验证的用户,理论上应该在所有页面上向所有用户展示CAPTCHA),以及其他人在 base.js 里时不时添加的东西。

我们转用了一个系统,JS 和 CSS 标签在页面加载完之后被输出(它们还是出现在页面顶部,只是在输出到浏览器之前被预先准备好,而不是被附加进去,这里有些复杂,超出本文讨论范围),所以require_static()可能出现在代码的任何地方。然后我们移动所有的require_static()到调用的地方(只有对话框代码会引入其依赖的 CSS 和 JS,因为并不是每个页面都有对话框),并且把 base.js 拆分成一系列更小的文件。

打包

大部分情况下最大的前端性能杀手是大量的http请求,针对这个问题最有力的武器是把单独的 JS 和 CSS 打包成一个大文件,这样就可以加载一个大的 JS 核心文件而不是加载一堆小文件。一旦其他基本工作到位,这是一个相对容易的更改。我们从手动定义包开始,最终转向基于生产数据的自动生成。

缓存与服务器内容

用最简单的方法引入静态资源,比如用 src="/js/base.js" 写下一个原生 JS 标签。随着站点规模的扩大,这将带来灾难性的问题,因为客户端使用的可能是老版本资源。这会引起一系列微妙的问题(尤其是使用了 CDN 时),最大的问题是当你 push/deploy 站点时用户正访问你的站点,客户端不会为已有的缓存资源发起请求,因此即使你的服务器能正确响应 If-None-Match (ETags) 和 If-Modified-Since (Expires),当你正将静态资源变更 push 到站点时,此时的浏览者将见不到这些变化后的静态资源。

解决这个问题最好的方法是给 URI 加版本号,这样各版本资源文件对应一个独立的 URI,如:

rsrc/af04d14/js/base.js

当你 push 站点时,用户将访问引用新 URI 的页面,浏览器会重新加载资源。

但是,还有一个大问题,一旦你有一堆前端页面:

当你 push 站点时,用户可能会发出一个请求,这个请求由运行新版本代码的服务器处理,返回了一个包含新 URI 的页面。然后浏览器发起了对新 URI 的请求,却被分发到了还未安装新版本代码的服务器上,服务器返回了旧版本的资源。这样客户端就有了脏缓存:新版本的 URI 下缓存了旧版本代码。

有很多巧妙的方法来解决这个问题,Facebook 解决的方法是用数据库而不是硬盘提供静态资源。当一个 push 开始之前,新的静态资源被写在数据库里,这样每个服务器都可以同时处理新旧资源的请求。

这种方式也使一些处理流程变得相对容易(例如删除注释和空格),只需要把压缩/加工的 CSS 和 JS 版本插入数据库即可。

参考实现:Celerity

这里讨论的一些想法在 Phabricator's 的 Celerity 系统中实现,该系统本质上是 Facebook使用的 Haste 系统简化版。

转载于:https://juejin.im/post/5c88a651f265da2de04af973

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值