在 JavaScript 应用越发多样化和越发复杂的趋势下,也给构建带来了越来越多的挑战。在公司级别的环境下,搭建一个基础环境就要耗费半天,已经输在了起跑线上。我们希望有一个工具来使开发同学专注于研发本身。本文会介绍基于 Webpack 实现的构建工具 Ykit,以及它在去哪儿网的实践。
Webpack 是现在最流行的前端构建工具之一。它具备高可配置性的特点,你可以用它来构建 React、Angular、Vue 等等各种类型的 Javascript 应用。它的构建过程十分灵活,支持使用各种模块加载器和插件进行个性化定制。
Webpack 工作示意图
然而从另一方面来讲,Webpack 的高灵活性也带来了配置过于复杂,对初学者不友好等问题。在公司内部我们希望开发同学能更加专注于研发本身,摆脱掉繁冗的配置文件并且避免一些实际使用中的陷阱 。在本文中会介绍基于 Webpack 实现的构建工具 Ykit,它在 Webpack 基础上进行了哪些优化,以及它在公司中的应用现状。
1. 背景——各自为战时期
在 Ykit 出来之前,公司里的开发同学使用过各种各样的构建工具。有 Gulp、Grunt、Webpack 以及一些类似的工具等,从这些独立构建的项目中我们发现了几个共同的问题:
- 几乎每个项目都要通过配置或脚本完成一些特定的工作。比如指定资源输入输出路径、生成资源版本号、配置 HMR 、搭建 mock 服务等等,这些类似的工作经常被重头到尾实现一遍。这些工作如果可以由统一的工具来实现则可以节省很多开发成本。
- 缺少构建层面的优化。不管是从打包出来的资源体积以及编译速度上,不少项目都有很大的提升空间。我们曾试着将其中一个工程的公用库用 CommonChunks 的方式提取出来,将整体资源体积减小了多一半。这主要是因为很多时候开发同学只是想短平快地完成一些业务,并不会过多关注流程上的优化。
- 沟通和学习成本高。跨团队和跨项目都有可能由于构建工具和流程不一样而带来额外的成本。当面对一个缺少文档的新项目时,一个新来的同学可能是完全懵逼的,要先花好久搭建环境才能把项目运行起来。而项目间工具的不一致也会导致切换环境时要花更多的时间和精力。
沟通不畅
由这些现象我们在想,能不能提供一个统一的工具出来,将这些共性的工作由工具来完成,保持开发体验的一致性,使得开发同学在构建项目时效率更高并且少踩一些坑。
2. Ykit——多样化的构建
Ykit 是对 Webapck 的一层封装,如果要说它最大的特点,就是用插件机制来封装了各种类型应用的配置,只要选择安装合适的插件就可以把一个基本的开发环境搭建好了。
插件
比如说做一个 React 应用,只要安装上相应的 React 插件就可以直接在代码里引用 React 模块,和编写 ES6 语法的代码了。而当你想使用 Ant Design 这个 UI 组件库,则引入相应它的插件即可。目前公司内外有十几个不同的插件来满足多样化的需求。
除了封装第三方模块,插件内部还可以添加很多编译打包流程上的钩子,方便完成各种构建流程上的工作。在公司内部的构建流程中有很多固定的任务,比如生成一个单独存放资源版本号的文件等。这些类似的工作都被纳入了一个专门为公司构建流程设计的插件中,每个项目将其引入之后即不必担心这些构建流程中的问题。
实际上利用插件还可以做更多更有想象力的事情。比如现在有为微信小程序量身打造的 Ykit 插件。它内置了初始化脚手架,编译小程序特定语法,支持引入 npm 包等等功能,目前公司的小程序都是依赖于它来构建。另外也有专门用来制作移动端活动页的插件,它可以将 psd 设计稿直接生成 html,自动生成雪碧图,封装了常用的样式和动画库让开发者可以高效地完成各种布局和特效。
总的来说 Ykit 身只是一个壳,真正的多样化构建依赖于插件。插件都是一个个 npm 模块,它们将构建过程中的配置和功能进行封装,使得 Ykit 能满足多种多样的需求而又不会互相冲突,同时保持了开发体验的相对一致性。
3. 如何使构建更快?
Webpack 一直容易被人诟病的就是它的构建速度慢。官方虽然也给出了许多优化策略,但是一些优化只对特定类型的项目有效果,对于其他项目则效果有限,而对于开发者来说有时并没有时间和精力去一个个尝试到自己的项目中。而这些工作由 Ykit 来做却是非常合适的。
接触 Webpack 的同学应该不难发现 Webpack 总是第一次构建很慢。启动项目时要等好久才能把页面打开,这是因为 Webpack 会把所有的资源都打包一遍。如果项目中有 10 个 JS,而第一次打开的页面只请求了其中一个,那么也要等所有资源作为一个整体打包完成之后返回那其中的一个。
Ykit 在这里进行了一次入口过滤。当本地服务接收到页面的请求时,会带着所请求的资源去项目中找,生成一个只含有所请求的资源入口的 Webpack 实例,打包完成后立即返回结果。实际情况还要比这个更复杂一些,比如所请求的资源有可能只是打包的副产品而不在配置入口中,Ykit 对这些情况都进行了处理。最后达到的效果是页面请求哪个资源才会打包哪个资源,即便是对于很大型的工程来说第一次打开的速度也会相对来说可以接受。
本地服务资源打包优化
另一个在 Webpack 中很耗时的操作是压缩资源,Ykit 并没有采用它内置的 UglifyJS 插件,而是采用多进程去压缩,与此同时这也解决了较大型应用使用 Webpack 压缩资源时内存溢出的问题。对于资源数量多的项目有比较显著的提升。之前有一个资源数在 70 个左右的项目,使用多进程压缩之后将它的构建时间从 75s 减少到了 25s。
最后一些就是在 Ykit 插件中内置的优化了。插件其实是很适合来做这种工作的,因为针对不同类型应用优化的策略也不一样。比如使用 Babel 来编译 es6 代码的时候可以采用 Happypack 替代原有的 Loader 进行打包。去哪儿有一套移动端的开发框架 Hy2,它内部的依赖库很多。我们在它的插件中使用了 Happypack、 DLLPlugin 等优化策略,将首次打包的时间从 10~20s 减少到了 3~4s 。不同插件可以针对自己的场景进行深度优化,使每一种类型的应用都变得更高效。
4. 现状和未来
在公司中各个业务线都已经开始在使用 Ykit 构建和发布,截止到目前上线的项目有 80 多个。在未来我们还会着眼更多的场景,就像现在为小程序提供的脚手架和开发工具,在以后可能会有更多这样的模式,使得搭建各种各样的开发环境都变得更加简单,让开发同学更少地去花精力在构建这件事而更加专注于研发本身。 |