最近在使用seajs
进行开发时,碰到了一个百思不得其解的问题,在测试环境中,我的config是这样配置的:
seajs.config = {
'base' : 'http://static.dajieimg.com',
'alias' : {
'modA' : 'path/modeA.js'
}
};
在使用时,这样调用:
seajs.use('modA',function (modA) {
// 这里是可以执行的
});
但是在上线的时候,碰到了一个问题。
我司的上线流程是有一个打版本号
的过程的,所以呢,到线上的时候,config的配置变成了这样:
seajs.config = {
'base' : 'http://static.dajieimg.com',
'alias' : {
'modA' : 'path/modeA.01.js'
}
}; 这样的一个形式,这个时候,再使用上面的调用方式,就出现了神奇的事情:
seajs.use('modA',function (modA) {
// 这里报错
// console.log(modA)竟然是undefined
});
这是为什么呢?在测试的时候明明是好的啊?
这个问题其实仔细一想,大概就能知道问题出在了哪儿。因为合并js时用的是grunt-cmd-transport
这个task中间件,根据CMD
的规范规定,每个模块都会根据其所在的目录位置,生成其唯一的id,就比如这个modA
模块,合并完了之后,其实其真实地id应该是path/modA
,在使用seajs.use
的时候,实际上是根据这个模块的id去seajs的cache里找对应的方法,所以,上面那种use
方法出错是理所当然的。
但是呢,最让人困惑的不是这个,是为什么在不加版本号的时候,就是可以正确获取到模块的,为什么加了版本号之后就不行了呢?
带着这个问题,我大概看了一下seajs的源码,所幸源码写的非常易读,很快就找到了点。
在解析模块的时候,seajs会调用内部的一个id2Uri
这个方法,故名思议,就是将id转行成uri,然后去获取模块。在这个方法中,又调用了一个normalize
方法,这个方法会将id后加上.js
,期望获得真正的文件路径。
在seajs内部,有个cachedMods
对象用于存放已经加载过的模块,key是文件的路径,对应的就是模块的Module对象。这里的文件路径,取得是在alias中配置的文件路径,所以,在不带版本号的时候,id2Uri
返回的uri和alias
中配置的uri是相同的,所以不会出问题,但是,一旦有了版本号之后,实际路径,也就是cachedMods
中作为key的路径,也是带有版本号的了,就跟id2Uri
解析出来的不同,所以自然也就会出现差错了。
ps:后记
出现这种问题其实绝大多数的情况下还是自己对CMD
规范理解不到位,外加比较赖o(╯□╰)o。
所以呢,其实seajs这种比较高容错
的机制有时候反而会带来一些让人捉摸不透的问题,宽容
和严格
这两种方式,有些时候还真没法说哪种更好一些。
所以呢,还是等我想明白了再来继续说这个吧。