seajs使用补遗

- 1 min

最近在使用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这种比较高容错的机制有时候反而会带来一些让人捉摸不透的问题,宽容严格这两种方式,有些时候还真没法说哪种更好一些。

所以呢,还是等我想明白了再来继续说这个吧。

rss facebook twitter github youtube mail spotify lastfm instagram linkedin google google-plus pinterest medium vimeo stackoverflow reddit quora