不确定文章的标题描述的是否已经足够明了,至少用类似的描述在gg中并没有定位到相关的文章。讨论这个话题的更多是围绕这前端工程化套件的用法的(例如webpack、grunt、gulp等),而这些工具对单入口页面SPA应用支持度非常的好。但现实往往不尽如意,面对传统的多入口web项目,前端又应该如何解决浏览器缓存旧版本代码的问题呢?

让我们先来详细描述一下问题的环境域:

  • 多入口项目,意味着包含非常多的html页面
  • 大量的内嵌js和css

我们的关注点不在加载性能上,本次我们仅关注:如何实时影响浏览器端及时访问更新后的代码版本。这应该属于工程问题,而非开发问题。意味着我们不应该试图让开发人员来解决这个问题,而应该在工具上来寻找突破口。毕竟,开发人员来解决的话,他们会简单粗暴的靠代码来禁用浏览器缓存,这虽然确实“治本”,但杀伤力太大,朕很不喜欢。那么到底应该怎么来做才完美呢?

首先我们来看看到底有哪些内容被缓存了:

  • html,以及内嵌其中的js和css
  • 外联的js和css
  • 其它静态资源文件,如图片等

回忆之前写的spa项目,不存在内嵌js,所有项目的前端应用js脚本都会最终编译打包成一个独立的文件,并且会根据合并后的内容做签名,有效的避免了浏览器使用旧版本缓存的问题。而html这部分也都会使用js模版方案,最终也是会编译成js打包起来的。css也会合并成一个带内容签名的独立文件的。换句话说,SPA项目已经有了成熟的解决方案和工具来帮我们解决旧代码版本的浏览器缓存问题。

但,传统的多html文件入口的web项目呢?就没有人管它们的死活了吗?好像真的是啊!唉~至少我在google上找了一圈,都没有相关资料啊(baidu就不试了)。看来只能挽起袖子自己动手丰衣足食了啊!

其实也并不需要从零做起,依然是可以根据现有工具来实现我们所需的功能的。这里我打算基于webpack来完成这个挑战。不过在具体动手之前,得先仔细分析一下要解决的问题范围:

  • html的新旧版本问题
  • 外联js和css的新旧版本问题

第二个问题其实webpack已经可以解决的很好了。关键是第一个问题很难搞,为什么呢?如果我们参照js文件的处理方式来修改html文件的名字来依靠签名做版本控制,这会导致我们还需要同步维护应用逻辑中所有的跳转链接,让其自动的可以绑定最新的文件名。

如果我们的前端项目中要求所有使用链接的地方都调用一个特定的函数来获取目标链接,这是可以让我们有机会在前端脚本执行时根据额外的一个路由表来动态绑定正确的链接。但这个方案的问题是,要求代码修改量较大,且会导致用户的历史收藏夹保存的链接失效。

再考虑考虑,如果我们不修改html的文件名本身,而是在后面增加请求参数呢?例如:

test.html?v=1&

经测试,完美。那我们可以保证html版本的更新不会导致用户历史收藏夹失效,但依然需要大量的人为修改代码的工作,有没有进阶的办法呢?其实可以将这部分的人工操作自动化处理。只需要匹配出html中所有的链接,并根据生成的路由表来自动替换即可。

注意上面例子中结束的”&”,这样若项目需要其它的地址栏参数,则可以直接拼接。

目前能想到的需要匹配出的链接上下文场景有:

  • html中a标签的href属性
  • 内嵌js脚本的相关跳转地址
  • 可能还会有form标签的action属性
  • 外联js脚本的相关跳转地址

注意一个细节,由于我们是先根据文件内容创建出路由表,再去替换文件内容中的链接地址,这会再触发一次内容变更。目前我不确定这是否会成为一个问题,不过先标注出来吧。

思路大致有了,感觉也不是太复杂。剩下的就是看看如何使用webpack来完成了。


###补充

由于我们当前的项目是基于这个框架来组织代码的,所以前面提到的那个会导致手工修改工作量的问题在当前项目中其实不存在。而且,我们的思路中提到的路由表甚至都不需要生成,因为本身这个框架中就提供了每个模块的配置文件,我们只需要修改配置文件中对应项即可完成目标,简直了!

根据具体情况,我在原有编译流程中增加了这些逻辑,轻松完成需求。