Node.js v8.x 中文文档
目录
ECMAScript模块#
Node.js包含了对基于 [Node.js EP for ES Modules] 的ES模块的支持。
不是所有EP的功能都是完整的并且将随着VM的支持和实现而就绪的。有问题的地方正在被修改完善。
启用#
--experimental-modules
标志可用于启用加载ES模块的功能。
一旦被设置启用,以 .mjs
为后缀的文件将能够作为ES模块加载。
node --experimental-modules my-app.mjs
特性#
Supported#
只有在程序主入口添加CLI参数可以成为ES模块的入口点。在未来 import()
可以在程序运行时创建ES模块入口点。
Unsupported#
特性 | 原因 |
---|---|
require('./foo.mjs') | ES模块具有不同的加载方式,使用 import() 语言标准 |
import() | 等待在Node.js中使用更加新的V8版本 |
import.meta | 等待V8实现 |
import
与 require
之间的显著差异#
No NODE_PATH#
根据 NODE_PATH
查询模块不是解析 import
的环节之一。如果想要怎么做,那么请使用符号链接。
No require.extensions
#
require.extensions
没有被 import
使用。但是值得期望的是,加载器钩子可能在未来提供这个工作流流程。
No require.cache
#
require.cache
没有被 import
使用。它有一个独立的缓存。
URL based paths#
ESM基于URL
语义来解析和缓存。这意味着那些包含特殊字符的文件名,如 #
和 ?
需要进行转义。
如果使用 import
来解析一个拥有不同查询或片段的模块,该模块将被加载多次。
import './foo?query=1'; // loads ./foo with query of "?query=1"import './foo?query=2'; // loads ./foo with query of "?query=2"
直到现在,模块只能使用 file:
协议来加载。
与现有模块的交互#
所有CommonJS,JSON和C++模块都可以通过 import
来加载。
以这种方式加载的模块只加载一次,即使 import
语句中同一个模块的查询或片段字符串不同。
当通过 import
加载时,这些模块将提供一个 default
导出相当于完成计算后的 module.exports
。
import fs from 'fs';fs.readFile('./foo.txt', (err, body) => { if (err) { console.error(err); } else { console.log(body); }});
Loader hooks#
定制一个默认的模块解决方案,加载器钩子能通过提供给Node一个 --loader ./loader-name.mjs 参数来配置。
当此钩子被使用时,只支持ES模块加载,不支持任何的CommonJS模块加载。
Resolve hook#
The resolve hook returns the resolved file URL and module format for agiven module specifier and parent file URL:
import url from 'url';export async function resolve(specifier, parentModuleURL, defaultResolver) { return { url: new URL(specifier, parentModuleURL).href, format: 'esm' };}
The default NodeJS ES module resolution function is provided as a thirdargument to the resolver for easy compatibility workflows.
In addition to returning the resolved file URL value, the resolve hook alsoreturns a format
property specifying the module format of the resolvedmodule. This can be one of the following:
format | Description |
---|---|
"esm" | Load a standard JavaScript module |
"commonjs" | Load a node-style CommonJS module |
"builtin" | Load a node builtin CommonJS module |
"json" | Load a JSON file |
"addon" | Load a [C++ Addon][addons] |
"dynamic" | Use a [dynamic instantiate hook][] |
For example, a dummy loader to load JavaScript restricted to browser resolutionrules with only JS file extension and Node builtin modules support couldbe written:
import url from 'url';import path from 'path';import process from 'process';import Module from 'module';const builtins = Module.builtinModules;const JS_EXTENSIONS = new Set(['.js', '.mjs']);export function resolve(specifier, parentModuleURL/*, defaultResolve */) { if (builtins.includes(specifier)) { return { url: specifier, format: 'builtin' }; } if (/^\.{0,2}[/]/.test(specifier) !== true && !specifier.startsWith('file:')) { // For node_modules support: // return defaultResolve(specifier, parentModuleURL); throw new Error( `imports must begin with '/', './', or '../'; '${specifier}' does not`); } const resolved = new url.URL(specifier, parentModuleURL); const ext = path.extname(resolved.pathname); if (!JS_EXTENSIONS.has(ext)) { throw new Error( `Cannot load file with non-JavaScript file extension ${ext}.`); } return { url: resolved.href, format: 'esm' };}
With this loader, running:
NODE_OPTIONS='--experimental-modules --loader ./custom-loader.mjs' node x.js
would load the module x.js
as an ES module with relative resolution support(with node_modules
loading skipped in this example).
Dynamic instantiate hook#
To create a custom dynamic module that doesn't correspond to one of theexisting format
interpretations, the dynamicInstantiate
hook can be used.This hook is called only for modules that return format: "dynamic"
fromthe resolve
hook.
export async function dynamicInstantiate(url) { return { exports: ['customExportName'], execute: (exports) => { // get and set functions provided for pre-allocated export names exports.customExportName.set('value'); } };}
With the list of module exports provided upfront, the execute
function willthen be called at the exact point of module evaluation order for that modulein the import tree.[Node.js EP for ES Modules]: https://github.com/nodejs/node-eps/blob/master/002-es-modules.md[addons]: addons.html[dynamic instantiate hook]: #esm_dynamic_instantiate_hook