1下载

使用 coolie demo 命令下载本 demo。

  1. coolie demo 10

2公共模块

在介绍分块模块之前,来说些公共模块。当一个项目逐渐壮大的时候,势必会出现一些公共模块。如何分配和处理这些公共模块,需要全局考虑,是一个不小的利弊权衡。

如工程里共有 20 个入口模块, 5 个入口模块引用了同一个模块 a,10 个入口模块引用了同一个模块 b,15 个入口模块引用了同一个模块 c,20 个入口模块引用了同一个模块 d。

如何分配这 4 个公共模块呢?

  • 全部打包在一起,即每个入口模块都将 a、b、c、d 四个模块都合并进去。
  • a 模块不打包进来,即每个入口模块都将 b、c、d 三个模块都合并进去。
  • a、b 模块不打包进来,即每个入口模块都将 c、d 两个模块都合并进去。
  • a、b、c 模块不打包进来,即每个入口模块只将 d 模块都合并进去。
  • a、b、c、d 四个模块都不打包,即每个入口模块根据自身情况加载属于自己的模块,就丧失了公共模块的特征。

3分块策略

基于上述的 5 种要求,对应着 5 种分块策略:

3.1策略1

  1. chunk: [
  2. 'a|b|c|d' // a、b、c、d 合并作为一个公共模块,此时会被 5 个入口模块引用(以最小引用数量的 a 模块为准)
  3. ]

3.2策略2

  1. chunk: [
  2. 'b|c|d' // b、c、d 合并作为一个公共模块,此时会被 10 个入口模块引用(以最小引用数量的 b 模块为准)
  3. ]

3.3策略3

  1. chunk: [
  2. 'c|d' // c、d 合并作为一个公共模块,此时会被 15 个入口模块引用(以最小引用数量的 c 模块为准)
  3. ]

3.4策略4

  1. chunk: [
  2. 'd' // d 作为一个公共模块,此时会被 20 个入口模块引用
  3. ]

3.5策略5

  1. chunk: [
  2. // 空,没有公共模块
  3. ]

是不是只有这 5 种分块策略?当然不止:

3.6策略6

  1. chunk: [
  2. 'a', // a 作为一个公共模块,此时会被 5 个入口模块引用
  3. 'b|c|d' // b、c、d 合并作为一个公共模块,此时会被 10 个入口模块引用(以最小引用数量的 b 模块为准)
  4. ]

3.7策略7

  1. chunk: [
  2. 'a', // a 作为一个公共模块,此时会被 5 个入口模块引用
  3. 'b', // b 作为一个公共模块,此时会被 10 个入口模块引用
  4. 'c|d' // c、d 合并作为一个公共模块,此时会被 15 个入口模块引用(以最小引用数量的 c 模块为准)
  5. ]

3.8策略8

  1. chunk: [
  2. 'a', // a 作为一个公共模块,此时会被 5 个入口模块引用
  3. 'b', // b 作为一个公共模块,此时会被 10 个入口模块引用
  4. 'c', // c 作为一个公共模块,此时会被 15 个入口模块引用
  5. 'c', // d 作为一个公共模块,此时会被 20 个入口模块引用
  6. ]

3.9策略9

  1. chunk: [
  2. 'a|b', // a、b 合并作为一个公共模块,此时会被 5 个入口模块引用(以最小引用数量的 a 模块为准)
  3. 'c', // c 作为一个公共模块,此时会被 15 个入口模块引用
  4. 'c', // d 作为一个公共模块,此时会被 20 个入口模块引用
  5. ]

这种排列组合的问题,这里就不一一展示了。关于公共模块,都是需要站在工程角度全盘考虑,需要有全局眼光,轻重之间,取舍有道。

4demo

4.1初始化目录结构

新建一个coolie-demo10的目录,结构如下:

  1. .
  2. └── webroot-dev // 开发目录
  3. └── static // 静态目录
  4. └── js // js 目录
  5. ├── main // 入口模块目录
  6. └── libs // 脚本库模块
  7. 5 directories, 0 files

4.2初始化文件

本 demo 要的是,显示今天的年月日。分别在 libs 目录下新建

  • webroot-dev/static/js/libs/year.js
  • webroot-dev/static/js/libs/month.js
  • webroot-dev/static/js/libs/date.js
    三个 js 分别输出当前的年、月、日。

4.2.1year.js

  1. module.exports = function () {
  2. return new Date().getFullYear();
  3. };

