原文地址: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加载下来后,它会做两件事件:

  1. 加载js/main.js
  2. 将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 :让依赖更简洁、灵活

比如我们加载了下面一堆模块(好多水果。。。),看着下面一长串的依赖列表,可能你一下子就看出问题来了:

  1. 费力气:每个加载的模块前面都有长长的 common/fruits
  2. 难维护:说不定哪一天目录名就变了(在大型项目中并不算罕见),想象一下目录结构变更带来的工作量
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的例子。这里再来个例子,说明下下三种情况下,匹配路径的规则 
>

  1. apple :没有在paths规则里定义,于是为 baseUrl + apple.js => js/apple.js
  2. common/fruits :common已经在paths里定义,于是为baseUrl + common/fruits + apple.js => js/common/fruits/apple.js
  3. ../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)时的路径小结的更多相关文章

  1. requirejs:模块加载(require)及定义(define)时的路径理解

    给新来的实习生普及下JS基本知识,看到比较好的文章 转载https://blog.csdn.net/xuxiaoping1989/article/details/52384778 接触过require ...

  2. 模块加载(require)及定义(define)时的路径

    最近新公司在用requireJS进行JS的整合,刚开始接触有点蒙,于是深入了解了一下.requireJS主要是为了解决一下两个问题: (1)实现js文件的异步加载,避免网页失去响应: (2)管理模块之 ...

  3. lua的模块加载require

    加载指定的模块.首先函数会在 package.loaded 这个表中查看是否已经加载 了 modname 这个模块.如果是,那么 require 会返回保存在 package.loaded[modna ...

  4. javascript 异步模块加载 简易实现

    在javascript是没有类似java或其他语言的模块概念的,因此也不可能通过import或using等关键字来引用模块,这样造成了复杂项目中前端代码混乱,变量互相影响等. 因此在复杂项目中引入AM ...

  5. requirejs的加载原理 - 场景1. 定义一个require依赖a模块

    我们学习一个新的技术,熟练的使用之后,就应该去探索它的原理.这篇文章我们来探索下requirejs的原理. 从4个场景来探索requirejs的原理 场景1. 定义一个require依赖b模块 场景2 ...

  6. 实现一个类 RequireJS 的模块加载器 (二)

    2017 新年好 ! 新年第一天对我来说真是悲伤 ,早上兴冲冲地爬起来背着书包跑去实验室,结果今天大家都休息 .回宿舍的时候发现书包湿了,原来盒子装的牛奶盖子松了,泼了一书包,电脑风扇口和USB口都进 ...

  7. 使用RequireJS并实现一个自己的模块加载器 (一)

    RequireJS & SeaJS 在 模块化开发 开发以前,都是直接在页面上引入 script 标签来引用脚本的,当项目变得比较复杂,就会带来很多问题. JS项目中的依赖只有通过引入JS的顺 ...

  8. 第三章:模块加载系统(requirejs)

    任何一门语言在大规模应用阶段,必然要经历拆分模块的过程.便于维护与团队协作,与java走的最近的dojo率先引入加载器,早期的加载器都是同步的,使用document.write与同步Ajax请求实现. ...

  9. 使用RequireJS并实现一个自己的模块加载器 (二)

    2017 新年好 ! 新年第一天对我来说真是悲伤 ,早上兴冲冲地爬起来背着书包跑去实验室,结果今天大家都休息 .回宿舍的时候发现书包湿了,原来盒子装的牛奶盖子松了,泼了一书包,电脑风扇口和USB口都进 ...

随机推荐

  1. flask初探

    为什么我们需要模板 让我们来考虑下我们该如何扩充我们这个小的应用程序. 我们希望我们的微博应用程序的主页上有一个欢迎登录用户的标题,这是这种类型的应用程序的一个"标配".忽略本应用 ...

  2. 浅谈Android中拍照、从相册选择图片并截图相关知识点

    前言 我们在Android开发中经常会需要使用相机或者从相册中选取图片的情况,今天就把这里面相关的知识点总结下,方便以后开发的时候使用. 1.相机拍照并可自定义截图功能 我们先来看如何使用Intent ...

  3. php如何防止图片盗用/盗链的两种方法

    如今的互联网,采集网站非常多,很多网站都喜欢盗链/盗用别人网站的图片,这样不仅侵犯网权,还导致被盗链的网站消耗大量的流量,给服务器造成比较大的压力,本文章向大家介绍php如何防止图片盗用/盗链的两种方 ...

  4. Linux下安装和配置JDK与Tomcat(升级版)

    在这个版本 Linux下安装和配置JDK与Tomcat(入门版) 的基础上优化升级 1.下载相关软件 apache-tomcat-6.0.37.tar.gz jdk-6u25-linux-i586-r ...

  5. [BZOJ1604][Usaco2008 Open]Cow Neighborhoods 奶牛的邻居

    [BZOJ1604][Usaco2008 Open]Cow Neighborhoods 奶牛的邻居 试题描述 了解奶牛们的人都知道,奶牛喜欢成群结队.观察约翰的N(1≤N≤100000)只奶牛,你会发 ...

  6. PHP学习-链接数据库

    链接数据库文件:conn.php <?php $conn = mysql_connect("localhost:3306","root","us ...

  7. 2016年11月28日--ADO.Net 查、插、删、改 小练习

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  8. PHP获取一段时间内的每个周几, 每月几号, 遇到特殊日子就往后延

    2016年11月1日 16:18:19 星期二 主要用到的函数是 strtotime() strtotime('+1 Tuesday', $timestamp) 获取下周二, 从时间戳$timesta ...

  9. ASM:《X86汇编语言-从实模式到保护模式》第17章:保护模式下中断和异常的处理与抢占式多任务

    ★PART1:中断和异常概述 1. 中断(Interrupt) 中断包括硬件中断和软中断.硬件中断是由外围设备发出的中断信号引发的,以请求处理器提供服务.当I/O接口发出中断请求的时候,会被像8259 ...

  10. LeetCode 26 Remove Duplicates from Sorted Array

    Problem: Given a sorted array, remove the duplicates in place such that each element appear only onc ...