requirejs:让人迷惑的路径解析
接触过requirejs的童鞋可能都知道,无论是通过define来定义模块,还是通过require来加载模块,模块依赖声明都是很重要的一步。而其中涉及到的模块路径解析,对于新手来说,有的时候会让人觉得很困惑。
start up
假设我们的目录结构如下:
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:让人迷惑的路径解析的更多相关文章
- 转:requirejs:让人迷惑的路径解析(~~不错)
接触过requirejs的童鞋可能都知道,无论是通过define来定义模块,还是通过require来加载模块,模块依赖声明都是很重要的一步.而其中涉及到的模块路径解析,对于新手来说,有的时候会让人觉得 ...
- 模块化开发RequireJS之路径解析
1.requirejs遵循AMD规范,将需要的都加载好(前置加载).注:cmd是就近加载. define(['jQuery','dialog'],function($,d){ // 业务逻辑 }) ( ...
- 转:VC include 路径解析
VC include 路径解析 要了解vc中使用#include命令包含头文件所搜寻的路径,必须先了解vc中的几种路径: 1. 系统路径 系统路径在vc中是"Tools->Option ...
- JSP Servlet 路径解析 路径设置
转自:http://ethen.iteye.com/blog/800415 在用JSP和Servlet编写Web应用时,经常遇到的问题就是找不到.do路径,或者.do路径不能解析,其实归根到底就是Se ...
- stl+模拟 CCF2016 4 路径解析
// stl+模拟 CCF2016 4 路径解析 // 一开始题意理解错了.... #include <iostream> #include <string> #include ...
- Xamarin版的C# SVG路径解析器
原文:Xamarin版的C# SVG路径解析器 Xamarin版的C# SVG路径解析器,对SVG的Path路径进行解析,其中包括: 主程序SvgPathParser.cs, 相关接口定义:ISour ...
- CCF CSP 201604-3 路径解析
CCF计算机职业资格认证考试题解系列文章为meelo原创,请务必以链接形式注明本文地址 CCF CSP 201604-3 路径解析 问题描述 在操作系统中,数据通常以文件的形式存储在文件系统中.文件系 ...
- nodejs系列笔记02---模块路径解析
模块路径解析规则 参考这篇博客 我们已经知道,require函数支持斜杠(/)或盘符(C:)开头的绝对路径,也支持./开头的相对路径.但这两种路径在模块之间建立了强耦合关系,一旦某个模块文件的存放位置 ...
- rails中path、url路径解析,routes信息,form_for剖析,link_to示例,路由实例说明
原创,转载请注明http://www.cnblogs.com/juandx/p/3963023.html rails中path.url路径解析,routes信息,form_for剖析,link_to ...
随机推荐
- CSS层叠
前面的话 层叠样式表CSS最基本的一个特性就是层叠.冲突的声明通过层叠进行排序,由此确定最终的文档表示.而这个过程的核心就是选择器及其相关声明的特殊性.重要性.来源及继承机制.本文将详细介绍CSS层叠 ...
- JavaScript禁用页面刷新
JavaScript禁用页面刷新代码如下: //禁用F5刷新 document.onkeydown = function () { if (event.keyCode == 116) { event. ...
- Javascript定时器(三)——setTimeout(func, 0)
setTimeout(func, 0)可以使用在很多地方,拆分循环.模拟事件捕获.页面渲染等 一.setTimeout中的delay参数为0,并不是指马上执行 <script type=&quo ...
- 精致3D图片切换效果,最适合企业产品展示
这是一个精致的立体图片切换效果,特别适合企业产品展示,可立即用于实际项目中.支持导航和自动播放功能, 基于 CSS3 实现,推荐使用最新的 Chrome,Firefox 和 Safari 浏览器浏览效 ...
- Android 软件开发之如何使用Eclipse Debug调试程序详解及Eclipse常用快捷键(转)
1.在程序中添加一个断点如果所示:在Eclipse中添加了一个程序断点 在Eclipse中一共有三种添加断点的方法 第一种: 在红框区域右键出现菜单后点击第一项 Toggle Breakpoint 将 ...
- git gitignore文件失效处理
这里讲的是使用 git ignore 时候的一种特殊情况 正常你在本地给项目添加了一些文件之后,一般都会自动全部跟踪,但是在这个时候你必须编辑一个ignore文件,把一些不需要跟踪到文件ignor ...
- [Core] .NET Core & VS Code 之路(1) Hello World
目录 相关链接 dotnet命令 VS Code Hello World Web Hello World 总结 其实本篇上个月已经写好, 只是 但是,不忘初心方得始终 相关链接 Learn .NET ...
- Java进阶之reflection(反射机制)——反射概念与基础
反射机制是Java动态性之一,而说到动态性首先得了解动态语言.那么何为动态语言? 一.动态语言 动态语言,是指程序在运行时可以改变其结构:新的函数可以引进,已有的函数可以被删除等结构上的变化.比如常见 ...
- visual studio 2015.3 downloads
https://www.visualstudio.com/zh-hans/downloads/ visual studio 2015.3 downloads http://download.micro ...
- ASP.NET MVC系列:从Controller访问Model数据
在项目解决方案中,添加一个MoviesController控制器,选择对应的模板,和模型类以及数据上下文:关于如何添加模型类和数据上下文,我们在ASP.NET MVC系列:添加模型中已经介绍过