4.2.2month.js

  1. module.exports = function () {
  2. return new Date().getMonth() + 1;
  3. };

4.2.3date.js

  1. module.exports = function () {
  2. return new Date().getDate();
  3. };

然后,在 main 目录下,新建两个 js ,分别属性今天的年、月和年、月、日。

  • webroot-dev/static/js/main/year-month.js
  • webroot-dev/static/js/main/year-month-date.js

4.2.4year-month.js

输出当前的年、月

  1. var year = require('../libs/year.js');
  2. var month = require('../libs/month.js');
  3. alert('today is ' + year() + '-' + month());

4.2.5year-month-date.js

输出当前的年、月、日

  1. var year = require('../libs/year.js');
  2. var month = require('../libs/month.js');
  3. var date = require('../libs/date.js');
  4. alert('today is ' + year() + '-' + month() + '-' + date());

从上面的代码结构和文件划分,可以明显的看出来,year.jsmonth.jsdate.js是可以作为公共模块来处理的。

4.2.6coolie.js

  • webroot-dev 目录下新建 package.json
  • webroot-dev 目录下下载模块加载器 npm install —save coolie.js

4.2.7coolie-config.js

在 js 目录下新建模块加载器配置文件:

  1. coolie init -j
  2. ┌────────────────────────────────────┐
  3. coolie-cli
  4. coolie@1.6.5
  5. The front-end development builder.
  6. └────────────────────────────────────┘
  7. init success >> /coolie-demo10/src/static/js/coolie-config.js

不需要修改配置文件。

返回 webroot-dev 目录,新建两个 html 分别执行两个入口模块:

  • webroot-dev/year-month.html
  • webroot-dev/year-month-date.html

4.2.8year-month.html

