构建的核心是资源管理。简单说,构建就是把前端工程师开发的源代码进行编译、压缩、打包等一系列操做,最终产出能够直接上线或者可供后端工程师的资源。javascript
构建能够划分为纯前端构建和先后端协做构建。php
这两个不是专业术语,若是你有更合适的称谓,欢迎指正。css
所谓纯前端构建,就是说不涉及后端模板的构建,通过构建以后的前端代码能够直接上线。这种情形下大可能是数据驱动UI的web应用,模板只负责提供空白的容器和基础的静态资源,UI的文档结构交由前端JavaScript实现。这个过程可使用一些框架,好比近期较流行的React、Vue等;也使用较轻量级的JavaScript模板工具,好比的underscore template、jsmart、Mustache等;甚至能够直接拼接字符串。html
先后端协做构建与纯前端构建惟一的不一样是加入了对后端模板的依赖,这也是目前绝大多数web应用的工做模式。这种模式下,构建工具要额外处理模板中对静态资源的引用地址。咱们在浅析前端工程化一文中提到的即是先后端协做的构建模式,也是本文将要讨论的方向。前端
下面咱们细化资源管理的每一个关键点,共同探讨一下前端工程中构建环节的工做内容和面临的问题。java
若是是纯前端构建(不涉及后端模板),在资源管理方面,编译工具须要完成的事情包括:es6
是否合并这一步由用户选择,好比项目中使用requirejs做为前端模块化方案,考虑到缓存、异步等问题可能选择不合并。这种状况下每每须要在本次构建产出的资源依赖表的基础上进行二次构建,后续会详细说明。web
一套完整的构建流程以下图所示:
算法
具体构建流程中的各个行为并非严格按照上图的先后顺序进行,能够自行安排。后端
上图中提到的各个构建行为中,代码审查、预编译、uglify&compress、hash指纹实现较容易,各构建模式中没有差别,本文便再也不赘述。而依赖打包管理和模板构建是须要额外配置而且方案不惟一,下面详细探讨这两个行为的具体内容。
依赖管理之因此方案不惟一是由于每一个项目可能会采用不一样的客户端模块加载方案(AMD/CMD/CommonJS)。构建平台自己不该该面向某一种方案,而应该是可配置的。
好比某个项目客户端的模块化方案采用AMD,使用requirejs做为模块加载器,那么在构建平台产出上述资源依赖表以后,还须要对requirejs进行配置,这个阶段咱们能够称为二次构建。
二次构建要用到依赖分析以后的资源依赖表和release以后产出资源定位表。假设资源依赖表格式以下:
{ 'a.js': { deps:['b.js','c.js'] } 'c.js': { deps: ['d.js'] } 'e.js': { deps: ['f.js'] } }
资源定位表的格式以下:
{ 'src/js/a.js': 'release\js\a.sdf43n.js', 'src/js/b.js': 'release\js\b.sdf43n.js', 'src/js/c.js': 'release\js\c.sdf43n.js', 'src/js/d.js': 'release\js\d.sdf43n.js', 'src/js/e.js': 'release\js\e.sdf43n.js', 'src/js/f.js': 'release\js\f.sdf43n.js', }
在二次构建阶段,requirejs根据资源依赖表和资源定位表须要做出以下配置:
requirejs.config({ baseUrl: '/', path: { 'a.js': 'release\js\a.sdf43n.js', 'b.js': 'release\js\b.sdf43n.js', //... }, shim: { 'c.js': { deps: ['d.js'] } //... } });
虽然同步依赖的文件原则上应该打包成一个文件,可是构建平台不该该制定一些条律,因此在requirejs配置完成以后,构建平台应该还须要提供是否压缩打包的配置项。
此外,若是开发阶段使用es6语法,客户端使用AMD方案的话,在二次构建以前还须要将es6 module模块编译为AMD规范,这一步在预编译阶段完成。
模板构建的核心问题是如何同步更新静态资源的引用地址。除此以外,模板中每每还包含一些由Controller输出的动态数据,在构建过程当中须要谨慎处理各模板引擎的语法。
目前对模板的处理分为两种模式:由前端负责构建和由后端负责构建。
这两种模式不只仅是分工的不一样,同时涉及开发方案的不一样。
若是模板由前端构建工具进行编译,交到后端开发者手里的模板中对静态资源的引用地址是已经更新后的url,后端开发者不须要对模板进行额外操做即可以直接进行下一步流程(测试、部署)。
可是前端构建工具必须谨慎处理模板引擎的语法,以避免形成“误伤”。后端模板引擎多种多样,前端构建工具很难作到百分百覆盖。因此一般状况下须要对模板中静态资源的url添加额外标识位,以处理文本的方式识别标识位并进行替换。好比:
<script src='[__static-start__]src/js/index.js[/__static-end__]'></script>
上述代码中将index.js
的url用类ubb格式的开闭标签包裹起来。假设经编译后index.js
的资源定位表以下:
{ 'src/js/index.js': 'static.daojia.com/js/index.sfdf232.js' }
前端构建工具首先获取模板文件的文本内容,正则出[__static-start__]src/js/index.js[/__static-end__]
,而后替换为static.daojia.com/js/index.sfdf232.js
。
以上的操做每每很是耗时,而且不能保证百分百正确率。
模板有后端构建的意思是,后端开发人员对模板引擎进行扩展,书写一个模板引擎语法的资源寻址function。好比php使用smarty模板引擎实现一个cdn
方法:
<?php /* * Smarty plugin * ------------------------------------------------------------- * File: function.cdn.php * Type: function * Name: cdn * Purpose: transform internal cdn path to online format * ------------------------------------------------------------- */ function smarty_function_cdn($params, Smarty_Internal_Template $smarty){ //... }
还能够针对不一样类型的静态资源扩展对应的cdn寻址方法:
<?php /* * Smarty plugin * ------------------------------------------------------------- * File: function.js.php * Type: function * Name: js * Purpose: print script tag by url * ------------------------------------------------------------- */ require_once('function.cdn.php'); function smarty_function_js($params, $smarty){ //... }
而后前端开发人员在编写smarty模板时即可以使用以下语法引入静态资源:
{js url="/src/js/index.js"}
前端构建工具只须要处理静态资源便可,后端模板在部署上线后会将index.js
的url更新为线上地址。
模板交由后端构建的优势是能够对每种模板引擎有针对性的处理,并且是很工程化的构建方式;缺点是须要额外书写寻址function,可是这个缺点相对于优势来讲微不足道。
综上所述,模板前端构建和后端构建的对好比下:
根据表格的对比数据能够看出模板后端构建相比前端构建有很大优点。可是做为构建平台,应该同时支持两种模式。因此在开发构建平台的时候,开发者应该提供前端构建的功能接口,由用户选择是否采用。
本文简单讲述构建平台在不一样开发模式下对应的构建方案。以上内容是笔者的一些经验和思考,确定会有不足和错误之处,欢迎你们反馈,共同探讨。