学习 kityminder 笔记(十二) 构建部分
2015-12-02 00:00
190 查看
有点不太一样的 grunt 任务.
1. clean --- 清理临时文件. 作为入门了解 grunt 任务.
在 Gruntfile.js 中, 有加载 clean 任务的部分:
grunt.loadNpmTasks('grunt-contrib-clean');
找到位于 node_modules 目录下的 grunt-contrib-clean 子目录 (通过 npm 安装的), 找到对应的 package.json,
打开查看, 可发现该模块也放在 github 上面: https://github.com/gruntjs/grunt-contrib-clean .
现在简单看一眼 tasks 目录下的 clean.js 文件. 里面的重点有:
grunt.registerMultiTask('clean', ..., function() {
... clean(filepath, options); // 调用实际清理函数.
});
再看看 grunt 模块下的各个文件(没时间细看, 简单翻了一下), 大致是读取 Gruntfile.js, package,json 提取信息,
然后调用各种 task 执行任务.
2. 重点是一个 dependence 任务:
任务的 npm 模块为 grunt-module-dependence, 到该子目录的 package.json 有
homepage = https://github.com/HanCong03/
该任务与其它任务不同的是, 它通过组装多个 js 文件为一个, 动态改变了程序的结构. 必须要了解最后生成的文件
结构, 才能理解前面使用 seajs 要求的规格 define(xxx) . 以我们的 hello.js 和一个子模块 foobar.js 为例:
如上所示, 重点在于改变了程序的结构, 模块被变成 _p
= {...} 形式, 对其它模块的引用变成 _p.r(n) 的形式.
其中函数 _p.r(n) 现在可以细看看, 因已知 n 是模块编号, 且可通过 _p
的方式访问到.
因此这里的 _p.r() 函数, 相当于取代了 seajs.require() 方法, 以将一组模块组装在一起成为单一的大的 js.
生成的大的 js 文件后面还有 use() 方法, 看似取代 seajs.use() 方法, 并初始加载所指定的主模块 'hello'.
这是在 options 中指定的 entrance 值.
所有这些变换无疑都是 dependence 模块运作的了, 一旦了解了原理, 当需要的时候我们就能够自己定义这些
过程, 进行自己所需的变换.
大致是这样了. 这样最后合并出的 kity.js 就不需要 seajs 的支持了, 而且代码也很少, 这一点还是值得赞的.
不过程序的变换也许可以更好一些, 例如, define, require 函数也许不需要变换, 直接提供一个简单的?
3. 任务 concat
给步骤 2 生成的 js 外面再包一个闭包, 即提供一个 banner, 提供一个 footer. 比较简单就不用细说了.
4. 任务 uglify
压缩 js 为最小化. 理解即可, 实在需要再去看怎么实现, 但估计是用 flex 做代码分析, 压缩空格, 去掉注释, 命名改短
等, 现在还不想看, 了解作用即可.
1. clean --- 清理临时文件. 作为入门了解 grunt 任务.
在 Gruntfile.js 中, 有加载 clean 任务的部分:
grunt.loadNpmTasks('grunt-contrib-clean');
找到位于 node_modules 目录下的 grunt-contrib-clean 子目录 (通过 npm 安装的), 找到对应的 package.json,
打开查看, 可发现该模块也放在 github 上面: https://github.com/gruntjs/grunt-contrib-clean .
现在简单看一眼 tasks 目录下的 clean.js 文件. 里面的重点有:
grunt.registerMultiTask('clean', ..., function() {
... clean(filepath, options); // 调用实际清理函数.
});
再看看 grunt 模块下的各个文件(没时间细看, 简单翻了一下), 大致是读取 Gruntfile.js, package,json 提取信息,
然后调用各种 task 执行任务.
2. 重点是一个 dependence 任务:
任务的 npm 模块为 grunt-module-dependence, 到该子目录的 package.json 有
homepage = https://github.com/HanCong03/
该任务与其它任务不同的是, 它通过组装多个 js 文件为一个, 动态改变了程序的结构. 必须要了解最后生成的文件
结构, 才能理解前面使用 seajs 要求的规格 define(xxx) . 以我们的 hello.js 和一个子模块 foobar.js 为例:
var _p = { // 这是 dependence 模块生成的一个对象. r: function() ... // 稍后细看, 估计类似于 require() 函数. }; // src/foobar.js 被编号为 0, 估计按照顺序. _p[0] = { // 这个函数 value 即是 foobar.js 中用 define() 定义的工厂函数. value: function(require, exports, module) { ... } }; // src/hello.js 编号为 1. _p[1] = { // 同样是工厂函数. value: function(...) { // 重点在这里, 原来写的 require('foobar') 被代换为调用 _p.r() 函数以索引 0. var foobar = _p.r(0); ... 其它部分 ... } }; // 后面其它部分稍后需要再看.
如上所示, 重点在于改变了程序的结构, 模块被变成 _p
= {...} 形式, 对其它模块的引用变成 _p.r(n) 的形式.
其中函数 _p.r(n) 现在可以细看看, 因已知 n 是模块编号, 且可通过 _p
的方式访问到.
_p.r = function(index) { var mod = _p[index]; // 用一个 mod 名字表明这是一个模块, 原程序不是这样. // 如果此模块已经初始化过, 则直接返回其 value. if (mod.inited) return mod.value; // 调用工厂方法(如果是的话)进行初始化. if (mod.value is function) { mod.inited = true; // 先设置值以 防止递归? mod.value.call(......); // 调用该工厂方法. 可能导致递归调用 _p.r() // 处理返回的 exports 略 } else { // 可能只是定义了一些数据, 而不是工厂方法 mod.inited = true; return mod.value; } }
因此这里的 _p.r() 函数, 相当于取代了 seajs.require() 方法, 以将一组模块组装在一起成为单一的大的 js.
生成的大的 js 文件后面还有 use() 方法, 看似取代 seajs.use() 方法, 并初始加载所指定的主模块 'hello'.
这是在 options 中指定的 entrance 值.
所有这些变换无疑都是 dependence 模块运作的了, 一旦了解了原理, 当需要的时候我们就能够自己定义这些
过程, 进行自己所需的变换.
// dependence.js 部分代码摘读. module.exports = function(grunt) { // 注册为一种 grunt 任务. 这里有一个自吹自擂我们就略过吧... grunt.registerMultiTask('dependence', 'The best Grunt plugin ever.' function() { // 其它略... 这里遍历要合并的 src 文件. src_files.forEach(function() { source = read(src); // 读入源文件. // 对代码进行变换(transform) 然后放入模块列表中. all_source[module_index++] = transform(source); // 合并后的源码再处理处理. removeRequire(...); join() ... wrap() ... format()... -> 写入目标文件 }); }); // 看注释了解即可, 详细代码略. // 对 module 执行转换, 更改其定义方式, 使其可以脱离 define 方法. function transform(...) { // 用正则表达式找 define... , 修改|替换某些东西... } // 删除 require 依赖. function removeRequire(...) { // 用正则表达式替换 require(...) 为 _p.r() } // 其它 format(格式化源码), wrap(包裹最终的源码) 等辅助函数略.
大致是这样了. 这样最后合并出的 kity.js 就不需要 seajs 的支持了, 而且代码也很少, 这一点还是值得赞的.
不过程序的变换也许可以更好一些, 例如, define, require 函数也许不需要变换, 直接提供一个简单的?
3. 任务 concat
给步骤 2 生成的 js 外面再包一个闭包, 即提供一个 banner, 提供一个 footer. 比较简单就不用细说了.
4. 任务 uglify
压缩 js 为最小化. 理解即可, 实在需要再去看怎么实现, 但估计是用 flex 做代码分析, 压缩空格, 去掉注释, 命名改短
等, 现在还不想看, 了解作用即可.
相关文章推荐
- 思科ASA防火墙之NAT
- 利用__define_setter__和 __define_getter__ 定义动态的对象属性
- centos7 安装samba
- 用版本控制系统来管理android studio项目时 配置忽略文件
- python调用wifi
- python 多参数处理
- android-通过StatFs获取文件系统的空间信息
- Java final 关键字
- 如何xcode6中创建pch文件
- 什么是反向链接?
- 监控linux的脚本
- angular之DI理解
- angular之cloak
- 关于如何在javascript中实现DI
- 舍入
- Java配置环境变量
- Spring Quartz与Spring Task总结
- js的异步调用
- 如何手动用Eclipse默认的keystore导出安卓应用
- hadoop的eclipse安装