最近连续折腾了将近一个星期的seajs构建。。踩了不少坑,总结了一些经验,在这里贴一下
用seajs做模块化开发,经常用到这个函数:
require("module/path/file");
require("./file");
这个参数有2个意思,首先是代表路径,根据这个路径要能够找到模块所在的文件,否则直接返回了404,什么也别谈了。其次,还代表模块的ID,如果根据路径找到了模块文件,但是模块的ID(也就是define()的第一个参数)不匹配,模块也无法加载成功,这称为路径与ID的一致性
总之就是2个约束:路径要能访问到文件,而且路径和模块ID要一致。这并不是CommonJS规范的要求,这只是seajs自己的规定
这个规定看起来有点怪,比如node.js里就没有这个奇怪的约束,只要能根据路径找到相应的文件就行了。但是这是前端开发的特殊性决定的
server端的js,没有合并的需求。但是前端的js在发布时一般都需要合并,以减少http请求数。所以开发的时候,可能根据业务逻辑,把模块划分得很清楚:
user.js
employee.js
......
但是在部署的时候,会合并压缩成只有一个文件:total.js
所以这就带来一个问题,require()的参数要如何写?
在开发的时候:
require("user");// 可以找到user.js require("total");// 此时还不存在total.js,因为还没有合并
require("user");// 此时已经不存在 require("total");// 可以找到total.js
不过这里有一个建议:每个模块都只对外暴露唯一的接口,并且就将这个接口的文件名,作为合并后的文件名。这是一个取巧的方法,可以解决合并前后文件名不一致的问题
define(function(require, exports){ exports.add = function(){ // code here... }; });
// package.js define(function(require, exports){ exports.a = require("./a"); });
// outter define(function(require){ var a = require("package").a; });
require("package");
理论上可以自己构建seajs项目,但是实际上没有人这么做,因为太复杂。seajs的作者也强烈建议用户使用官方配套的构建工具来构建项目
构建工具有2种,分别是spm-build和grunt-cmd-xxx
spm-build是spm的附属项目。spm是seajs的包管理工具,可以理解成前端的npm。spm不在本文的讨论范围内,就不多说了
spm-build要求模块目录下有package.json文件,其中用<spm>属性声明要如何构建,然后执行spm-build就一条龙构建完了,包括文件的uglify。方便倒挺方便,不过可配置性比较弱,而且如果用了angular的话,spm-build在uglify的时候,会把不该替换的变量名也替换了,还是需要人工干预一下
总的来说,如果想省事的话,用spm-build也就可以了。但是如果项目有一些特殊的需求,spm-build可能就满足不了。另外spm-build不再是官方推荐的构建方式,后续的发展还不清楚
其实只有2个grunt插件,分别是grunt-cmd-transport和grunt-cmd-concat,分别完成提取依赖和合并的工作,后续的uglify还是用grunt-contrib-uglify来做的
这种构建方法其实就把构建的流程打散,只提供2个Task插件,用户自己控制构建过程,所以比较灵活。这也是官方推荐的构建方式。不过说实话,还比较复杂。构建过程可以看我的另外几篇帖子
下面是一个关键的:截至到目前,grunt-cmd-transport有一个BUG,提取后的js,会把间接依赖也写入deps数组,所以浏览器会发起很多无效的http请求。这个BUG目前还没有解决,但是用spm-build不会遇到这个问题。所以一定要慎重,详情在:grunt-cmd-transport的BUG