大公司里怎样开发和部署前端代码(张云龙)
大公司的静态资源优化方案
- 配置超长时间的本地缓存 —— 节省带宽,提高性能
- 采用内容摘要作为缓存更新依据 —— 精确的缓存控制
- 静态资源CDN部署 —— 优化网络请求
- 更资源发布路径实现非覆盖式发布 —— 平滑升级
如何把之前不再用的静态文件删除呢
这个问题,大致要分两种情况讨论:
使用了CDN缓存
未使用CDN缓存
首先我们先看看非覆盖式发布的部署方式,假设我们把静态资源部署到线上服务器的webroot目录下,第一次发版,其内文件为:
─ webroot
├─ foo.82068b6.js
└─ bar.c1e6b0e.js
接下来版本迭代,产生了新的资源文件需要部署上线,再假设待部署的文件是:
─ release
├─ foo.5899c6d.js
└─ bar.1d163de.js
如果你的项目使用了CDN缓存
由于CDN可以缓存大部分静态资源,所以部署新版本的时候,你可以考虑只部署一份内容,将之前的线上代码直接备份后删除,然后将新的代码部署到webroot下,这样,你的线上部署的结果始终只有一份:
─ webroot # 部署无冗余
├─ foo.5899c6d.js
└─ bar.1d163de.js
这种做法有一个小漏洞,就是部署过程中,如果用户访问旧页面请求了一个很『冷』的资源,在CDN上恰好无缓存需要回源时,由于你的源服务器只保留一个版本,最终会导致资源加载不到而页面报错,但由于出现这种问题的概率比较低,可以忽略不计。
这种部署策略可以让你不用烦恼冗余部署的清理问题
如果你的项目没使用CDN缓存
没有CDN缓存,我们一般也会把静态资源部署到独立的静态资源服务器上,这个时候可以利用服务器的缓存功能可以暂时保留当前版本,这种情况下也可以如使用了CDN缓存一样只保留单一版本。
如果没有任何缓存支持,而项目又是多集群部署的话,静态资源就需要冗余了:
─ webroot # 部署有冗余
├─ foo.82068b6.js
├─ foo.5899c6d.js
├─ bar.c1e6b0e.js
└─ bar.1d163de.js
这种情况下,需要求助运维同学写清理脚本,定期清理。清理的策略主要是根据文件名收集冗余版本,然后根据创建日期保留最近2个版本,其他文件都清理掉。
这里不由得让我想起webpack,webpack在处理资源定位上用了一个讨巧的办法,把所有资源目录层级去掉,展平了放在一起,这种设计对构建工具来说实现很方便,不用保留原始路径,但最终部署的时候会导致一个目录下部署太多静态资源文件,如果再结合多版本冗余部署,最终会对系统读写文件的性能造成一定的影响。
将FIS解决方案理解为“配置”好的FIS项目当我对FIS的使用和了解足够深入的时候,可以利用FIS定制出最适合自己开发需求的解决方案的?
前端架构大部分工作要解决的是 如何用工具连接框架和规范的问题。这是一个工程问题。fis想解决的正是规范与框架的链接问题,而不是简单的前端源码构建。
所谓框架,主要指模块化框架,其职责包括对模块化资源的管理和加载,管理包括js/css的依赖管理,加载包括按需加载和请求合并,以及资源缓存与更新。
所谓规范,主要是指开发和部署规范,比如哪些是模块化资源,哪些是非模块化资源,模块化资源如何包装、优化和部署,非模块化资源如何部署等,什么文件发布到什么目录,是否有CDN等等。
框架、规范、工具三者需要紧密配合才能比较完美的解决模块化开发、性能优化等前端工程问题。
fis本身是一种特殊的 “工具”,通过一些比较 “奇怪” 的配置设计,实现了框架与规范的绑定过程。这些问题我觉得是grunt/gulp不曾思考过的。
fis的解决方案,包括你看到的rsd,还有 scrat,其实都是对fis的配置,每一套配置用于连接一种特定的规范和框架:
fis-plus:以smarty为模板引擎,以 mod 为模块化框架,适用于php后端渲染及部署运维方式的解决方案。
yogurt:以swig为模板引擎,以 mod 为模块化框架,适用于nodejs后端渲染架构及部署运维方式的解决方案
jello:以velocity为模板引擎,以 mod 为模块化框架,适用于java后端渲染架构及部署运维方式的解决方案
pure:无后端渲染,使用前端模板,以 mod 为模块化框架,适用于纯前端,前后端严格分类的项目
gois:go语言解决方案。
spmx:纯前端方案,以seajs为模块化框架,一个示例项目,不完整,不要用于生产
rsd:纯粹是为了展示静态资源md5问题的项目,把fis所有的语言插件都装上,可以在一个项目里混合多种语言进行开发,用资源内嵌实现打包,可以认为是最简易的fis,不适合大规模生产。
scrat:以 scrat.js 为模块化框架,内含webapp、seo、olpm三种模式,其中:webapp是纯前端解决方案,依赖combo服务实现资源合并,适用于中型移动端单页面应用。
seo是多页面模式,以swig为模板引擎,进行后端渲染,支持quickling(或者pjax),以combo服务合并资源,面向需要seo的单页面应用。
olpm是运营后台模板开发模式,我们内部有一个CMS,可以用这种模式进行开发,本地预览,然后把代码打包上传到cms系统,作为专题模板使用。
总之,由于前端的开发环境、开发模式、部署方式实在是太五花八门了,有传统多页面模式,有移动端SPA模式,有CMS组件化拼装模式,不同的模式还可能会结合不同的后端语言(不要以为前端可以完全从后端剥离出来,不理解其中的原理,我可以单独写一篇文章说明),所以不可能有一种固定模式能解决所有问题,fis的设计就是把所有这些模式中的公共部分抽取出来形成一个基础工具,面对不同开发部署规范、不同模块化框架再做配置即可。
所有不同的前端开发模式,有一些相同的内在联系,那就是:资源定位
,资源内嵌
和资源依赖
这三种语言能力。这三种语言能力为什么会成为所有开发模式的共性,这和前端这种特殊的GUI软件的安装和运行方式有关
在grunt/gulp工具链中,有 yo 来做你说的“工具连接框架和规范的问题”
在我理解,yo属于脚手架工具吧,而我说的连接主要是指:
“在开发目录中的什么文件,将来要部署到什么集群上,框架中要做哪些处理” 这样的事情,也就是连接开发规范、部署规范和模块化框架的工作。三者是需要工具进行转换的。
要实现一个完整的模块化开发体系,我觉得需要有一个工具做这些事情:
对模块化资源进行扫描,获取资源依赖关系,生成依赖表,注入到模块化框架中供依赖管理、按需加载、合并请求等优化使用(资源依赖,用于连接框架)
接收一种配置,标记每种类型的文件会发布到什么目录或集群中,然后扫描所有文件中的资源定位标记,将其替换成部署路径(资源定位,用于连接开发和部署规范)
允许一些资源并不是通过模块化方式加载,而是直接内嵌到其他资源中使用,比如把图片以base64形式嵌入到css、js中(资源内嵌,非必须,但很有用)
以上三件事并不是yo的工作。下面图解一下这几件事:
1.所谓工具连接框架
连接框架
就是工具把静态分析的依赖关系以某种形式传递给框架,用于框架在运行时的资源管理、加载及优化
给一个配置文件,告诉工具,源码中的什么文件(用reg匹配)部署后会发布到哪里(release定义),这样,工具会把源码中所有关于这个资源的定位标记替换成部署路径。实现开发时使用工程路径,构建后使用部署路径的功能。这个功能可以保证资源的独立性,并且能对性能做优化(加md5戳)。独立性可以让资源无论是被合并、移位还是在其他地方加载都能正常运行。