模块规范

    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 实现了内置条件 importdefault,但未实现条件 require、。

    开发者可通过编辑器主菜单 项目 -> 项目设置 -> 脚本 中的 导出条件 项指定 额外 的条件,该项默认值为 browser,可用 逗号 作为分隔符来指定多个额外条件,例如 browser, bar

    导出条件 项使用默认值 browser,当某 npm 包 foopackage.json 中包含以下配置时:

    1. {
    2. "exports": {
    3. ".": {
    4. "browser": "./dist/browser-main.mjs",
    5. "import": "./dist/main.mjs"
    6. }
    7. }
    8. }

    "foo" 将解析为包中路径为 dist/browser-main.mjs 的模块。

    导出条件 项设置为空,则表示不指定任何额外条件,上例中的 "foo" 将解析为包中路径为 dist/main.mjs 的模块。

    后缀与目录导入

    Cocos Creator 对模块说明符中模块的后缀要求更偏向于 Web —— 必须指定后缀并且不支持 Node.js 式的目录导入。然而,基于历史原因和现行的一些限制,TypeScript 模块不允许给出后缀并支持 Node.js 式的目录导入。具体来说:

    当目标模块文件的后缀是 .js.mjs 时,模块说明符中 必须指定 后缀:

    1. import './foo/index.mjs'; // 正确
    2. import './foo'; // 错误:无法找到模块。

    但当目标模块文件的后缀是 .ts 时,模块说明符中 不允许指定 后缀:

    另一方面,支持 Node.js 式的目录导入:

    1. import './foo'; // 正确:解析为 `foo/index.ts` 模块

    有些 npm 包的清单文件 package.json 中记录了 browser 字段,例如 JSZipbrowser 字段用于指定当该包在非 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' 来观察:

    1. import * as m from 'cjs';
    2. // 打印:
    3. // [Module] { default: <module.exports> }

    Cocos Creator 用于解析 ESM 模块说明符的算法由以下的 CREATOR_ESM_RESOLVE 方法给出。它返回从当前 URL 解析模块说明符得到的 URL 结果。

    在解析算法规范中,引用了Node ESM 解析算法 和 (引用为 IMPORT_MAP_RESOLVE)。

    解析算法规范

    CREATOR_ESM_RESOLVE(specifier, parentURL)

    1. Let resolved be the result of CREATOR_STD_RESOLVE(specifier, parentURL).
    2. Return resolved.

    CREATOR_STD_RESOLVE(specifier, parentURL)

    1. If import map configured, then
      1. Let resolved be the result of IMPORT_MAP_RESOLVE(specifier, parentURL), with parsed import map.
      2. If resolved is not nil, return resolved.
    2. return ESM_RESOLVE(specifier, parentURL).
    1. If the file at url exists, then
      1. Return url.
    2. Let baseName be the portion after the last “/“ in pathname of url, or whole pathname if it does not contain a “/“.
    3. If baseName is empty, then
      1. Return undefined.
    4. Let resolved be the result URL resolution of “./“ concatenated with baseName and .ts, relative to parentURL.
      1. If the file at resolved exists, then
      2. Return resolved.
    5. Let resolved be the result URL resolution of “./“ concatenated with baseName and /index.ts, relative to parentURL.
      1. If the file at resolved exists, then
      2. Return .
    6. Return undefined.