跟我学 coolie 之 3 模块化构建 hello world
什么是前端构建
前端构建,指的是将开发环境中的代码编译、修改、重写成生产环境下可更快、更好运行的代码。比如压缩 JS、CSS 文件,或者合并 JS、CSS 文件,这些操作都是一个构建过程。
为什么要前端构建
可以不要前端构建吗?答案当然是可以,即生产环境和开发环境是同一份代码。
- 开发环境:通常是本地环境。
- 生产环境:通常是线上环境或预发布环境、测试环境。
如果开发和生产同一份代码,那么会出现以下问题:
- 代码没有经过压缩:浏览器下载的资源会比压缩后的大很多,比如 jquery.js(http://code.jquery.com/jquery-2.1.4.js) 未压缩时大约有 87KB,而压缩版本 jquery.min.js(http://code.jquery.com/jquery-2.1.4.min.js) 只有34KB,文件的容量只有源文件的1/3。压缩后的代码对浏览器来说,都是可读的,不必担心其运行效率。
- 代码没有经过合并:比如网页上放置了10个
script
标签,那么浏览器就要去加载这10个文件后才能运行完毕,而浏览器的并发请求数量是有上限的。例如一次请求只有 5 个,那么就需要连续请求2次。另外,HTTP 请求是无状态的,每次请求都需要重新发起,更加延长了加载时间。 - 没有做版本处理:如果没有做版本管理的话,那么在网站更新的时候,客户机拿到的代码很可能因为缓存的原因,拿到的是旧代码,导致不可预计的问题。
- 等等更多。
构建哪些东西
coolie 很好的每一位前端开发者完成了上述的工作,并且它是低侵入性的,即不需要修改任何源代码(开发环境下代码的不会被修改),也不需要监听构建(百度的 fis 竟然要实时监听构建,无可理喻),几乎 0 配置(比起 spm 那个坑货来说,coolie 构建实在是太强大了)。
coolie 主要构建了哪些东西?
- JS:coolie 能做的:JS 模块依赖分析、合并、压缩、版本管理
- CSS:coolie 能做的:CSS 模块依赖分析、合并、压缩、版本管理
- HTML:coolie 能做的:HTML 文件的资源分析、资源替换、内容压缩
- 静态资源:coolie 能做的:静态资源的依赖分析、版本管理
有兴趣的朋友,可以点击上述链接详看。
如何进行前端构建
生成配置文件
在上一节说到的根目录执行
coolie json
# 生成构建配置文件 coolie.json
如同生成模块加载器配置文件一样,也会通过对话的方式生成:
➜ coolie json
╔═════════════════════════════════════════╗
║ coolie@0.21.6 ║
║ The front-end development builder. ║
╚═════════════════════════════════════════╝
tips => 以下操作留空回车表示同意默认配置。
file path => /path/to/coolie.json
warning => 如果上述目录不正确,请按`ctrl+C`退出后重新指定。
1/7 => 请输入 JS 入口模块的路径。
支持通配符,多个路径使用空格分开,默认为“./static/js/app/**/*.js”。
./index.js
2/7 => 请输入 coolie.js 配置文件所在的路径,默认为“./static/js/coolie-config.js”。
./coolie-config.js
3/7 => 请输入合并压缩后的非模块化 JS 文件的保存目录。默认为“./static/js/”。
不建议与 JS 入口模块的目录一样
./
4/7 => 请输入合并压缩后的 CSS 文件的保存目录。默认为“./static/css/”。
./
5/7 => 请输入 HTML 文件所在的路径。
支持通配符,多个路径使用空格分开。默认为“./views/**/*.html”。
./index.html
6/7 => 请输入构建之后的静态资源(如:图片、字体)的目录,默认为“./static/res/”。
./
7/7 => 请输入构建的目标目录,默认为“../dest/”。
confirm => 文件内容为:
coolie.json => {
"js": {
"src": [
"./index.js"
],
"coolie-config.js": "./coolie-config.js",
"dest": "./",
"chunk": []
},
"css": {
"dest": "./",
"minify": {
"compatibility": "ie7"
}
},
"html": {
"src": [
"./index.html"
],
"minify": true
},
"resource": {
"dest": "./res/",
"minify": true
},
"copy": [],
"dest": {
"dirname": "../dest/",
"host": ""
}
}
confirm => 确认文件内容正确并生成文件?([y]/n)
y
√ => /path/to/coolie.json
生成的配置文件(以下为了说明各个参数的意思,加了注释,实际 JSON 文件是不允许有注释的):
{
// JS 文件构建配置
"js": {
// JS 文件构建路径,可以使用 glob 通配符
"src": [
"./index.js"
],
// 模块加载器配置文件路径
"coolie-config.js": "./coolie-config.js",
// 非模块化脚本存放位置
"dest": "./",
// chunk 模块列表
"chunk": []
},
// CSS 文件构建配置
"css": {
// CSS 文件的生成目录
"dest": "./"
},
// HTML 文件构建配置
"html": {
// HTML 文件的构建目录,可以使用 glob 通配符
"src": [
"./index.html"
],
// 是否压缩 HTML 文件
"minify": true
},
// 静态资源文件构建配置
"resource": {
// 静态资源的生成目录
"dest": "./",
// 是否压缩静态资源文件
"minify": true
},
// 构建结果目录
"dest": "../dest/",
// 需要复制到构建目录的文件或目录的列表,可以使用 glob 通配符
"copy": []
}
上文提到的 glob 通配符:
*
Matches 0 or more characters in a single path portion?
Matches 1 character[...]
Matches a range of characters, similar to a RegExp range. If the first character of the range is ! or ^ then it matches any character not in the range.!(pattern|pattern|pattern)
Matches anything that does not match any of the patterns provided.?(pattern|pattern|pattern)
Matches zero or one occurrence of the patterns provided.+(pattern|pattern|pattern)
Matches one or more occurrences of the patterns provided.*(a|b|c)
Matches zero or more occurrences of the patterns provided@(pattern|pat*|pat?erN)
Matches exactly one of the patterns provided**
If a "globstar" is alone in a path portion, then it matches zero or more directories and subdirectories searching for matches. It does not crawl symlinked directories.
更多:https://github.com/isaacs/node-glob
执行构建
配置文件生成之后,就可以执行构建了:
coolie build
此时,命令行会输出构建细节:
➜ test coolie build
╔═════════════════════════════════════════╗
║ coolie@0.21.6 ║
║ The front-end development builder. ║
╚═════════════════════════════════════════╝
1/5 => copy files
2/5 => build main
√ => /path/to/src/index.js
× => unchunk modules
3/5 => overwrite config
√ => base: "./"
√ => version: "{
"index.js": "0c0e55a404cb28a132fd79b5d1dec5b1"
}"
√ => callbacks: 0
√ => /path/to/dest/coolie-config.30b4c2b3e6b2e4ec52950f0f91f9f085.js
4/5 => build html css
√ => /path/to/dest/coolie.min.js
√ => /path/to/src/index.html
5/5 => generator relationship map
√ => /path/to/dest/relationship-map.json
build success => copy 1 file(s),
build 1 main file(s),
build 0 js file(s),
build 1 html file(s),
build 0 css file(s),
build 0 resource file(s),
past 138 ms
如上构建细节,会描述正在构建的资源和其他构建信息。此时的文件目录是这样的:
- src 开发目录
|-- index.js
|-- coolie.min.js
|-- coolie-config.js
|-- index.html
`-- coolie.json
- dest 生产目录
|-- coolie-config.30b4c2b3e6b2e4ec52950f0f91f9f085.js
|-- coolie.min.js
|-- index.0c0e55a404cb28a132fd79b5d1dec5b1.js
|-- index.html
`-- relationship-map.json #资源关系引用地图
我们打开index.html
,和预期一样,弹出了警告框:
构建结果
我们来分别看下各个文件
index.html
为了演示,已加了一些空白。
<!doctype html>
<meta charset="utf8">
<script src="/coolie.min.js"
data-config="./coolie-config.30b4c2b3e6b2e4ec52950f0f91f9f085.js"
data-main="index.js"></script>
<!--coolie@0.21.6-->
可以明显看到是:
- 文件经过了压缩,其他没有做修改。
- 配置文件也被修改了。
- 文件末尾添加了签名。
index.版本号.js
/*coolie@0.21.6*/
define("0",[],function(e,l,n){alert("Hello world!")});
可以明显看到:
- 文件经过了压缩。
- 文件内容也发生了变化。
coolie-config.版本号.js
/*coolie@0.21.6*/
coolie.config({base:"./",debug:!1,cache:!0,
version:{"index.js":"0c0e55a404cb28a132fd79b5d1dec5b1"}}).use();
可以明显看到:
- 文件经过了压缩。
- 配置文件增加了
debug
、cache
和version
3 个参数:debug
:是否在控制台输出调试信息,生产环境是不需要的。cache
:是否保留模块缓存,生产环境是需要的。version
:指定入口文件的版本信息,而index.js
的版本就是0c0e55a404cb28a132fd79b5d1dec5b1
,所以模块加载器加载的就是index.0c0e55a404cb28a132fd79b5d1dec5b1.js
文件。
relationship-map.json
{
// 被构建的 HTML 页面
"index.html": {
// 该页面引用的 CSS 文件
"css": [],
// 非模块化 JS 文件
"js": {},
// 该页面的入口 JS 模块
"main": "index.js",
// 该页面依赖的 JS 模块
"deps": []
}
}
此文件描述的时构建读取到的一些依赖信息,详细说明如上。
结语
从上,很明显的看到,开发环境和生产环境中代码的不同,并且做了版本管理。以小见大,在大的工程构建上面,达到的效果会更加可观。
</>