YUI 的模块信息配置优先级关系梳理
背景
YUI的配置参数较多, 可以在好几个地方配置一个module的相关信息, 如:
//在全局配置, 所以YUI实例共享 YUI_config = { modules: { 'w-autcomplete': { requires: ['module1'], path: 'test1.js', } }, groups: { modules: { 'w-autocomplete': { requires: ['module2'], path: 'test2.js' } } } } //在某一个YUI实例中配置 YUI({ groups: { fecore: { modules: { 'w-autocomplete': { base: 'http://fe.com?f=fecore/test3', type: 'js', requires: ['module3'], } } } }, modules: { 'w-autocomplete': { base: 'http://fe.com?f=fecore/', path: 'w-autocomplete/w-autocomplete.js', type: 'js', } } }).use('w-autocomplete', function(Y) { console.log(Y); }); //在模块文件中申明配置: w-autocomplete.js M.add('w-autocomplete', function(Y) { ... }, '1.0.0', { requires: ['module4'] } );
这三类情况, YUI在加载的时候到底如何来判断, 使用哪一个module的配置信息呢?
配置优先级关系
一个YUI实例config
配置优先级关系从高到底依次为:
-
YUI(args) 里面的 args, args可以是数组, 数组依次执行 applyConfig(arg[i]);
-
YUI_config
-
YUI.GlobalConfig
YUI初始化的时候会将这些参数按如上所述的优先级进行config初始化。 所以当使用YUI(args).use 的方式来使用模块时, args会自动覆盖当前实例Y的modules 配置信息。
当我们需要给所有YUI实例添加配置参数的时候, 可以直接通过配置 YUI_config
或者 YUI.GlobalConfig
来实现。 也可以在YUI或者YUI实例初始化后,进行动态配置,如:
Y.applyConfig({groups: {}, modules: {} }); YUI.applyConfig({groups: {}, modules: {} });
处理同一优先级的配置
对同一优先级的配置使用applyConfig的时候, 由于是Map操作,所以并不能保证config里面的groups & modules的覆盖顺序, 测试了一下for in操作在各个浏览器下的表现, 证明对于key都是字符串的情况,在不同浏览器中执行顺序和书写的顺序有关系。
所以当groups.modules和modules里面都定义了相同module时, 谁定义在后面就以谁的定义为准 。
YUI().add定义的模块信息
YUI().add('w-autocomplete', function(Y) {}, 1.0.0, { requires: ['module1', 'module2'], use: ['module3', 'module4'] }),
在执行add操作时, YUI.Env.mods里面会新增如下对象:
{ detail: { requires: ['module1', 'module2'] use: ['module3', 'module4'] }, version: 1.0.0, name: 'w-autocomplate', fn: fn }
module加载完毕后, 在执行回调之前, 会先检查加载的依赖链中的missing module, missing module包括module定义中的 requires和use。 得到missing列表后,再用Y.use函数进行reload。
var missing = []; var mods = YUI.Env.mods; var process = function(names, skip) { var i = 0, a = [], name, len, m, req, use; len = names.length; for (i = 0; i < len; i++) { name = names[i]; m = mods[name]; req = null; use = null; if (m) { used[name] = true; req = m.details.requires; use = m.details.use; } else { if (!G_ENV._loaded[VERSION][name]) { missing.push(name); } else { used[name] = true; // probably css } } // make sure requirements are attached if (req && req.length) { process(req); } // make sure we grab the submodule dependencies too if (use && use.length) { process(use, 1); } } }; process(modules); redo = missing.length; if (redo) { Y._use(missing, function() { if (Y._attach(data)) { Y._notify(callback, response, data) } }); }
so, requires 和 use的定义会影响到loader的加载。而和在前面两种方式配置模块的requires和use 主要区别是, 前两种配置依赖的module会在当前模块加载之前加载, 而后面这种方式会在当前模块加载完成后再进行加载。
但是如果在module里面定义的其他信息,如condition等,loader会忽略不管。
总结
如果每个级别的优先级都配置了mod信息, 会按优先级关系逐级覆盖, module信息以最高优先级的配置为准。
如果同级优先级配置里面 modules 和 groups.modules里面有相同的module配置,取决于for in 遍历的顺序。 测试各浏览器结果会按照定义顺序, 后定义的module信息优先级更高。