Yuguo.us

前端工业化1:自动化

Introduction

user

余果

全栈工程师,《Web全栈工程师的自我修养》作者。


Featured

front-end

前端工业化1:自动化

Posted by 余果 on .

最近在学习百度前端工程师张云龙的F.I.S系统的时候,了解到他关于“前端工业化”的理解,我也经历过很多前端架构方法和架构工具的变迁,所以希望借写这篇文章的机会,自己也整理一下。

之前有读者建议我写写关于D.R.Y的经验,其实好的架构能让你免于Repeat Yourself。但是架构的目的不仅限于在开发者侧更轻松,更有组织,而更重要的是在客户侧更简洁纯粹。

张云龙关于架构有一段话很好:

因为优化原则中很多要求是与工程管理相违背的,比如“把css放在头部”和“把js放在尾部”这两条原则,我们不能让团队的工程师在写样式和脚本引用的时候都去修改一个相同的页面文件。

就像是硬币的两面,一面朝客户,关注性能、缓存、减少重复、保持一致;一面朝前端团队,关注维护、发布流程

小型团队也需要合理的架构,这样可以增强扩展性和安全性。当网站从小团队渐渐发展到大团队,网站渐渐拥有千万用户的时候,整个流程更加要自动化。如果说求职的时候需要的“精通CSS”是考察开发者手工技艺,那么前端工业化就是关于如何让开发者团队可以无缝工作。

先介绍我们Qzone团队是怎样从刀耕火种的原始时代过度到现在的。

手工

大概是2010年之前,我们SVN的目录结构很简单。

┌ html
├ public
├ PSD
├ 规范
└ 一些批处理脚本

public里的东西就是对应外网发布的静态资源,包括css和图片,雪碧图全手工拼接。外网代码中甚至能看到注释。

CDN输出静态资源采用统一的缓存规定,好像是一个小时。要发布新代码就直接发布覆盖旧文件,反正缓存时间不长。

但是我们也有长缓存的需求,比如一个黄钻vip的图标,可能一年都不会变,这时候我们规定了一个目录叫/ac/,代表长缓存,至于有多长,这个没法定制,反正运维人员给CDN统一设定了一个很长的时间,开发者想长缓存的东西就丢进去好了。

这个/ac/目录出于某种神秘的原因甚至不在SVN的管理之中,我们要修改的话直接去服务器上拿(后来那台服务器挂了,我们就从外网拿)。

cssgaga

因为我们发布文件的第一步需要把文件放在一台服务器上,然后通过发布系统分发到CDN。放文件这个过程不是很优雅,也不太可靠。需要我们打开两个资源管理器(远程服务器还要输入用户名和密码),然后拷贝过去。

第二步,分发系统(ARS)需要知道文件在哪台服务器上的哪个路径(linux路径),所以我们提交发布单的时候还要提供linux路径列表(称为提单列表),这就很麻烦。

于是我们的团队成员yt 就研发了一个工具叫做cssgaga。在windows上运行,简单配置之后,只要把需要发布的文件拖拽到工具里,就可以自动登录远程服务器并且把文件放在对应的地方,非常方便。

再后来,yt慢慢在cssgaga中加入了更多的功能,比如css文件中的@import语法,可以自动合并成一个css文件,这样减少了http请求和渲染阻塞。

还有data-uri,可以把引入的图片变成data-url,进一步请求,不过这个比较极端,很少用到。比如图片关联性检查,会遍历CSS中对img的引用,并自动生成提单列表。

真正让cssgaga成为团队必不可少人人都用的是在2010年12月,cssgaga加入了自动雪碧图的功能,那篇介绍雪碧图功能的文章获得了80个评论。因为市面上的雪碧图工具都不太好用,拼雪碧图还处于半手工的状态,而cssgaga是完全自动化的。

其实cssgaga这几年一直都在更新,加入了大量团队需要的功能,但是最核心的几条原则从来没有改变过:

  • 本地的CSS源码也是完全合法的语法,没有自定义的语法规则,可以直接打开静态页面,最终cssgaga生成的代码也是最符合雅虎14条的压缩代码。
  • assets之间的关系通过合法的语法关联起来,而不是像F.I.S或者Grunt那样有一个配置关联表。举例来说,多个css组件被@import到同一个A.css中,然后拖A.css的时候就会自动搜寻相对路径中的那些css进来。拖某个css到cssgaga中(并勾选检查关联性),就会自动搜寻当前目录下所有@import了这个css的css文件,并全部发布。
  • 黑盒+不开源

我很欣赏yt有自己的坚持,有清晰的理念支持的工具,但是我们也应该了解其他可能的选择。

Shell编程

之前写过一篇文章Bootstrap的编译机制,当时Bootstrap的CSS文件是使用Make来编译的,如果你没有看过这篇文章,强烈推荐你先阅读这篇文章,再回来也许能更好的理解Make。

GNU make是一个方便的工具,目的是把大量的shell 命令组合起来完成一个任务。这些命令之所以能组合起来,跟Linux哲学是息息相关的:

程序要能协作。程序要能处理文本流,因为这是最通用的接口。

程序协作是通过“依赖”来实现,而make能很好地解决任务之间的依赖问题。

gh-pages: bootstrap docs
    rm -f docs/assets/bootstrap.zip
    zip -r docs/assets/bootstrap.zip bootstrap
    rm -r bootstrap
    rm -f ../bootstrap-gh-pages/assets/bootstrap.zip
    node docs/build production
    cp -r docs/* ../bootstrap-gh-pages
  • gh-pages是工作目标;
  • bootstrap docs是必要条件;
  • 以后的6行是命令

Makefile的语法是linux shell语法,所以对于前端开发来说需要一定的学习成本。这里有一篇不错的文章,可以看一下GNU Make in Detail for Beginners

Grunt

Grunt的自我介绍是:“The JavaScript Task Runner”。

Grunt 是一个开源的基于任务 (Task) 的前端构建框架。它除了有 Jake 的优点(跨平台、开发简单)以外,还有一套设计良好的 task 框架用来组织各种构建任务。Grunt 内置了几个非常常见的构建任务:

  • concat - 组合各种文件
  • lint - 用 JSHint 检查代码
  • min - 用 UglifyJS 压缩代码
  • qunit - 跑 QUnit 单元测试
  • watch - 当源代码文件发生变化时自动执行任务

除此之外还可以通过 npm 来方便的获取几百个现成的 task,比如用 closure 而不是 UglifyJS 来压缩 js,或者用 less 来生成 css,又或者用 jslint 而不是 jshint 来检查语法等,这些任务都可以在 npm 上找到。如果这些任务无法满足你的需求,Grunt 还允许你方便的添加自定任务,就像写 nodejs 代码一样简单。

对于前端开发者来说,Grunt语法可比Shell友好多了,而且Gruntfile.js是合法的javascript文件,在里面可以运行任何合法的javascript代码,非常灵活。关于从Shell过度到Grunt这个过程,有兴趣的可以参考这篇文章Grunt – 最好的前端构建框架

话分两边,工具侧我们一直没有停止进步,朝着更自动化的方向迅猛发展。那么真正面向用户的缓存和请求侧又有哪些进展呢,下一篇日志会讲讲缓存和更新缓存。

user

余果

https://yuguo.us

全栈工程师,《Web全栈工程师的自我修养》作者。