@@ -71,9 +71,9 @@ Expect major changes in the implementation including interoperability support,
71
71
specifier resolution, and default behavior.
72
72
73
73
<!-- Anchors to make sure old links find a target -->
74
- <i id =" # esm_package_json_type_field" ></i >
75
- <i id =" # esm_package_scope_and_file_extensions" ></i >
76
- <i id =" # esm_input_type_flag" ></i >
74
+ <i id =" esm_package_json_type_field " ></i >
75
+ <i id =" esm_package_scope_and_file_extensions " ></i >
76
+ <i id =" esm_input_type_flag " ></i >
77
77
78
78
## Enabling
79
79
@@ -114,44 +114,65 @@ The _specifier_ of an `import` statement is the string after the `from` keyword,
114
114
e.g. ` 'path' ` in ` import { sep } from 'path' ` . Specifiers are also used in
115
115
` export from ` statements, and as the argument to an ` import() ` expression.
116
116
117
- There are four types of specifiers:
118
-
119
- * _ Bare specifiers_ like ` 'some-package' ` . They refer to an entry point of a
120
- package by the package name.
121
-
122
- * _ Deep import specifiers_ like ` 'some-package/lib/shuffle.mjs' ` . They refer to
123
- a path within a package prefixed by the package name.
117
+ There are three types of specifiers:
124
118
125
119
* _ Relative specifiers_ like ` './startup.js' ` or ` '../config.mjs' ` . They refer
126
- to a path relative to the location of the importing file.
120
+ to a path relative to the location of the importing file. _ The file extension
121
+ is always necessary for these._
122
+
123
+ * _ Bare specifiers_ like ` 'some-package' ` or ` 'some-package/shuffle' ` . They can
124
+ refer to the main entry point of a package by the package name, or a
125
+ specific feature module within a package prefixed by the package name as per
126
+ the examples respectively. _ Including the file extension is only necessary
127
+ for packages without an [ ` "exports" ` ] [ ] field._
127
128
128
129
* _ Absolute specifiers_ like ` 'file:///opt/nodejs/config.js' ` . They refer
129
130
directly and explicitly to a full path.
130
131
131
- Bare specifiers, and the bare specifier portion of deep import specifiers, are
132
- strings; but everything else in a specifier is a URL.
132
+ Bare specifier resolutions are handled by the [ Node.js module resolution
133
+ algorithm] [ ] . All other specifier resolutions are always only resolved with
134
+ the standard relative [ URL] [ ] resolution semantics.
133
135
134
- ` file: ` , ` node: ` , and ` data: ` URLs are supported. A specifier like
135
- ` 'https://example.com/app.js' ` may be supported by browsers but it is not
136
- supported in Node.js.
136
+ Like in CommonJS, module files within packages can be accessed by appending a
137
+ path to the package name unless the package’s [ ` package.json ` ] [ ] contains an
138
+ [ ` "exports" ` ] [ ] field, in which case files within packages can only be accessed
139
+ via the paths defined in [ ` "exports" ` ] [ ] .
137
140
138
- Specifiers may not begin with ` / ` or ` // ` . These are reserved for potential
139
- future use. The root of the current volume may be referenced via ` file:/// ` .
141
+ For details on these package resolution rules that apply to bare specifiers in
142
+ the Node.js module resolution, see the [ packages documentation ] ( packages.md ) .
140
143
141
- #### ` node: ` Imports
144
+ ### Mandatory file extensions
142
145
143
- <!-- YAML
144
- added: v14.13.1
145
- -->
146
+ A file extension must be provided when using the ` import ` keyword to resolve
147
+ relative or absolute specifiers. Directory indexes (e.g. ` './startup/index.js' ` )
148
+ must also be fully specified.
149
+
150
+ This behavior matches how ` import ` behaves in browser environments, assuming a
151
+ typically configured server.
146
152
147
- ` node: ` URLs are supported as a means to load Node.js builtin modules. This
148
- URL scheme allows for builtin modules to be referenced by valid absolute URL
149
- strings.
153
+ ### URLs
154
+
155
+ ES modules are resolved and cached as URLs. This means that files containing
156
+ special characters such as ` # ` and ` ? ` need to be escaped.
157
+
158
+ ` file: ` , ` node: ` , and ` data: ` URL schemes are supported. A specifier like
159
+ ` 'https://example.com/app.js' ` is not supported natively in Node.js unless using
160
+ a [ custom HTTPS loader] [ ] .
161
+
162
+ #### ` file: ` URLs
163
+
164
+ Modules are loaded multiple times if the ` import ` specifier used to resolve
165
+ them has a different query or fragment.
150
166
151
167
``` js
152
- import fs from ' node:fs/promises' ;
168
+ import ' ./foo.mjs?query=1' ; // loads ./foo.mjs with query of "?query=1"
169
+ import ' ./foo.mjs?query=2' ; // loads ./foo.mjs with query of "?query=2"
153
170
```
154
171
172
+ The volume root may be referenced via ` / ` , ` // ` or ` file:/// ` . Given the
173
+ differences between [ URL] [ ] and path resolution (such as percent encoding
174
+ details), it is recommended to use [ url.pathToFileURL] [ ] when importing a path.
175
+
155
176
#### ` data: ` Imports
156
177
157
178
<!-- YAML
@@ -177,143 +198,130 @@ import 'data:text/javascript,console.log("hello!");';
177
198
import _ from ' data:application/json,"world!"' ;
178
199
```
179
200
180
- ## ` import.meta `
201
+ #### ` node: ` Imports
181
202
182
- * {Object}
203
+ <!-- YAML
204
+ added: v14.13.1
205
+ -->
183
206
184
- The ` import.meta ` metaproperty is an ` Object ` that contains the following
185
- property:
207
+ ` node: ` URLs are supported as an alternative means to load Node.js builtin
208
+ modules. This URL scheme allows for builtin modules to be referenced by valid
209
+ absolute URL strings.
186
210
187
- * ` url ` {string} The absolute ` file: ` URL of the module.
211
+ ``` js
212
+ import fs from ' node:fs/promises' ;
213
+ ```
188
214
189
- ## Differences between ES modules and CommonJS
215
+ ## Builtin modules
190
216
191
- ### Mandatory file extensions
217
+ [ Core modules] [ ] provide named exports of their public API. A
218
+ default export is also provided which is the value of the CommonJS exports.
219
+ The default export can be used for, among other things, modifying the named
220
+ exports. Named exports of builtin modules are updated only by calling
221
+ [ ` module.syncBuiltinESMExports() ` ] [ ] .
192
222
193
- A file extension must be provided when using the ` import ` keyword. Directory
194
- indexes (e.g. ` './startup/index.js' ` ) must also be fully specified.
223
+ ``` js
224
+ import EventEmitter from ' events' ;
225
+ const e = new EventEmitter ();
226
+ ```
195
227
196
- This behavior matches how ` import ` behaves in browser environments, assuming a
197
- typically configured server.
228
+ ``` js
229
+ import { readFile } from ' fs' ;
230
+ readFile (' ./foo.txt' , (err , source ) => {
231
+ if (err) {
232
+ console .error (err);
233
+ } else {
234
+ console .log (source);
235
+ }
236
+ });
237
+ ```
198
238
199
- ### No ` NODE_PATH `
239
+ ``` js
240
+ import fs , { readFileSync } from ' fs' ;
241
+ import { syncBuiltinESMExports } from ' module' ;
200
242
201
- ` NODE_PATH ` is not part of resolving ` import ` specifiers. Please use symlinks
202
- if this behavior is desired.
243
+ fs . readFileSync = () => Buffer . from ( ' Hello, ESM ' );
244
+ syncBuiltinESMExports ();
203
245
204
- ### No ` require ` , ` exports ` , ` module.exports ` , ` __filename ` , ` __dirname `
246
+ fs .readFileSync === readFileSync;
247
+ ```
205
248
206
- These CommonJS variables are not available in ES modules.
249
+ ## ` import() ` expressions
207
250
208
- ` require ` can be imported into an ES module using [ ` module.createRequire() ` ] [ ] .
251
+ [ Dynamic ` import() ` ] [ ] is supported in both CommonJS and ES modules. In CommonJS
252
+ modules it can be used to load ES modules.
209
253
210
- Equivalents of ` __filename ` and ` __dirname ` can be created inside of each file
211
- via [ ` import.meta.url ` ] [ ] .
254
+ ## ` import.meta `
212
255
213
- ``` js
214
- import { fileURLToPath } from ' url' ;
215
- import { dirname } from ' path' ;
256
+ * {Object}
216
257
217
- const __filename = fileURLToPath (import .meta.url);
218
- const __dirname = dirname (__filename );
219
- ` ` `
258
+ The ` import.meta ` meta property is an ` Object ` that contains the following
259
+ properties.
220
260
221
- ### No ` require . resolve `
261
+ ### ` import.meta.url `
222
262
223
- Former use cases relying on ` require .resolve ` to determine the resolved path
224
- of a module can be supported via ` import .meta.resolve` , which is experimental
225
- and supported via the ` --experimental-import-meta-resolve` flag:
263
+ * {string} The absolute ` file: ` URL of the module.
226
264
227
- ` ` ` js
228
- (async () => {
229
- const dependencyAsset = await import .meta.resolve(' component-lib/asset.css' );
230
- })();
231
- ` ` `
265
+ This is defined exactly the same as it is in browsers providing the URL of the
266
+ current module file.
232
267
233
- ` import .meta.resolve` also accepts a second argument which is the parent module
234
- from which to resolve from:
268
+ This enables useful patterns such as relative file loading:
235
269
236
270
``` js
237
- (async () => {
238
- // Equivalent to import.meta.resolve('./dep')
239
- await import .meta.resolve(' ./dep' , import.meta.url);
240
- })();
271
+ import { readFileSync } from ' fs' ;
272
+ const buffer = readFileSync (new URL (' ./data.proto' , import .meta.url));
241
273
` ` `
242
274
243
- This function is asynchronous because the ES module resolver in Node.js is
244
- asynchronous. With the introduction of [Top-Level Await][], these use cases
245
- will be easier as they won't require an async function wrapper.
246
-
247
- ### No ` require .extensions `
248
-
249
- ` require .extensions ` is not used by ` import ` . The expectation is that loader
250
- hooks can provide this workflow in the future.
275
+ ### ` import .meta.resolve(specifier[, parent])`
251
276
252
- ### No ` require.cache `
277
+ > Stability: 1 - Experimental
253
278
254
- ` require.cache` is not used by ` import` . It has a separate cache.
279
+ * ` specifier` {string} The module specifier to resolve relative to ` parent` .
280
+ * ` parent ` {string|URL} The absolute parent module URL to resolve from. If none
281
+ is specified, the value of ` import.meta.url` is used as the default.
282
+ * Returns: {Promise}
255
283
256
- ### URL-based paths
284
+ Provides a module-relative resolution function scoped to each module, returning
285
+ the URL string.
257
286
258
- ES modules are resolved and cached based upon
259
- [URL](https://url.spec.whatwg.org/) semantics. This means that files containing
260
- special characters such as ` #` and ` ?` need to be escaped.
287
+ <!-- eslint-skip -->
288
+ ` ` ` js
289
+ const dependencyAsset = await import .meta.resolve(' component-lib/asset.css' );
290
+ ` ` `
261
291
262
- Modules are loaded multiple times if the ` import ` specifier used to resolve
263
- them has a different query or fragment.
292
+ ` import .meta.resolve ` also accepts a second argument which is the parent module
293
+ from which to resolve from:
264
294
295
+ <!-- eslint-skip -->
265
296
` ` ` js
266
- import ' ./foo.mjs?query=1' ; // loads ./foo.mjs with query of "?query=1"
267
- import ' ./foo.mjs?query=2' ; // loads ./foo.mjs with query of "?query=2"
297
+ await import .meta.resolve(' ./dep' , import.meta.url);
268
298
` ` `
269
299
270
- For now, only modules using the ` file: ` protocol can be loaded.
300
+ This function is asynchronous because the ES module resolver in Node.js is
301
+ allowed to be asynchronous.
271
302
272
303
## Interoperability with CommonJS
273
304
274
- ### ` require`
275
-
276
- ` require` always treats the files it references as CommonJS. This applies
277
- whether ` require` is used the traditional way within a CommonJS environment, or
278
- in an ES module environment using [` module .createRequire ()` ][].
279
-
280
- To include an ES module into CommonJS, use [` import ()` ][].
281
-
282
305
### ` import ` statements
283
306
284
307
An ` import` statement can reference an ES module or a CommonJS module.
285
- ` import` statements are permitted only in ES modules. For similar functionality
286
- in CommonJS, see [ ` import() ` ][] .
308
+ ` import` statements are permitted only in ES modules, but dynamic [ ` import() ` ][]
309
+ expressions are supported in CommonJS for loading ES modules .
287
310
288
311
When importing [CommonJS modules](#esm_commonjs_namespaces), the
289
312
` module.exports` object is provided as the default export. Named exports may be
290
313
available, provided by static analysis as a convenience for better ecosystem
291
314
compatibility.
292
315
293
- Additional experimental flags are available for importing
294
- [Wasm modules](#esm_experimental_wasm_modules) or
295
- [JSON modules](#esm_experimental_json_modules). For importing native modules or
296
- JSON modules unflagged, see [` module.createRequire()` ][].
297
-
298
- The _specifier_ of an ` import ` statement (the string after the ` from ` keyword)
299
- can either be an URL-style relative path like ` ' ./file.mjs' ` or a package name
300
- like ` ' fs' ` .
301
-
302
- Like in CommonJS, files within packages can be accessed by appending a path to
303
- the package name; unless the package’s [` package.json` ][] contains an
304
- [` " exports" ` ][] field, in which case files within packages need to be accessed
305
- via the path defined in [` " exports" ` ][].
306
-
307
- ` ` ` js
308
- import { sin , cos } from ' geometry/trigonometry-functions.mjs' ;
309
- ` ` `
316
+ ### ` require`
310
317
311
- ### ` import () ` expressions
318
+ The CommonJS module ` require ` always treats the files it references as CommonJS.
312
319
313
- [Dynamic ` import ()` ][] is supported in both CommonJS and ES modules. It can be
314
- used to include ES module files from CommonJS code.
320
+ Using ` require` to load an ES module is not supported because ES modules have
321
+ asynchronous execution. Instead, use use [` import()` ][] to load an ES module
322
+ from a CommonJS module.
315
323
316
- ## CommonJS Namespaces
324
+ ### CommonJS Namespaces
317
325
318
326
CommonJS modules consist of a ` module.exports` object which can be of any type.
319
327
@@ -396,59 +404,73 @@ Named exports detection covers many common export patterns, reexport patterns
396
404
and build tool and transpiler outputs. See [cjs-module-lexer][] for the exact
397
405
semantics implemented.
398
406
399
- ## Builtin modules
407
+ ### Differences between ES modules and CommonJS
400
408
401
- [Core modules][] provide named exports of their public API. A
402
- default export is also provided which is the value of the CommonJS exports.
403
- The default export can be used for, among other things, modifying the named
404
- exports. Named exports of builtin modules are updated only by calling
405
- [` module .syncBuiltinESMExports ()` ][].
409
+ #### No ` require` , ` exports ` or ` module .exports `
406
410
407
- ` ` ` js
408
- import EventEmitter from ' events ' ;
409
- const e = new EventEmitter ();
410
- ` ` `
411
+ In most cases, the ES module ` import ` can be used to load CommonJS modules.
412
+
413
+ If needed, a ` require ` function can be constructed within an ES module using
414
+ [ ` module.createRequire() ` ][].
411
415
416
+ #### No ` __filename` or ` __dirname`
417
+
418
+ These CommonJS variables are not available in ES modules.
419
+
420
+ ` __filename` and ` __dirname` use cases can be replicated via
421
+ [` import.meta.url` ][].
422
+
423
+ #### No JSON Module Loading
424
+
425
+ JSON imports are still experimental and only supported via the
426
+ ` --experimental-json-modules` flag.
427
+
428
+ Local JSON files can be loaded relative to ` import.meta.url` with ` fs` directly:
429
+
430
+ <!-- eslint-skip -->
412
431
` ` ` js
413
- import { readFile } from ' fs' ;
414
- readFile (' ./foo.txt' , (err , source ) => {
415
- if (err) {
416
- console .error (err);
417
- } else {
418
- console .log (source);
419
- }
420
- });
432
+ import { readFile } from ' fs/promises' ;
433
+ const json = JSON .parse (await readFile (new URL (' ./dat.json' , import .meta.url)));
421
434
` ` `
422
435
423
- ` ` ` js
424
- import fs , { readFileSync } from ' fs' ;
425
- import { syncBuiltinESMExports } from ' module' ;
436
+ Alterantively ` module .createRequire ()` can be used.
426
437
427
- fs .readFileSync = () => Buffer .from (' Hello, ESM' );
428
- syncBuiltinESMExports ();
438
+ #### No Native Module Loading
429
439
430
- fs .readFileSync === readFileSync;
431
- ` ` `
440
+ Native modules are not currently supported with ES module imports.
432
441
433
- ## CommonJS, JSON, and native modules
442
+ The can instead be loaded with [` module .createRequire ()` ][] or
443
+ [` process .dlopen ` ][].
434
444
435
- CommonJS, JSON, and native modules can be used with
436
- [` module .createRequire ()` ][].
445
+ #### No ` require .resolve `
437
446
438
- ` ` ` js
439
- // cjs.cjs
440
- module .exports = ' cjs' ;
447
+ Relative resolution can be handled via ` new URL (' ./local' , import .meta.url)` .
441
448
442
- // esm.mjs
443
- import { createRequire } from ' module ' ;
449
+ For a complete ` require.resolve ` replacement, there is a flagged experimental
450
+ [ ` import.meta.resolve ` ][] API.
444
451
445
- const require = createRequire (import .meta.url);
452
+ Alternatively ` module. createRequire() ` can be used.
446
453
447
- const cjs = require (' ./cjs.cjs' );
448
- cjs === ' cjs' ; // true
449
- ` ` `
454
+ #### No ` NODE_PATH`
455
+
456
+ ` NODE_PATH` is not part of resolving ` import` specifiers. Please use symlinks
457
+ if this behavior is desired.
450
458
451
- ## Experimental JSON modules
459
+ #### No ` require.extensions`
460
+
461
+ ` require.extensions` is not used by ` import` . The expectation is that loader
462
+ hooks can provide this workflow in the future.
463
+
464
+ #### No ` require.cache`
465
+
466
+ ` require.cache` is not used by ` import` as the ES module loader has its own
467
+ separate cache.
468
+
469
+ <i id="esm_experimental_json_modules"></i>
470
+
471
+ ## JSON modules
472
+
473
+ > Stability: 1 - Experimental
452
474
453
475
Currently importing JSON modules are only supported in the ` commonjs` mode
454
476
and are loaded using the CJS loader. [WHATWG JSON modules specification][] are
@@ -478,7 +500,11 @@ node index.mjs # fails
478
500
node -- experimental- json- modules index .mjs # works
479
501
` ` `
480
502
481
- ## Experimental Wasm modules
503
+ <i id="esm_experimental_wasm_modules"></i>
504
+
505
+ ## Wasm modules
506
+
507
+ > Stability: 1 - Experimental
482
508
483
509
Importing Web Assembly modules is supported under the
484
510
` -- experimental- wasm- modules` flag, allowing any ` .wasm ` files to be
@@ -502,7 +528,11 @@ node --experimental-wasm-modules index.mjs
502
528
503
529
would provide the exports interface for the instantiation of ` module .wasm ` .
504
530
505
- ## Experimental top-level ` await `
531
+ <i id="esm_experimental_top_level_await"></i>
532
+
533
+ ## Top-level ` await `
534
+
535
+ > Stability: 1 - Experimental
506
536
507
537
The ` await ` keyword may be used in the top level (outside of async functions)
508
538
within modules as per the [ECMAScript Top-Level ` await ` proposal][].
@@ -526,7 +556,11 @@ console.log(five); // Logs `5`
526
556
node b .mjs # works
527
557
` ` `
528
558
529
- ## Experimental loaders
559
+ <i id="esm_experimental_loaders"></i>
560
+
561
+ ## Loaders
562
+
563
+ > Stability: 1 - Experimental
530
564
531
565
**Note: This API is currently being redesigned and will still change.**
532
566
@@ -1237,6 +1271,8 @@ _internal_, _conditions_)
1237
1271
1238
1272
### Customizing ESM specifier resolution algorithm
1239
1273
1274
+ > Stability: 1 - Experimental
1275
+
1240
1276
The current specifier resolution does not support all default behavior of
1241
1277
the CommonJS loader . One of the behavior differences is automatic resolution
1242
1278
of file extensions and the ability to import directories that have an index
@@ -1267,8 +1303,9 @@ success!
1267
1303
[ECMAScript- modules implementation]: https: // github.com/nodejs/modules/blob/master/doc/plan-for-new-modules-implementation.md
1268
1304
[ES Module Integration Proposal for Web Assembly]: https: // github.com/webassembly/esm-integration
1269
1305
[Node .js EP for ES Modules]: https: // github.com/nodejs/node-eps/blob/master/002-es-modules.md
1306
+ [Node .js Module Resolution Algorithm]: #esm_resolver_algorithm_specification
1270
1307
[Terminology]: #esm_terminology
1271
- [Top - Level Await ]: https: // github.com/tc39/proposal-top-level-await
1308
+ [URL ]: https: // url.spec.whatwg.org/
1272
1309
[WHATWG JSON modules specification]: https: // html.spec.whatwg.org/#creating-a-json-module-script
1273
1310
[` "exports"` ]: packages .md #packages_exports
1274
1311
[` "type"` ]: packages .md #packages_type
@@ -1279,15 +1316,19 @@ success!
1279
1316
[` data:` URLs]: https: // developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs
1280
1317
[` export` ]: https: // developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export
1281
1318
[` import()` ]: #esm_import_expressions
1282
- [` import.meta.url` ]: #esm_import_meta
1319
+ [` import.meta.url` ]: #esm_import_meta_url
1320
+ [` import.meta.resolve` ]: #esm_import_meta_resolve_specifier_parent
1283
1321
[` import` ]: https: // developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import
1284
1322
[` module.createRequire()` ]: module .md #module_module_createrequire_filename
1285
1323
[` module.syncBuiltinESMExports()` ]: module .md #module_module_syncbuiltinesmexports
1286
1324
[` package.json` ]: packages .md #packages_node_js_package_json_field_definitions
1325
+ [` process.dlopen` ]: process .md #process_process_dlopen_module_filename_flags
1287
1326
[` transformSource` hook]: #esm_transformsource_source_context_defaulttransformsource
1288
1327
[` string` ]: https: // developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String
1289
1328
[` util.TextDecoder` ]: util .md #util_class_util_textdecoder
1290
1329
[cjs- module - lexer]: https: // github.com/guybedford/cjs-module-lexer/tree/1.0.0
1330
+ [custom https loader]: #esm_https_loader
1291
1331
[special scheme]: https: // url.spec.whatwg.org/#special-scheme
1292
1332
[the official standard format]: https: // tc39.github.io/ecma262/#sec-modules
1293
1333
[transpiler loader example]: #esm_transpiler_loader
1334
+ [url .pathToFileURL ]: url .md #url_url_pathtofileurl_path
0 commit comments