最近半个月,将seajs构建方式从spm-build改为grunt + grunt-cmd-xxx,踩坑无数,今天终于基本大功告成,在此总结一下:
首先,这个帖子写得不错,介绍了为什么seajs构建这么麻烦:为什么seajs构建这么麻烦
其实最关键的一个问题,就是用grunt-cmd-transport来提取依赖的时候,会将间接依赖也写入deps[],于是会造成大量无效的http请求(404),关键的参数有2个,一个是transport task的paths参数,第二个是concat task的include参数
paths:表示transport时,到哪里找依赖的模块,如果找到就写入deps[]。如果没有找到则报错,但是可以用--force参数强制继续,不会写入deps[]
include:表示concat时,合并哪些文件。有3个可选值,self,relative(默认),all
self基本是没用的;relative只会合并相对标识的依赖;all会合并所有依赖:标准构建
require("./menu");// 设置include:relative时会合并 require("uiframework/static/package");// 设置include:all时会合并
源码目录结构大致是这样的:
在src下有N个模块,每个模块都有很多.js,规定以package.js作为此模块的出口。如果外部模块需要依赖该模块,就用:
require("xxx/static/package");
将transport的paths配置为src,concat的include配置为relative
合并后得到的package.js文件类似这样:
可以看到,deps[]数组里把间接依赖也全部写进来了,正常应该只有uiframework/static/package。像红框里的这些文件,在合并后已经不存在了(开发阶段才有),但是seajs还是会发起无效的HTTP请求
为了解决这个问题,把concat的include配置为all
这样会把这些文件也全部合并进来,倒是不会再发起无效的http请求了,但是这样有2个问题
1,合并后的package.js文件超大,而且大量重复。因为每个模块都有package.js(模块出口),其中有大量重复的内容
2,每个模块都有menu.js,代码中是:
require("./menu");
观察用spm build合并出来的文件:
可以看到deps[]是正确的,只依赖每个外部模块的出口(当然还有模块内部的所有js),这样就很完美,不会发起无效的HTTP请求,而且也不需要合并多余的文件进来
spm-build内部使用的也是grunt-cmd-transport和grunt-cmd-concat,所以没道理spm-build能构建成功,自己写grunt就不行。一怒之下看了spm-build的源码,发现它配置的include也是relative,而paths配置是错的
这里配置的paths我的目录结构里根本就没有,所以等于是没有配置paths参数,于是在我的Gruntfile里也把paths去掉,运行grunt报错,使用--force强制继续,最后就得到了跟spm-build一模一样的构建结果。区别是spm-build要求是标准目录结构,而且需要到每个模块下执行一遍;用grunt则可以自定义目录结构,而且可以一键构建
1、paths不要配置,用--force强制执行
2、include配置为relative
3、开发中规定每个模块只有一个出口,这样
require("module_name/static/package");这行代码,无论在开发态还是部署态都是OK的,算是取了个巧
4、开发态和部署态的相对目录结构要保持一致,这是为了满足seajs的约定(模块ID即路径)