模块规范
Cocos Creator 引擎提供的所有功能都以 ESM 模块的形式存在,见 引擎模块。
项目资源目录下以 .ts
作为后缀的文件。例如 assets/scripts/foo.ts
。
对于任何其它模块格式,Cocos Creator 选择与 Node.js 类似的规则来 。具体地,以下文件将被视为 ESM 格式:
以
.mjs
为后缀的文件;以
.js
为后缀的文件,并且与其最相近的父级package.json
文件中包含一个顶级的"type"
字段,其值为"module"
。
其余的文件将被视为 CommonJS 模块格式,这包括:
以
.cjs
为后缀的文件;以
.js
为后缀的文件,并且与其最相近的父级package.json
文件中包含一个顶级的"type"
字段,其值为"commonjs"
。不在上述条件下的以
.js
为后缀的文件。
在 ESM 模块中,通过标准的导入导出语句与目标模块进行交互,例如:
导入导出语句中关键字 from
后的字符串称为 模块说明符。模块说明符也可作为参数出现在动态导入表达式 import()
中。
模块说明符用于指定目标模块,从模块说明符中解析出目标模块 URL 的过程称为 模块解析。
Cocos Creator 支持三种模块说明符:
相对说明符 像
'./foo'
、'../bar'
这样以'./'
和'../'
开头的说明符。绝对说明符 指定了一个 URL 的说明符。例如:
foo:/bar
。
相对说明符以当前模块的 URL 为基础 URL,以相对说明符为输入来解析目标模块的 URL。
例如,对于模块 项目路径/assets/scripts/utils/foo
来说,'./bar'
将解析为同目录下的 项目路径/assets/scripts/utils/bar
;'../baz'
将解析为上层目录中的 项目路径/assets/scripts/baz
。
绝对说明符
绝对说明符直接指定了目标模块的 URL。
Cocos Creator 目前仅支持文件协议的 URL。但由于文件 URL 中指定的文件路径是绝对路径,因此很少使用。
目前为止,对于裸说明符,Cocos Creator 将应用 和 Node.js 模块解析算法。
条件性导出
在 Node.js 模块解析算法中,包的条件性导出 特性用于根据一些条件映射包中的子路径。与 Node.js 类似,Cocos Creator 实现了内置条件 import
、default
,但未实现条件 require
、。
开发者可通过编辑器主菜单 项目 -> 项目设置 -> 脚本 中的 导出条件 项指定 额外 的条件,该项默认值为 browser,可用 逗号 作为分隔符来指定多个额外条件,例如 browser, bar
。
若 导出条件 项使用默认值 browser
,当某 npm 包 foo
的 package.json
中包含以下配置时:
{
"exports": {
".": {
"browser": "./dist/browser-main.mjs",
"import": "./dist/main.mjs"
}
}
}
"foo"
将解析为包中路径为 dist/browser-main.mjs
的模块。
若 导出条件 项设置为空,则表示不指定任何额外条件,上例中的 "foo"
将解析为包中路径为 dist/main.mjs
的模块。
后缀与目录导入
Cocos Creator 对模块说明符中模块的后缀要求更偏向于 Web —— 必须指定后缀并且不支持 Node.js 式的目录导入。然而,基于历史原因和现行的一些限制,TypeScript 模块不允许给出后缀并支持 Node.js 式的目录导入。具体来说:
当目标模块文件的后缀是 .js
、.mjs
时,模块说明符中 必须指定 后缀:
import './foo/index.mjs'; // 正确
import './foo'; // 错误:无法找到模块。
但当目标模块文件的后缀是 .ts
时,模块说明符中 不允许指定 后缀:
另一方面,支持 Node.js 式的目录导入:
import './foo'; // 正确:解析为 `foo/index.ts` 模块
有些 npm 包的清单文件 package.json
中记录了 browser
字段,例如 JSZip。browser
字段用于指定当该包在非 Node.js 环境下特有的模块解析方法,它可使得包中的某些专用于 Node.js 的模块被替换为能够在 Web 中使用的模块。虽然 Cocos Creator 不支持该字段,但如果对 npm 包有编辑的能力,Cocos Creator 推荐使用 和 子路径导入 来代替 browser
字段。
否则,可以以非 npm 的方式使用目标库。例如,将目标库中专为非 Node.js 环境制定的模块复制至项目中,再通过相对路径来导入。
在 CommonJS 模块中,Cocos Creator 应用的是 。
Cocos Creator 允许在 ESM 模块中导入 CommonJS 模块。
当从 ESM 模块中导入 CommonJS 模块时,CommonJS 模块的 module.exports
对象将作为 ESM 模块的默认导出:
CommonJS 模块的 ECMAScript 模块命名空间 表示,是含有一个 default
导出的命名空间,其中的 default
导出就指向了 CommonJS 模块的 module.exports
的值。
该 可以通过 import * as m from 'cjs'
来观察:
import * as m from 'cjs';
// 打印:
// [Module] { default: <module.exports> }
Cocos Creator 用于解析 ESM 模块说明符的算法由以下的 CREATOR_ESM_RESOLVE
方法给出。它返回从当前 URL 解析模块说明符得到的 URL 结果。
在解析算法规范中,引用了Node ESM 解析算法 和 (引用为 IMPORT_MAP_RESOLVE
)。
解析算法规范
CREATOR_ESM_RESOLVE(specifier, parentURL)
- Let
resolved
be the result ofCREATOR_STD_RESOLVE(specifier, parentURL)
. - Return
resolved
.
CREATOR_STD_RESOLVE(specifier, parentURL)
- If import map configured, then
- Let
resolved
be the result ofIMPORT_MAP_RESOLVE(specifier, parentURL)
, with parsed import map. - If
resolved
is not nil, returnresolved
.
- Let
- return
ESM_RESOLVE(specifier, parentURL)
.
- If the file at
url
exists, then- Return
url
.
- Return
- Let
baseName
be the portion after the last “/“ in pathname ofurl
, or whole pathname if it does not contain a “/“. - If
baseName
is empty, then- Return
undefined
.
- Return
- Let
resolved
be the result URL resolution of “./“ concatenated withbaseName
and.ts
, relative to parentURL.- If the file at
resolved
exists, then - Return
resolved
.
- If the file at
- Let
resolved
be the result URL resolution of “./“ concatenated withbaseName
and/index.ts
, relative to parentURL.- If the file at
resolved
exists, then - Return .
- If the file at
- Return
undefined
.