接触过requirejs的童鞋可能都知道,无论是通过define来定义模块,还是通过require来加载模块,模块依赖声明都是很重要的一步。而其中涉及到的模块路径解析,对于新手来说,有的时候会让人觉得很困惑。
假设我们的目录结构如下:
demo.htmljs/main.jsjs/lib.jsjs/util.jsjs/common/lib.jsjs/common/jqury/lib.jscommon/lib.js
下面的这两个例子,看着很简单吧,但应该大部分的人跟我一样没办法一眼就识别出来依赖模块最终转化成的路径。原因在于,这里压根就没有提供足够的上下文信息。。。(= =b 别打我)
require例子:
// main.js require([‘./util‘], function(){ // do sth });
define例子:
define([‘./util‘], function(){ // do sth });
下面,我们再一步步通过具体的例子来看下,requirejs在不同的场景下,是如何解析模块路径的。
baseUrl
在requirejs的模块路径解析里,baseUrl是非常基础的概念,离开了它,基本就玩不转了,所以这里简单介绍一下。简单的说,baseUrl指定了一个目录,然后requirejs基于这个目录来寻找依赖的模块。
举个栗子,在demo.html里加载requirejs,同时在requirejs所在的script上声明data-main属性,那么,requirejs加载下来后,它会做两件事件:
data-main
<script src="js/require.js" data-main="js/main.js"></script>
那么,下面依赖的lib模块的实际路径为 js/lib.js
js/lib.js
main.js
require([‘lib‘], function(Lib){ // do sth });
当然,除了data-main属性,你也可以手动配置baseUrl,比如下面例子。需要强调的是:
如果没有通过data-main属性指定baseUrl,也没有通过config的方式显示声明baseUrl,那么baseUrl默认为加载requirejs的那个页面所在的路径
demo.html
<script src="js/require.js"></script> <script src="js/main.js"></script>
requirejs.config({ baseUrl: ‘js‘ }); require([‘lib‘], function(Lib){ // do sth });
path
比如我们加载了下面一堆模块(好多水果。。。),看着下面一长串的依赖列表,可能你一下子就看出问题来了:
common/fruits
requirejs.config({ baseUrl: ‘js‘ }); // 加载一堆水果 require([‘common/fruits/apple‘, ‘common/fruits/orange‘, ‘common/fruits/grape‘, ‘common/fruits/pears‘], function(Apple, Orange, Grape, Pears){ // do sth });
对一个模块加载器来说,上面说的这两点问题显然需要考虑进去。于是requirejs的作者提供了paths这个配置项。我们看下修改后的代码。
paths
requirejs.config({ baseUrl: ‘js‘, paths: { fruits: ‘common/fruits‘ } }); // 加载一堆水果 require([‘fruits/apple‘, ‘fruits/orange‘, ‘fruits/grape‘, ‘fruits/pears‘], function(Apple, Orange, Grape, Pears){ // do sth });
其实就少了个common前缀,也没节省多少代码,但当项目结构变更时,好处就体现了。假设common/fruits某一天突然变成了common/third-party/fruits,那很简单,改下paths就可以了。
common
common/third-party/fruits
requirejs.config({ baseUrl: ‘js‘, paths: { fruits: ‘common/third-party/fruits‘ } });
上一节已经举例说明了path的例子。这里再来个例子,说明下下三种情况下,匹配路径的规则>
apple
../common/apple
requirejs.config({ baseUrl: ‘js‘, paths: { common: ‘common/fruits‘ } }); // 从左到右,加载的路径依次为 js/lib.js、 js/common/jquery/lib.js、common/lib.js require([‘apple‘, ‘common/apple‘, ‘../common/apple‘], function(){ // do something });
./module
应该说,这个是最让人疑惑的地方。
js/main.js
requirejs.config({ baseUrl: ‘js/common‘ }); // 实际加载的路径都是是 /lib.js require([‘./lib‘, ‘lib‘], function(Lib){ Lib.say(‘hello‘); });
简单改下上面的例子,可以看到:
通过define定义模块A时,模块A依赖的模块B,如果是./module形式,则基于模块A所在目录解析模块B的路径。
define
requirejs.config({ baseUrl: ‘js‘ }); // 依赖lib.js,实际加载的路径是 js/common/lib.js,而lib模块又依赖于util模块(‘./util‘),解析后的实际路径为 js/common/util.js require([‘common/lib‘], function(Lib){ Lib.say(‘hello‘); });
// 依赖util模块 define([‘./util‘], function(Util){ return { say: function(msg){ Util.say(msg); } }; });
demo2实际上会有特例,比如下面,lib模块依赖的util模块,最终解析出来的路径是js/util.js
js/util.js
requirejs.config({ baseUrl: ‘js‘, paths: { lib: ‘common/lib‘ } }); // 实际加载的路径是 js/common/lib.js require([‘lib‘], function(Lib){ Lib.say(‘hello‘); });
lib.js
// util模块解析后的路径为 js/util.js define([‘./util‘], function(Lib){ return { say: function(msg){ Lib.say(msg); } }; });
上面讲到通过paths指定的模块路径加载模块时,./module路径解析就会按照baseUrl + moduleName的方式,但稍微修改下main.js,发现结果就不一样了。此时,util模块对应的路径为js/common/util.js
moduleName
js/common/util.js
requirejs.config({ baseUrl: ‘js‘, paths: { common: ‘common‘ } }); // 实际加载的路径是 js/common/lib.js require([‘common/lib‘], function(Lib){ Lib.say(‘hello‘); });
util.js
define([‘./util‘], function(Lib){ return { say: function(msg){ Lib.say(msg); } }; });
如下面例子所示,我们可能会疑惑,为什么不是相对于main.js所在的路径解析呢?其实很简单,作者也不知道你这段代码出现在哪个文件呀亲。所以,只能通过baseUrljs/main.js
require([‘./lib‘, function(Lib){ // do sth }]);
加个@todo,这个估计只有作者和看过源码的人知道了,好像文档里也没明确说到~todo下先
// @todo
啰啰嗦嗦写了一大堆,requirejs中的路径解析整体上不复杂,但./module这种形式的路径解析,对于刚接触requirejs的人来说稍微有些费解。也许,当你从requirejs设计者的角度来看,问题可能相对好理解一些。
requirejs:让人迷惑的路径解析,布布扣,bubuko.com
requirejs:让人迷惑的路径解析
原文:http://www.cnblogs.com/chyingp/p/requirejs-path-resolve.html