RequireJS 笔记

概述

RequireJS 是一个工具库,能在网页中进行模块化编程,从而提高代码的性能和可维护性。它的模块管理遵守 AMD 规范。类似的库还有 sea.js 国人开发的一个库,遵守 CMD 规范。

个人推荐使用 RequireJS 库,从功能上说,两者是差不多的,但 RequireJS 有完善的文档和很好的打包工具可用,相比 sea.js 强多了,在这里吐槽下,感觉之前被 sea.js 坑了不少。

使用

加载 javascript 文件

RequireJS 以一个相对于 baseUrl 的地址来加载所有的代码。 页面顶层 <script> 标签含有一个特殊的属性 data-main 使用它来启动脚本加载过程,而 baseUrl 一般设置到与该属性相一致的目录。

1
<script data-main="scripts/main.js" src="scripts/require.js"></script>

baseUrl 亦可通过 RequireJS config 手动设置。如果没有显式指定 config 及 data-main ,则默认的 baseUrl 为包含 RequireJS 的那个 HTML 页面的所属目录。

若符合下述规则之一,则可避开 baseUrl + paths 配置

  • 以 “.js” 结束
  • 以 “/“ 开始
  • 包含 URL 协议, 如 “http:” or “https:”

一般来说,最好还是使用 baseUrlpaths 去设置。它会给你带来额外的灵活性,如便于脚本的重命名、重定位等。同时,为了避免凌乱的配置,最好不要使用多级嵌套的目录层次来组织代码。

模块的定义

1.Simple Name/Value Pairs

1
2
3
4
define({
color: "black",
size: "unisize"
});

2.Definition Functions

1
2
3
4
5
6
7
8
define(function () {
// ...
return {
color: "black",
size: "unisize"
}
});

3.Definition Functions with Dependencies

1
2
3
4
5
6
7
8
9
10
11
12
define(["./cart", "./inventory"], function(cart, inventory) {
//return an object
return {
color: "blue",
size: "large",
addToCart: function() {
inventory.decrement(this);
cart.add(this);
}
}
}
);

依赖关系会以参数的形式注入到函数上,参数列表与依赖名称列表一一对应。

4.Define a Module as a Function

1
2
3
4
5
6
7
8
9
10
define(["my/cart", "my/inventory"],
function(cart, inventory) {
//return a function.
//It gets or sets the window title.
return function(title) {
return title ? (window.title = title) :
inventory.storeName + ' ' + cart.name;
}
}
);

5.Define a Module with Simplified CommonJS Wrapper

1
2
3
4
5
6
7
8
define(function(require, exports, module) {
var a = require('a'),
b = require('b');
//Return the module value
return function () {};
}
);

利用 Function.prototype.toString() 实现,但在一些设备如 PS3 及一些老的 Opera 手机浏览器中不起作用。

6.Define a Module with a Name

1
2
3
4
5
6
define("foo/title",
["my/cart", "my/inventory"],
function(cart, inventory) {
//...
}
);

可看到一些 define() 中包含了一个模块名称作为首个参数,这些常由打包工具生成。你也可以自己显式指定模块名称,但这使模块更不具备移植性——就是说若你将文件移动到其他目录下,你就得重命名。

Loader Plugins

有关 Loader Plugins 可跳转阅读 http://requirejs.org/docs/api.html#plugins 有关 requirejs 插件的编写可跳阅 http://requirejs.org/docs/plugins.html#api

CommonJS Compatibility

1
2
3
4
5
6
7
8
//BAD
var mod = require(someCondition ? 'a' : 'b');
//BAD
if (someCondition) {
var a = require('a');
} else {
var b = require('b');

以上的写法在 RequireJS 中是错误的用法,这样做的话, a 和 b 这两模块都会加载到页面中,这里可查看下文给出的列子。详细可点击阅读 CommonJS Compatibility
这种业务场景的解决方案 callback-require

机制

RequireJS 使用 head.appendChild() 将每一个依赖加载为一个 script 标签。
RequireJS 等待所有的依赖加载完毕,加载是异步的,计算出模块定义函数正确调用顺序,然后依次调用它们。

打包

RequireJS 提供一个基于 node.js 的命令行工具 r.js ,用来压缩多个 js 文件。它的主要作用是将多个模块文件压缩合并成一个脚本文件,以减少网页的HTTP请求数。例:

1
node r.js -o baseUrl=. name=main out=main-built.js

除了直接在命令行提供参数设置,也可以将参数写入一个文件,假定文件名为 build.js

1
node r.js -o build.js

有关更多的配置项可查看 example.build.js 和一个打包示例 requirejs/example-multipage

进一步优化,使用 r.js 优化后的代码可以使用 almond 来加载。

RequireJS 用法示例

例子中有对上文内容的一些补充,建议详细阅读代码。大家可点击 例子 打开看看,留意控制台的输出,注意这里为了演示就没有对 js 进行打包。

相关阅读