23 January 2014

原文:Consuming modules: Module ids

有些模块需要依赖其他模块才能运行,正如我们在 编写 AMD 模块 中所讨论的。通过在依赖列表中罗列每个模块的标识符,或者执行“require”,当前模块的作者可以指定所依赖的其他模块。

模块标识符

AMD 和 CommonJS 都指定了看起来非常像文件路径或 URL 的模块标识符:由斜杠分隔的词条组成。词条的定义相当宽松。虽然 CommonJS 规范 进一步约束“词条”为驼峰式的 JavaScript 标识符,但是在实际使用中,其他的流行文件名(例如 -)也是允许的。ES6 的模块规范 则更加宽松和实际,它要求标识符应该与文件系统和 URL 兼容。

AMD 保留了 ! 字符,如果标识符中含有该字符,则表示用 加载器插件 来加载模块或其他类型的资源。

译注:格式为 [Plugin Module ID]![resource ID],例如 text!../templates/start.html

一些合法的模块标识符示例:

"wire/lib/functional"
"poly/es5-strict"
"app/billing/billTo/Customer"
"jquery"

与文件系统和 URL 一样,模块标识符中的斜杠描述了层次结构。通常情况下,层次结构与文件系统的目录结构是相同的,但是无法百分百保证。例如,curl.js 暴漏了一些扩展 API 模块,这些模块的标识符格式是“curl/submodule”,但是它们并不是真实存在的文件。

注意大小写是否正确。尽管大部分模块通常映射到了文件,即模块标识符的拼写和大小写与文件名完全一样。例如,“jQuery”就不是正确的模块标识符(大写了“Q”)!下面的代码演示了如何在一个模块中加载 jQuery:

define(function (require) {

    var $ = require('jquery');
    $('body').text('Hello world!');

});

保留标识符

大多数 AMD 环境会保留几个特殊的模块标识符,用来引用内置模块或工具。例如,标识符“require”、“exports”和“module”用于模拟 CommonJS 中的同名变量,以此来访问伪模块。AMD 环境可能还保留了一些其他的标识符。例如,curl.js 0.8 的一个推荐特性是伪模块 global,用来帮助开发人员编写可以同时运行在服务器和浏览器的代码。

define(function (require) {

    // inspect the CommonJS "module" var
    var module = require('module');
    console.log(module.uri, module.id);

});

关于保留标识符的详细信息,请查阅你正在使用的 AMD 环境的文档。

相对标识符

AMD 和 CommonJS 也支持相对标识符概念。处于同一层级下的模块,可以通过以 . 开头的标识符来引用。处于上一层级的模块,则通过 ../ 来引用。

在运行时或构建时,AMD 环境必须将相对标识符转换为绝对标识符。绝对标识符位于模块层级的顶层,并且不包含 ...。移除起始 ... 的过程称为“规范化 normalization”。例如,假设当前模块的标识符是 app/billing/billTo/Customer,AMD 环境会像下面这样规范请求的标识符:

// module app/billing/billTo/Customer
define(function (require) {

    // normalizes to "app/billing/billTo/store"
    var store = require("./store");

    // normalizes to "app/billing/payee/Payee"
    var Payee = require("../payee/Payee");

});

AMD 和 CommonJS 也可以把单个的 ... 解释为模块标识符。. 被规范为与当前层级同名的模块,.. 被规范为与上一层级同名的模块。是的,太混乱了!也许这就是很少看到它们被使用的原因。但愿举一些例子会有所帮助。例如,当前模块是 “app/billing/billTo/Customer”,AMD 环境会像下面这样规范请求的标识符:

// module app/billing/billTo/Customer
define(function (require) {

    // normalizes to "app/billing/billTo" (a module, not a folder!)
    var billTo = require(".");

    // normalizes to "app/billing" (a module, not a folder!)
    var billing = require("..");

});

提示:永远不要使用相对标识符来引用不相关的模块!相对模块适用于在同一个“包 package”(后面再定义它)中的场景。此外,多个 ../ 是一种不好的代码味道,意味着你需要更好地组织你的模块。在 AMD 环境中,相对标识符还可能被解释为一个 URL 而不是标识符。

// module app/billing/billTo/Customer
define(function (require) {

    // OK: normalizes to "app/common/payee/Payee"
    // food for thought: should common and billing be separate packages?
    var Payee = require("../../common/payee/Payee");

    // BAD: normalizes to "../util/date" -- a URL, not an ID!
    var Date = require("../../../util/Date");

    // GOOD: use an absolute id to reference a different package
    var Date = require("util/Date"); // "Date" module in the "util" package

});

那么,如果我指定了标识符(而不是 URL),AMD 环境中是如何知道去哪里查找模块的呢?

那是 定位 AMD 模块 的主题了。



blog comments powered by Disqus