模块解析和加载


🌐 Module resolution and loading

Node.js 有两种模块解析和加载方式,具体取决于模块的请求方式。

🌐 Node.js has two types of module resolution and loading, chosen based on how the module is requested.

当通过 require() 请求模块时(在 CommonJS 模块中默认可用,并且可以在 CommonJS 和 ES 模块中使用 createRequire() 动态生成):

🌐 When a module is requested via require() (available by default in CommonJS modules, and can be dynamically generated using createRequire() in both CommonJS and ES Modules):

  • 分辨率:
    • require() 发起的解析支持 将文件夹作为模块
    • 在解析指定模块时,如果没有找到精确匹配,require() 会尝试添加扩展名(.js.json,最后是 .node),然后尝试解析 将文件夹作为模块
    • 默认情况下,它不支持将 URL 作为说明符。
  • 加载中:
    • .json 文件被视为 JSON 文本文件。
    • .node 文件被解释为使用 process.dlopen() 加载的编译插件模块。
    • .ts.mts.cts 文件被视为 TypeScript 文本文件。
    • 具有其他扩展名或没有扩展名的文件将被视为 JavaScript 文本文件。
    • require() 只能用于 从 CommonJS 模块加载 ECMAScript 模块,如果 ECMAScript 模块 及其依赖 是同步的(即它们不包含顶层 await)。

当通过静态 import 语句(仅在 ES 模块中可用)或 import() 表达式(在 CommonJS 和 ES 模块中均可用)请求模块时:

🌐 When a module is requested via static import statements (only available in ES Modules) or import() expressions (available in both CommonJS and ES Modules):

  • 分辨率:
    • import/import() 的解析不支持将文件夹作为模块,目录索引(例如 './startup/index.js')必须完整指定。
    • 它不会执行扩展名搜索。当指定符是相对或绝对文件 URL 时,必须提供文件扩展名。
    • 默认情况下,它支持将 file://data: URL 用作指定符。
  • 加载中:
    • .json 文件被视为 JSON 文本文件。导入 JSON 模块时,需要指定导入类型属性(例如 import json from './data.json' with { type: 'json' })。
    • 如果启用了 --experimental-addon-modules.node 文件会被解释为通过 process.dlopen() 加载的已编译插件模块。
    • .ts.mts.cts 文件被视为 TypeScript 文本文件。
    • 它只接受 .js.mjs.cjs 扩展名的 JavaScript 文本文件。
    • .wasm 文件被视为 WebAssembly 模块
    • 任何其他文件扩展名都会导致 ERR_UNKNOWN_FILE_EXTENSION 错误。可以通过 自定义钩子 添加其他文件扩展名。
    • import/import() 可以用来加载 JavaScript CommonJS 模块。这样的模块会通过 cjs-module-lexer 处理,以尝试识别命名导出,如果可以通过静态分析确定,则可以使用这些导出。

无论模块以何种方式被请求,都可以使用 自定义钩子 自定义解析和加载过程。

🌐 Regardless of how a module is requested, the resolution and loading process can be customized using customization hooks.