输出当前的年、月

  1. <!doctype html>
  2. <meta charset="utf-8">
  3. <script coolie src="/node_modules/coolie.js/coolie.js"
  4. data-config="/static/js/coolie-config.js"
  5. data-main="year-month.js"></script>`

4.2.9year-month-date.html

输出当前的年、月、日

  1. <!doctype html>
  2. <meta charset="utf-8">
  3. <script coolie src="/node_modules/coolie.js/coolie.js"
  4. data-config="/static/js/coolie-config.js"
  5. data-main="year-month-date.js"></script>

4.3前端构建前运行

src目录下,使用模块分块构建(demo10) - 图1sts执行:

  1. sts
  2. sts >> A static server is running.
  3. open >> http://172.22.255.75:58920

然后打开year-month.html

模块分块构建(demo10) - 图2

继续打开year-month-date.html

模块分块构建(demo10) - 图3

显然,执行是正确的。当然,此时是没有任何分块和公共模块的,需要怎样抽象公共模块,继续往下看。

4.4前端构建配置

在写配置之前,考虑下哪些模块可以作为公共模块。

从全局来看,date.js只被入口模块使用了一次,没必要作为公共模块,year.jsmonth.js的使用率是 100%,有必要作为公共模块。

那么,就将year.jsmonth.js合并一起作为公共模块。

在 webroot-dev 目录下,初始化配置文件:

  1. coolie init -c
  2. ┌────────────────────────────────────┐
  3. coolie-cli
  4. coolie@1.6.5
  5. The front-end development builder.
  6. └────────────────────────────────────┘
  7. init success >> /coolie-demo10/src/coolie.config.js

修改配置文件为:

  1. /**
  2. * ======================================================
  3. * coolie-cli 配置文件 `coolie.config.js`
  4. * 使用 `coolie init -c` 生成 `coolie.config.js` 文件模板
  5. * 当前配置文件所在的目录为构建的根目录
  6. *
  7. * @link http://coolie.ydr.me/guide/coolie.config.js/
  8. * @author ydr.me
  9. * @version 1.6.5
  10. * @create 2016-01-26 22:00:17
  11. * =======================================================
  12. */
  13. 'use strict';
  14. module.exports = function (coolie) {
  15. // coolie 配置
  16. coolie.config({
  17. // 是否在构建之前清空目标目录
  18. clean: true,
  19. // 目标配置
  20. dest: {
  21. // 目标目录,相对于当前文件
  22. dirname: '../webroot-pro/',
  23. // 目标根域
  24. host: '',
  25. // 版本号长度
  26. versionLength: 32
  27. },
  28. // js 构建
  29. js: {
  30. // 入口模块,相对于当前文件
  31. main: [
  32. // 支持 glob 语法
  33. './static/js/main/**/*.js'
  34. ],
  35. // coolie-config.js 路径,相对于当前文件
  36. 'coolie-config.js': './static/js/coolie-config.js',
  37. // js 文件保存目录,相对于 dest.dirname
  38. dest: './static/js/',
  39. // 分块配置
  40. chunk: [
  41. //【1】
  42. "static/js/libs/**.js"
  43. ]
  44. },
  45. // html 构建
  46. html: {
  47. // html 文件,相对于当前文件
  48. src: [
  49. // 支持 glob 语法
  50. //【2】
  51. '*.html'
  52. ],
  53. // 是否压缩
  54. minify: true
  55. },
  56. // css 构建
  57. css: {
  58. // css 文件保存目录,相对于 dest.dirname
  59. dest: './static/css/',
  60. // css 压缩配置
  61. minify: {
  62. compatibility: 'ie7'
  63. }
  64. },
  65. // 资源
  66. resource: {
  67. // 资源保存目录,相对于 dest.dirname
  68. dest: './static/res/',
  69. // 是否压缩
  70. minify: true
  71. },
  72. // 原样复制文件,相对于当前文件
  73. copy: [
  74. // 支持 glob 语法
  75. //【3】
  76. //'./favicon.ico',
  77. //'./robots.txt'
  78. ]
  79. });
  80. // 使用 coolie 中间件
  81. // coolie.use(require('coolie-*'));
  82. // 自定义 coolie 中间件
  83. //coolie.use(function (options) {
  84. // // do sth.
  85. // return options;
  86. //});
  87. };
  • 【1】:修改了 chunk 配置,配置数组里添加了一项,指定了 libs 下的模块可以作为公共模块,并交给构建工具自动管理
  • 【2】:修改了 html 配置,修改为*.html表示构建所有的 html 后缀文件
  • 【3】:去除了复制文件路径

4.5前端构建

在 webroot-dev 目录下,执行前端构建:

  1. coolie build
  2. ┌──────────────────────────────┐
  3. coolie@2.0.0
  4. 前端工程化构建工具
  5. 官网:https://coolie.ydr.me/ │
  6. └──────────────────────────────┘
  7. step 1/6 >> parse coolie-cli profile
  8. coolie config >> /coolie-demo10/webroot-dev/coolie.config.js
  9. src dirname >> /coolie-demo10/webroot-dev
  10. dest dirname >> /coolie-demo10/webroot-pro/
  11. step 2/6 >> copy files
  12. copy files >> no files are copied
  13. step 3/6 >> build main modules
  14. parse module >> 5 modules parsed
  15. build main >> will build 2 main modules
  16. 1/2 >> /static/js/main/year-month-date.js
  17. 2/2 >> /static/js/main/year-month.js
  18. step 4/6 >> generate coolie.js profile
  19. coolie-config.js >> mainModulesDir: "/static/js/main/"
  20. coolie-config.js >> asyncModulesDir: "../async/"
  21. coolie-config.js >> chunkModulesDir: "../chunk/"
  22. coolie-config.js >> callbacks: 0
  23. coolie-config.js >> ../webroot-pro/static/js/287a2adf0b6a17e0b667d11d009a4364.js
  24. step 5/6 >> build htmls
  25. 1/2 >> /year-month-date.html
  26. 2/2 >> /year-month.html
  27. step 6/6 >> generate coolie map
  28. coolie map >> ../webroot-pro/coolie-map.json
  29. build success >> elapsed 461ms, at 2016-05-29 21:36:41.392

从构建日志可以看出,确实多了一个 chunk 信息。先来看看构建之后的 webroot-pro 目录结构:

  1. webroot-pro
  2. ├── coolie-map.json
  3. ├── static
  4. └── js
  5. ├── 0996319be2c4f9517575b54dcc4af897.js
  6. ├── 287a2adf0b6a17e0b667d11d009a4364.js
  7. ├── chunk
  8. └── 0.d2f1d7c36aa7dd4588172993b6548c6d.js
  9. └── main
  10. ├── c3c0e8c986b8dcdcfc3405f65f5b83ec.js
  11. └── ff3cb2ca5aafd9ec63e6c2efe56dcf78.js
  12. ├── year-month-date.html
  13. └── year-month.html
  14. 4 directories, 8 files

从目录结构也很容易看到,确实多了一个 chunk 目录,里面有一个 chunk 模块。

4.6前端构建后运行

切换到 webroot-pro 目录,使用模块分块构建(demo10) - 图4sts执行:

  1. cd ../webroot-pro
  2. sts
  3. sts >> A static server is running.
  4. open >> http://192.168.0.185:60728

然后打开year-month.html

模块分块构建(demo10) - 图5

  • 【1】:加载了入口模块
  • 【2】:加载了分块模块
    继续打开year-month-date.html

模块分块构建(demo10) - 图6

  • 【1】:加载了入口模块
  • 【2】:加载了分块模块
    从两张图,可以明显的看出来【2】确实成为了公共模块。

4.7分析构建结果

4.7.1coolie-map

首先看下coolie-map.json深度解析点这里):

  1. {
  2. "/year-month-date.html": {
  3. "main": [
  4. {
  5. "src": "../webroot-dev/static/js/main/year-month-date.js",
  6. "dest": "/static/js/main/c3c0e8c986b8dcdcfc3405f65f5b83ec.js",
  7. "deps": [
  8. "../webroot-dev/static/js/libs/year.js",
  9. "../webroot-dev/static/js/libs/month.js",
  10. "../webroot-dev/static/js/libs/date.js"
  11. ]
  12. }
  13. ],
  14. "js": [
  15. {
  16. "dest": "/static/js/0996319be2c4f9517575b54dcc4af897.js",
  17. "deps": [
  18. "../webroot-dev/node_modules/coolie.js/coolie.js"
  19. ]
  20. }
  21. ],
  22. "css": [],
  23. "res": []
  24. },
  25. "/year-month.html": {
  26. "main": [
  27. {
  28. "src": "../webroot-dev/static/js/main/year-month.js",
  29. "dest": "/static/js/main/ff3cb2ca5aafd9ec63e6c2efe56dcf78.js",
  30. "deps": [
  31. "../webroot-dev/static/js/libs/year.js",
  32. "../webroot-dev/static/js/libs/month.js"
  33. ]
  34. }
  35. ],
  36. "js": [
  37. {
  38. "dest": "/static/js/0996319be2c4f9517575b54dcc4af897.js",
  39. "deps": [
  40. "../webroot-dev/node_modules/coolie.js/coolie.js"
  41. ]
  42. }
  43. ],
  44. "css": [],
  45. "res": []
  46. }
  47. }

从内容可以看出来各自页面引用的入口模块,以及他们的依赖关系。来分别看看构建之后的两个入口模块:

4.7.2year-month-date.js

c3c0e8c986b8dcdcfc3405f65f5b83ec.js:

  1. /*coolie built*/
  2. define("0",["1","2","3"],function(a,e,i){var n=a("1"),t=a("2"),d=a("3");alert("today is "+n()+"-"+t()+"-"+d())});
  3. define("3",[],function(e,n,t){t.exports=function(){return(new Date).getDate()}});
  4. coolie.chunk(["0"]);

这里最明显的变化就是在代码的最后一行添加了coolie.chunk,参数是一个数组,数组只有一项"0"。从字面可以理解,coolie 加载了 chunk 模块 ID 为 0 的 chunk 模块。

从代码上看,确实没有了year.jsmonth.js的痕迹,只有date.js的代码。

4.7.3year-month.js

ff3cb2ca5aafd9ec63e6c2efe56dcf78.js:

  1. /*coolie built*/
  2. define("0",["1","2"],function(a,e,i){var n=a("1"),t=a("2");alert("today is "+n()+"-"+t())});
  3. coolie.chunk(["0"]);

这里的代码就更简单了,只有一个入口模块,和一个coolie.chunkyear.jsmonth.js是公共模块,自然不在代码里。

4.7.4chunk0

最后来看看 chunk 模块吧:

0.d2f1d7c36aa7dd4588172993b6548c6d.js:

  1. /*coolie built*/
  2. define("1",[],function(e,n,t){t.exports=function(){return(new Date).getFullYear()}});
  3. define("2",[],function(n,e,t){t.exports=function(){return(new Date).getMonth()+1}});

chunk 模块是一个模块片段,包含了year.jsmonth.js的内容。

至此,完整的加载方式如下:

  1. year-month.html => chunk0
  2. => year + month
  3. => year + month
  4. year-month-date.html => date + chunk0
  5. => year + month
  6. => date + year + month

将 chunk 机制发挥到极致,就是一个网站全盘考虑的极致。

5github

模块分块构建(demo10) - 图7github.com

原文: https://coolie.ydr.me/guide/build-chunk-module