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 a given 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 third argument to the resolver for easy compatibility workflows.
In addition to returning the resolved file URL value, the resolve hook also
returns a format
property specifying the module format of the resolved
module. 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 resolution rules with only JS file extension and Node builtin modules support could be 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 the
existing format
interpretations, the dynamicInstantiate
hook can be used.
This hook is called only for modules that return format: "dynamic"
from
the 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 will
then be called at the exact point of module evaluation order for that module
in 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
- 断言测试
- 异步钩子(Async Hooks)
- 缓存(Buffer)
- C++ 插件
- C/C++ 插件 - N-API
- 子进程
- 集群(Cluster)
- 命令行参数
- 控制台(Console)
- 加密(Crypto)
- 调试器
- 废弃的 API
- DNS
- 域(Domain)
- ECMAScript 模块
- 错误(Errors)
- 事件(Events)
- 文件系统
- 全局对象(Globals)
- HTTP
- HTTP/2
- HTTPS
- 检查工具(Inspector)
- 国际化
- 模块(Modules)
- 网络(Net)
- 操作系统(OS)
- 路径(Path)
- 性能钩子(Performance Hooks)
- 进程
- Punycode
- 查询字符串
- 逐行读取
- 交互式解释器(REPL)
- 流(Stream)
- 字符串解码
- 定时器(Timers)
- 安全传输层(TLS/SSL)
- 事件跟踪(Tracing)
- TTY
- UDP / 数据报
- URL
- 工具集
- V8
- 虚拟机(VM)
- 压缩(ZLIB)