原文地址:http://www.tuicool.com/articles/7JBnmyjavascript
接触过requirejs的童鞋可能都知道,不管是经过define来定义模块,仍是经过require来加载模块,模块依赖声明都是很重要的一步。而其中涉及到的模块路径解析,对于新手来讲,有的时候会让人以为很困惑。css
假设咱们的目录结构以下:html
demo.html
js/main.js
js/lib.js
js/util.js
js/common/lib.js
js/common/jqury/lib.js
common/lib.jsjava
下面的这两个例子,看着很简单吧,但应该大部分的人跟我同样没办法一眼就识别出来依赖模块最终转化成的路径。缘由在于,这里压根就没有提供足够的上下文信息。。。(= =b 别打我)jquery
require例子:sql
// main.js require(['./util'], function(){ // do sth });
define例子:ruby
define(['./util'], function(){ // do sth });
下面,咱们再一步步经过具体的例子来看下,requirejs在不一样的场景下,是如何解析模块路径的。app
baseUrl
:基础中的基础在requirejs的模块路径解析里, baseUrl
是很是基础的概念,离开了它,基本就玩不转了,因此这里简单介绍一下。简单的说, baseUrl
指定了一个目录,而后requirejs基于这个目录来寻找依赖的模块。requirejs
举个栗子,在demo.html里加载requirejs,同时在requirejs所在的script上声明data-main
属性,那么,requirejs加载下来后,它会作两件事件:ui
<script src="js/require.js" data-main="js/main.js"></script>
那么,下面依赖的lib模块的实际路径为 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>
main.js
requirejs.config({
baseUrl: 'js' }); require(['lib'], function(Lib){ // do sth });
baseUrl
+ 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
这个配置项。咱们看下修改后的代码。
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
就能够了。
requirejs.config({ baseUrl: 'js', paths: { fruits: 'common/third-party/fruits' } });
paths
:简单但须要记住的要点上一节已经举例说明了path的例子。这里再来个例子,说明下下三种状况下,匹配路径的规则
>
apple
:没有在paths规则里定义,因而为 baseUrl + apple.js => js/apple.jscommon/fruits
:common已经在paths里定义,因而为baseUrl + common/fruits + apple.js => js/common/fruits/apple.js../common/apple
:common尽管已经在paths里定义,可是../common/apple
并非以common开头,因而为 baseUrl + ../common/apple.js => common/apple.jsrequirejs.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的路径。
js/main.js
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'); });
js/lib.js
// 依赖util模块 define(['./util'], function(Util){ return { say: function(msg){ Util.say(msg); } }; });
demo2实际上会有特例,好比下面,lib模块依赖的util模块,最终解析出来的路径是js/util.js
main.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
main.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
所在的路径解析呢?其实很简单,做者也不知道你这段代码出如今哪一个文件呀亲。因此,只能经过baseUrl
js/main.js
require(['./lib', function(Lib){ // do sth }]);
加个@todo,这个估计只有做者和看过源码的人知道了,好像文档里也没明确说到~todo下先
// @todo
啰啰嗦嗦写了一大堆,requirejs中的路径解析总体上不复杂,但 ./module
这种形式的路径解析,对于刚接触requirejs的人来讲稍微有些费解。也许,当你从requirejs设计者的角度来看,问题可能相对好理解一些