从 RequireJS 到 SeaJS(3)
来看 RequireJS 的 API 页面:api.html, 该篇博客着重分析 RequireJS 和 SeaJS 在 ID 规则上的异同。
RequireJS 的 ID 规则
对于模块加载器来说,模块 id 遵守的规则非常重要。
首先来定义几个概念。假设当前页面路径为 http://t.com/a/b/c.html
, 则:
- pageRoot =
http://t.com
- pageUrl =
http://t.com/a/b
- baseUrl: 在 RequireJS 里,默认情况下,baseUrl 就是 pageUrl, 除非:
- 通过 require.config 更改了 baseUrl
- 指定了 data-main, 比如
<script src="require.js" data-main="scripts/main"></script>
这时 baseUrl 为
pageUrl/scripts
- paths: 表示路径的缩写,通过 config 来配置:
require.config({ paths: { 'some': 'xxx/zzz' } })
这时,
some/a
实际上代表xxx/zzz/a
- moduleUrl: 如果模块路径为
http://t.com/path/to/a.js
, 则 moduleUrl =http://t.com/path/to
RequireJS 的 id 规则为:首先,会通过 paths 解析,解析完成后:
- 是 Page ID:
- 以
.js
结尾的,比如some/a/b.js
- 以
/
开头的,比如/a/b
- 以
http(s)://
开头的
Page ID 的解析规则与
script src="xxx"
中的 xxx 一样。 - 以
- 是
some/module
这种 Top-Level ID, 会解析成baseUrl/some/module.js
- 是
./some/module
这种 Relative ID, 会解析成moduleUrl/some/module.js
SeaJS 的 ID 规则
SeaJS 的 ID 规则可以总结为:
- 省略约定:
.js 后缀可以省略。
require('path/to/a.js')
和require('path/to/a')
是一样的。
- 环境相关: 除了 Top-Level ID 始终相对 baseUrl 来定位,其他 ID 都是相对当前环境来定位。
举例如下:
// 在 http://t.com/test.html 中: seajs.use(['./a', 'b', 'c.js', '/d', 'http://x.com/e']); // 会下载 // http://t.com/a.js // baseUrl/b.js // baseUrl/c.js // http://t.com/d.js // http://x.com/e.js // 在 http://cdn.com/path/to/t.js 中: define(function(require) { require('./a'); require('b'); require('c.js'); require('/d'); require('http://x.com/e'); }); // 会下载 // http://cdn.com/path/to/a.js // baseUrl/b.js // baseUrl/c.js // http://cdn.com/d.js // http://x.com/e.js
可以看出,在 SeaJS 里,ID 可以分成两类:
- Top-Level ID:
some/module
这种,会根据 baseUrl 来定位。 - Context ID: 除了
some/module
之外的所有形式,会根据当前环境来定位。
ID 规则对使用体验的影响
RequireJS 里有 Page ID 的概念,和浏览器解析 src 的规则保持一致。
SeaJS 里则有省缺 .js 后缀的约定,和 CommonJS 以及 NodeJS 的约定保持一致。
这个取舍,使得 RequireJS 的 ID 更接近文件路径,SeaJS 的 ID 则更接近模块标识。
这其实是由两者的定位决定的:RequireJS 想同时是文件和模块加载器,SeaJS 则只专注于模块加载器。
当采用 Simplified CommonJS Wrapper 格式时,RequireJS 和 SeaJS 的解析规则基本一致:
1
2
3
4
5
6
|
// xxx/to/a.js define(function(require, exports, module) { require('a'); // baseUrl/a.js require('./b'); // xxx/to/b.js require('./b.js'); // xxx/to/b.js }); |
RequireJS 的 ID 规则是比较容易让人混淆的,特别对于新手来说。有没有 .js 后缀,以及采用的模块书写格式,都会影响解析规则。
SeaJS 的 ID 规则更简单纯粹,和 CommonJS 以及 NodeJS 尽量保持一致。