前端团队 Gulp & Webpack 工作流 迁移记

2,177 阅读6分钟
原文链接: zhuanlan.zhihu.com

折腾

从 2015 到现在,短短的三年内,几乎每年折腾一下工作流的 “ 更新换代 ”。从最早开始使用 Grunt 到 Gulp 再到 Webpack,再到 Rollup,再到 Webpack@2.x ......

在这个前端工具变化如此之快的浪潮里,在前端团队中,并发合作开发多个项目,前后端分离等等情况下,配置 或者 升级 或者 迁移 这样的工作流 基本生产工具,往往造成耗费的就不是仅仅一个人的时间成本,而是十人,数十人的量级。

所以 一个靠谱、稳定、有效的工作流方案就显得特别重要。


Gulp

14 年 15 年初,因为构建性能等问题,已经从 Grunt 迁移到 Gulp 了 ( duowan/generator-lego )。从开源的 Github 仓库上不难看出,主要 工作流 是基于命令行的形式,配合 yeoman 脚手架工具,以 Gulp 任务为核心的。

对于 Gulp 定义,官方的说法是

gulp is a toolkit for automating painful or time-consuming tasks in your development workflow, so you can stop messing around and build something.

表明着,Gulp 是一个专门帮你处理一些痛苦耗时的自动化任务工具。

在这个表述中,Gulp 倾向的是于对 “任务” 这个概念的处理,而这个 “任务”,其实如果我们都尝试配置过 Gulp 的话,也就大概明白是怎样的一回事。

在这段时间期间,团队面向的业务,主要分类占比最大的是 专题类,运营类。

在这类专题基本入口都是从 HTML 开始,写 HTML Dom 结构,写样式,再后可能就写一些 JS 动效或者 AJAX 。几乎 JS 占比分量是超级少的,个别页甚至没有脚本,单纯给到 HTML & CSS 给到后端同事直出数据。

那时候 Gulp 所配置的任务


  • 监听匹配文件的变化自动刷新浏览器
  • 自动编译 SASS
  • 自动补全 CSS3 前缀
  • 多雪碧图合并、2x、3x 拼图
  • 等等

基于编译 HTML / SASS / 图片的任务,已经是完全满足我们的需求了。



Webpack

在 15 年末开始,渐渐接入的业务方向改变,需要接触到 Vue,也就渐渐发现 Gulp 对于 JS 模块处理的局限性。也在这时候,开始衡量是否需要迁移到 Webpack。

对于 Webpack 定义,官方的说法是

webpack, the production / unbiased / flexible / extensible / open source module bundler.
表明着,Webpack 是一个 xxx 的打包器。

而在这个表述中,Webpack 更多的偏向于资源的整理打包。而这个打包的开始,就是 定义在配置上的 entry。

对于 Vue 或 React 这类型的项目,Webpack 无疑是最最最适合不过了,以 JS 模块为编写入口,生成依赖链,整理打包出 HTML / JS / CSS / 图片。

开始本来也就以为 单单工作流核心 将 Gulp 迁移到 Webpack,这样就可以轻松解决。

直至到后来在 雪碧图的合并,2x / 3x 多倍图的输出上,在 Webpack 上苦苦找寻不了比较完美的解决方案等等。

另外团队还存有一些 专题业务类 的需求,也需要兼容旧有项目,团队成员开发时候,切换前端生产工具的适应性等,带来了一系列的问题。

这时迫切希望有 更加简便、有效的工作流方案。



Gulp + Webpack

既然 Gulp 对任务处理的强大,而 Webpack 对 JS 模块处理的专业,也就衡量着这两者的混合。

由 Gulp 基于处理 HTML / SASS / 图片等部分,Webpack 主要对 JS 模块进行编译。

带着这样的想法,也有网上挺多的思路,例如 gulp + webpack 构建多页面前端项目 · Issue #17 · fwon/blog 。但是都忽略了较根本上的问题 :

  • 每次 JS 改变都重新通过 Webpack 完整打包输出,效率没有保证

  • Webpack 下 JS 热刷新应该怎么联动 Gulp 的热刷新

