requirejs:模块加载(require)及定义(define)时的路径小结
原文地址:http://www.tuicool.com/articles/7JBnmy
接触过requirejs的童鞋可能都知道,无论是通过define来定义模块,还是通过require来加载模块,模块依赖声明都是很重要的一步。而其中涉及到的模块路径解析,对于新手来说,有的时候会让人觉得很困惑。
假设我们的目录结构如下:
demo.html
js/main.js
js/lib.js
js/util.js
js/common/lib.js
js/common/jqury/lib.js
common/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加载下来后,它会做两件事件:
- 加载js/main.js
- 将baseUrl设置为data-main指定的文件所在的路径,这里是 js/
<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.js
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 :让人疑惑的相对路径
应该说,这个是最让人疑惑的地方。
demo 1
js/main.js
requirejs.config({
baseUrl: 'js/common'
});
// 实际加载的路径都是是 /lib.js
require(['./lib', 'lib'], function(Lib){
Lib.say('hello');
});
demo 2
简单改下上面的例子,可以看到:
通过 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);
}
};
});
demo 3
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);
}
};
});
demo 4
上面讲到通过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);
}
};
});
各种疑问
为什么require(['./module'], callback)不是相对于当前路径解析
如下面例子所示,我们可能会疑惑,为什么不是相对于 main.js 所在的路径解析呢?其实很简单,作者也不知道你这段代码出现在哪个文件呀亲。所以,只能通过baseUrl
js/main.js
require(['./lib', function(Lib){
// do sth
}]);
define(['./module'], callback)什么时候是相对当前路径
加个@todo,这个估计只有作者和看过源码的人知道了,好像文档里也没明确说到~todo下先
// @todo
写在后面
啰啰嗦嗦写了一大堆,requirejs中的路径解析整体上不复杂,但 ./module 这种形式的路径解析,对于刚接触requirejs的人来说稍微有些费解。也许,当你从requirejs设计者的角度来看,问题可能相对好理解一些
requirejs:模块加载(require)及定义(define)时的路径小结的更多相关文章
- requirejs:模块加载(require)及定义(define)时的路径理解
给新来的实习生普及下JS基本知识,看到比较好的文章 转载https://blog.csdn.net/xuxiaoping1989/article/details/52384778 接触过require ...
- 模块加载(require)及定义(define)时的路径
最近新公司在用requireJS进行JS的整合,刚开始接触有点蒙,于是深入了解了一下.requireJS主要是为了解决一下两个问题: (1)实现js文件的异步加载,避免网页失去响应: (2)管理模块之 ...
- lua的模块加载require
加载指定的模块.首先函数会在 package.loaded 这个表中查看是否已经加载 了 modname 这个模块.如果是,那么 require 会返回保存在 package.loaded[modna ...
- javascript 异步模块加载 简易实现
在javascript是没有类似java或其他语言的模块概念的,因此也不可能通过import或using等关键字来引用模块,这样造成了复杂项目中前端代码混乱,变量互相影响等. 因此在复杂项目中引入AM ...
- requirejs的加载原理 - 场景1. 定义一个require依赖a模块
我们学习一个新的技术,熟练的使用之后,就应该去探索它的原理.这篇文章我们来探索下requirejs的原理. 从4个场景来探索requirejs的原理 场景1. 定义一个require依赖b模块 场景2 ...
- 实现一个类 RequireJS 的模块加载器 (二)
2017 新年好 ! 新年第一天对我来说真是悲伤 ,早上兴冲冲地爬起来背着书包跑去实验室,结果今天大家都休息 .回宿舍的时候发现书包湿了,原来盒子装的牛奶盖子松了,泼了一书包,电脑风扇口和USB口都进 ...
- 使用RequireJS并实现一个自己的模块加载器 (一)
RequireJS & SeaJS 在 模块化开发 开发以前,都是直接在页面上引入 script 标签来引用脚本的,当项目变得比较复杂,就会带来很多问题. JS项目中的依赖只有通过引入JS的顺 ...
- 第三章:模块加载系统(requirejs)
任何一门语言在大规模应用阶段,必然要经历拆分模块的过程.便于维护与团队协作,与java走的最近的dojo率先引入加载器,早期的加载器都是同步的,使用document.write与同步Ajax请求实现. ...
- 使用RequireJS并实现一个自己的模块加载器 (二)
2017 新年好 ! 新年第一天对我来说真是悲伤 ,早上兴冲冲地爬起来背着书包跑去实验室,结果今天大家都休息 .回宿舍的时候发现书包湿了,原来盒子装的牛奶盖子松了,泼了一书包,电脑风扇口和USB口都进 ...
随机推荐
- Eclipse DDT
http://www.eclipse.org/downloads/ https://github.com/DDT-IDE/DDT/blob/latest/documentation/UserGuide ...
- C语言基础(8)-const,volatile,register关键字
1 const const是定义一个常量 2 volatile 代表定义一个变量,这个变量值可能在CPU指令之外被改变 volatile int a;//定义了一个volatile类型的int变量 通 ...
- 处理 input 上传图片,浏览器读取图片大小过程中遇到到的坑(兼容IE8\9)
为了 解决这个坑~ 已经 累傻了.. 周末再 写吧..
- @Controller和@RestController的区别?
@Controller和@RestController的区别?官方文档:@RestController is a stereotype annotation that combines @Respon ...
- 【bzoj3450】Tyvj1952 Easy
题目描述 某一天WJMZBMR在打osu~~~但是他太弱逼了,有些地方完全靠运气:(我们来简化一下这个游戏的规则有n次点击要做,成功了就是o,失败了就是x,分数是按comb计算的,连续a个comb就有 ...
- PHP中类的继承和构造函数的继承
PHP4.x 版本: PHP 4.x 的构造函数名与类名相同. 子类的构造函数名与子类名相同(废话). 在子类里父类的构造函数不会自动执行. 要在子类里执行父类的构造函数,必须执行类似以下语句: $t ...
- URL处理几个关键的函数parse_url、parse_str与http_build_query
parse_url() 该函数可以解析 URL,返回其组成部分.它的用法如下: array parse_url(string $url) 此函数返回一个关联数组,包含现有 URL 的各种组成部分.如果 ...
- 如何挂载阿里云Linux服务器的“数据盘”(新购买)
详细操作参考: http://jingyan.baidu.com/article/90808022d2e9a3fd91c80fe9.html 用到的命令行汇总: 1.查看磁盘: fdisk -l 2. ...
- 【Alpha】Daily Scrum Meeting第十次
一.本次Daily Scrum Meeting主要内容 每个人学习情况 测试的任务的安排 Alpha版本展示的具体内容 二.任务安排 学号尾数 昨天做的任务 今天做的任务 任务用时 612 完成将计时 ...
- C和指针 第七章 习题
7.1 hermite递归函数 int hermite(int n, int x) { if (n <= 0) { return 1; } if (n == 1) { return 2 * x; ...