highso-fe / highso-fe-blog

:books: 嗨学网前端团队技术博客
15 stars 3 forks source link

嗨学网 Exam 项目上线自动化静态资源处理复盘分享 #5

Open ghost opened 7 years ago

ghost commented 7 years ago

2017.03.24 发布,最后更新于 2017.03.28

PC Web端 题库项目 v3.1.0 于 2017.03.23(周四)成功上线,这个版本我们对静态资源文件做了压缩处理及版本修订,在各位同事的共同努力下成功将静态资源处理部署至服务器并纳入版本发布自动化流程。

这篇博文旨在结合前端自动化构建领域知识对本次静态资源处理工作做知识分享并复盘本版本上线该功能遇到的问题。

(一)为什么要做自动化静态资源处理?

为了构建高性能 Web,我们通常会考虑到以下2个优化方向:

优化方向 优化手段
请求数量 合并脚本及图片(比如合并 css、js,CSS Sprites 技术)
请求带宽 精简脚本体积、移除冗余脚本代码、图片无损压缩技术

同时,我们项目中还存在以下2个问题:

问题 描述
缓存控制 应避免用户浏览器缓存而不去请求新版本资源的情况
代码安全 不应将 js 代码逻辑完好地暴露在公共网络中

而以上问题都可以通过在开发编码阶段后进行静态资源文件处理去解决。

至于自动化很好理解,为了提高生产力,可以解放劳动力嘛 :blush:

(二)我们做了哪些静态资源处理?

压缩 HTML 文件
压缩 CSS 文件
压缩、混淆 JS 文件

具体参考

压缩图片
版本修订

(三)query 方式还是 hash 方式?

两种方式都可以达到防止浏览器缓存:

query 方式的问题:

  1. 以覆盖同命名文件的方式进行线上资源替换,会导致引用该资源的页面与该资源发布不同步。比如 index.html 需要引用 a.js,一个先上,一个后上,这段间隙内存在引用资源与页面不匹配的问题
  2. 为更新后文件添加 query 很耗开发成本

hash 方式的优势:

  1. 当且仅当文件内容变化时文件名才做修改,与时间因素无关
  2. 由于哈希值是文件名的一部分,上线时可以先上静态资源,再上 html 文件,因此不存在 query 方式的覆盖间隙
  3. 版本回滚时,无需回滚静态资源,只需回滚页面
  4. 由于静态资源文件名只与文件内容相关,因此可以开启永久缓存,只有文件内容更新缓存才会失效,大大增加缓存利用率

(四)部署实施中遇到的问题

  1. 由于为静态资源进行版本修订需要指定基准路径(base url), 因此项目中对静态资源的引用应避免使用相对路径,引用常出现在 .vm, .html, .jsp, .css 中。可以使用 $STATIC_URL/exam/**/*/exam/**/* 的形式。目前解决措施是通过脚本匹配替换相对路径为相应的绝对路径
  2. 个别第三方库,比如 layer,会在 JS 中为 HTML 以添加 <link> 标签的方式添加对其 CSS 的引用,并动态添加 query。(当时和晓东发现这个的时候也是很无语的... :cry:)。对于这种个别情况,文件处理是搞不定的,只能手动排除加入构建黑名单中了...
  3. 应使用转义字符,eg: 使用 &gt; &lt; 而不是 > <
  4. 之前本考虑由于静态处理改动文件范围相当大,我们多测试一个版本再正式上线;发版后意识到,当把项目代码中部分文件引用的 query 去掉并提交过后,实际上静态资源文件处理的上线已经是开弓没有回头箭了 :facepunch:

(五)我们还使用了 Source Map 技术

那么问题来了,版本上线,如何在线上环境下的浏览器中调试已经压缩了的代码?

--> Chrome 和 FireFox 浏览器调试工具自带的 Pretty print 工具

那,如何格式化已经混淆了的 JS 呢?

--> Source Map 技术

(六)为什么需要前端自动化构建工具?

很早之前处理各种情景的工具已经出现了,我们需要把能处理各种任务的工具集成起来,实现可配置、可自动按需执行。对于需要反复重复的任务,例如压缩(minification)、编译、单元测试、linting 等,自动化工具可以减轻你的劳动,简化你的工作

gruntgulp:

Node.js 中,在使用 readFile 方法或 readFileSync 方法读取文件内容或者使用 writeFile 方法或 writeFileSync 方法写入文件内容时,Node.js 将该文件内容视为一个整体,为其分配缓存区并且一次性从缓存区操作文件内容,在这个期间,Node.js 将不能执行任何其他处理。

在很多场合下,我们并不关心整个文件的内容,而只关注是否从文件中读取到了某些数据,以及在读取到这些数据时所需要执行的处理。这时,我们可以使用 Node.js 中的文件流来执行这一处理。

-- 《Node.js 权威指南》

(七)除了处理静态资源,自动化构建还可以做什么?