基于解决根本痛点的,平衡功能,使用了另外一套方案 :

  1. Webpack 基于 webpack-dev-server 启动热刷新 服务 A
  2. browser-sync 使用 proxy 代理 服务 A 启动 服务 B
  3. Gulp watch HTML / SASS / 图片 变动
  4. Gulp watch 变动后触发 browser-sync reload

<img src="https://pic1.zhimg.com/v2-ecda2fcacaa6ebbee960b3813e84381c_b.png" data-rawwidth="742" data-rawheight="482" class="origin_image zh-lightbox-thumb" width="742" data-original="https://pic1.zhimg.com/v2-ecda2fcacaa6ebbee960b3813e84381c_r.png">
  • 通过 webpack-dev-server 热刷新等方式,优化 开发中 JS 构建效率
  • 通过 proxy 代理 让 webpack-dev-server 热刷新同步刷新 浏览器

Gulp 负责部分的 HTML / SASS / 图片等任务基本没有太大的变动,因而可以兼容到过往的旧项目需求,另外团队成员额外需要了解的是 JS 模块 Webpack 部分的构建,学习成本相对降低,在 2015 年末正式作为工作流解决方案加入在团队脚手架工具。


走多一步

2016 年初开始,因组内成员的增加,或者工作流功能版本的更新, 都伴随着维护工作流的各种问题 ( 即便写了不能再详细的文档 ),大致回归到 Node 版本的兼容性,node_modules 的版本功能兼容,Windows / macOS 带来的兼容性等等问题。

这时在思考着,能否有包装多一层去让这些兼容性问题都 避免开呢 ?

其实对于这样的整体封装,无疑有两条路可以走

  1. 类似于 NW 那样构建出 平台应用
  2. 类似于 PKG 那样构建出 执行程序

在寻找解决方案的时候,发现了 weixin/WeFlow ,但深入发现 WeFlow 仅基于 Gulp 任务,功能远远满足不了需求。

于是便开始了轮子的重构,首先遇到问题是 node-sass 的编译依赖问题,感谢 WeFlow 开发者分享踩过的坑( node-sass 依赖环境问题 · Issue ),如果团队是使用 less 或者 stylus 都无需重置那些依赖。

另外遇到了最麻烦的问题就是把 webpack 生态 迁移到应用上去,babel 依赖 / vue-loader 依赖 / ..... 其中遇到过各种依赖被重置到全局的问题,都在 babel 或者 vue-loader 的源码上进行 切面置换依赖。

经过几个内测版本的开发下,造出了 legoflow/legoflow

组内推行使用后也得到了 赞同的反馈,经过了几个大项目的洗礼后,从功能性变得更加丰富,兼容性上更加稳定。


<img src="https://pic3.zhimg.com/v2-453ef89bb0efbeb1eb2f2af13db5bc6a_b.png" data-rawwidth="990" data-rawheight="555" class="origin_image zh-lightbox-thumb" width="990" data-original="https://pic3.zhimg.com/v2-453ef89bb0efbeb1eb2f2af13db5bc6a_r.png">

而在今年 6 月也对外兼容版本 LegoFlow


走得更远

现在工作流中内置的 Webpack 还是基于 1.x 版本,其实在年初的时候是有想法把 整个 Webpack 生态升级为 2.x,因为在 webpack 2.x RC 期间,对 Rollup tree-shaking 已经很垂涎了。但是 Webpack 正式到 2.x,却发现无法兼容到 IE8 ( webpack2 doesn't support IE8 · Issue #3070 · webpack/webpack ),部分业务也脱离不了 IE8 的行列。

但计划在更远一点的时间下,看看如何能否到实现 Webpack 1.x & 2.x 的无缝切换。



最后

前端团队几次的生产力工作流工具的迁移,只是前端这个大浪潮中最小最小的 缩影。

每次改变像是意味着 进化,在如今 这个前端浮躁的年代,希望 做着相同事情的我们 有着一如既往的 初心 上下求索。