• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Modules: ECMAScript modules
2
3<!--introduced_in=v8.5.0-->
4
5<!-- type=misc -->
6
7<!-- YAML
8added: v8.5.0
9changes:
10  - version:
11    - v18.6.0
12    pr-url: https://github.com/nodejs/node/pull/42623
13    description: Add support for chaining loaders.
14  - version:
15    - v17.1.0
16    - v16.14.0
17    pr-url: https://github.com/nodejs/node/pull/40250
18    description: Add support for import assertions.
19  - version:
20    - v17.0.0
21    - v16.12.0
22    pr-url: https://github.com/nodejs/node/pull/37468
23    description:
24      Consolidate loader hooks, removed `getFormat`, `getSource`,
25      `transformSource`, and `getGlobalPreloadCode` hooks
26      added `load` and `globalPreload` hooks
27      allowed returning `format` from either `resolve` or `load` hooks.
28  - version:
29    - v15.3.0
30    - v14.17.0
31    - v12.22.0
32    pr-url: https://github.com/nodejs/node/pull/35781
33    description: Stabilize modules implementation.
34  - version:
35    - v14.13.0
36    - v12.20.0
37    pr-url: https://github.com/nodejs/node/pull/35249
38    description: Support for detection of CommonJS named exports.
39  - version: v14.8.0
40    pr-url: https://github.com/nodejs/node/pull/34558
41    description: Unflag Top-Level Await.
42  - version:
43    - v14.0.0
44    - v13.14.0
45    - v12.20.0
46    pr-url: https://github.com/nodejs/node/pull/31974
47    description: Remove experimental modules warning.
48  - version:
49    - v13.2.0
50    - v12.17.0
51    pr-url: https://github.com/nodejs/node/pull/29866
52    description: Loading ECMAScript modules no longer requires a command-line flag.
53  - version: v12.0.0
54    pr-url: https://github.com/nodejs/node/pull/26745
55    description:
56      Add support for ES modules using `.js` file extension via `package.json`
57      `"type"` field.
58-->
59
60> Stability: 2 - Stable
61
62## Introduction
63
64<!--name=esm-->
65
66ECMAScript modules are [the official standard format][] to package JavaScript
67code for reuse. Modules are defined using a variety of [`import`][] and
68[`export`][] statements.
69
70The following example of an ES module exports a function:
71
72```js
73// addTwo.mjs
74function addTwo(num) {
75  return num + 2;
76}
77
78export { addTwo };
79```
80
81The following example of an ES module imports the function from `addTwo.mjs`:
82
83```js
84// app.mjs
85import { addTwo } from './addTwo.mjs';
86
87// Prints: 6
88console.log(addTwo(4));
89```
90
91Node.js fully supports ECMAScript modules as they are currently specified and
92provides interoperability between them and its original module format,
93[CommonJS][].
94
95<!-- Anchors to make sure old links find a target -->
96
97<i id="esm_package_json_type_field"></i><i id="esm_package_scope_and_file_extensions"></i><i id="esm_input_type_flag"></i>
98
99## Enabling
100
101<!-- type=misc -->
102
103Node.js has two module systems: [CommonJS][] modules and ECMAScript modules.
104
105Authors can tell Node.js to use the ECMAScript modules loader
106via the `.mjs` file extension, the `package.json` [`"type"`][] field, or the
107[`--input-type`][] flag. Outside of those cases, Node.js will use the CommonJS
108module loader. See [Determining module system][] for more details.
109
110<!-- Anchors to make sure old links find a target -->
111
112<i id="esm_package_entry_points"></i><i id="esm_main_entry_point_export"></i><i id="esm_subpath_exports"></i><i id="esm_package_exports_fallbacks"></i><i id="esm_exports_sugar"></i><i id="esm_conditional_exports"></i><i id="esm_nested_conditions"></i><i id="esm_self_referencing_a_package_using_its_name"></i><i id="esm_internal_package_imports"></i><i id="esm_dual_commonjs_es_module_packages"></i><i id="esm_dual_package_hazard"></i><i id="esm_writing_dual_packages_while_avoiding_or_minimizing_hazards"></i><i id="esm_approach_1_use_an_es_module_wrapper"></i><i id="esm_approach_2_isolate_state"></i>
113
114## Packages
115
116This section was moved to [Modules: Packages](packages.md).
117
118## `import` Specifiers
119
120### Terminology
121
122The _specifier_ of an `import` statement is the string after the `from` keyword,
123e.g. `'node:path'` in `import { sep } from 'node:path'`. Specifiers are also
124used in `export from` statements, and as the argument to an `import()`
125expression.
126
127There are three types of specifiers:
128
129* _Relative specifiers_ like `'./startup.js'` or `'../config.mjs'`. They refer
130  to a path relative to the location of the importing file. _The file extension
131  is always necessary for these._
132
133* _Bare specifiers_ like `'some-package'` or `'some-package/shuffle'`. They can
134  refer to the main entry point of a package by the package name, or a
135  specific feature module within a package prefixed by the package name as per
136  the examples respectively. _Including the file extension is only necessary
137  for packages without an [`"exports"`][] field._
138
139* _Absolute specifiers_ like `'file:///opt/nodejs/config.js'`. They refer
140  directly and explicitly to a full path.
141
142Bare specifier resolutions are handled by the [Node.js module
143resolution and loading algorithm][].
144All other specifier resolutions are always only resolved with
145the standard relative [URL][] resolution semantics.
146
147Like in CommonJS, module files within packages can be accessed by appending a
148path to the package name unless the package's [`package.json`][] contains an
149[`"exports"`][] field, in which case files within packages can only be accessed
150via the paths defined in [`"exports"`][].
151
152For details on these package resolution rules that apply to bare specifiers in
153the Node.js module resolution, see the [packages documentation](packages.md).
154
155### Mandatory file extensions
156
157A file extension must be provided when using the `import` keyword to resolve
158relative or absolute specifiers. Directory indexes (e.g. `'./startup/index.js'`)
159must also be fully specified.
160
161This behavior matches how `import` behaves in browser environments, assuming a
162typically configured server.
163
164### URLs
165
166ES modules are resolved and cached as URLs. This means that special characters
167must be [percent-encoded][], such as `#` with `%23` and `?` with `%3F`.
168
169`file:`, `node:`, and `data:` URL schemes are supported. A specifier like
170`'https://example.com/app.js'` is not supported natively in Node.js unless using
171a [custom HTTPS loader][].
172
173#### `file:` URLs
174
175Modules are loaded multiple times if the `import` specifier used to resolve
176them has a different query or fragment.
177
178```js
179import './foo.mjs?query=1'; // loads ./foo.mjs with query of "?query=1"
180import './foo.mjs?query=2'; // loads ./foo.mjs with query of "?query=2"
181```
182
183The volume root may be referenced via `/`, `//`, or `file:///`. Given the
184differences between [URL][] and path resolution (such as percent encoding
185details), it is recommended to use [url.pathToFileURL][] when importing a path.
186
187#### `data:` imports
188
189<!-- YAML
190added: v12.10.0
191-->
192
193[`data:` URLs][] are supported for importing with the following MIME types:
194
195* `text/javascript` for ES modules
196* `application/json` for JSON
197* `application/wasm` for Wasm
198
199```js
200import 'data:text/javascript,console.log("hello!");';
201import _ from 'data:application/json,"world!"' assert { type: 'json' };
202```
203
204`data:` URLs only resolve [bare specifiers][Terminology] for builtin modules
205and [absolute specifiers][Terminology]. Resolving
206[relative specifiers][Terminology] does not work because `data:` is not a
207[special scheme][]. For example, attempting to load `./foo`
208from `data:text/javascript,import "./foo";` fails to resolve because there
209is no concept of relative resolution for `data:` URLs.
210
211#### `node:` imports
212
213<!-- YAML
214added:
215  - v14.13.1
216  - v12.20.0
217changes:
218  - version:
219      - v16.0.0
220      - v14.18.0
221    pr-url: https://github.com/nodejs/node/pull/37246
222    description: Added `node:` import support to `require(...)`.
223-->
224
225`node:` URLs are supported as an alternative means to load Node.js builtin
226modules. This URL scheme allows for builtin modules to be referenced by valid
227absolute URL strings.
228
229```js
230import fs from 'node:fs/promises';
231```
232
233## Import assertions
234
235<!-- YAML
236added:
237  - v17.1.0
238  - v16.14.0
239-->
240
241> Stability: 1 - Experimental
242
243The [Import Assertions proposal][] adds an inline syntax for module import
244statements to pass on more information alongside the module specifier.
245
246```js
247import fooData from './foo.json' assert { type: 'json' };
248
249const { default: barData } =
250  await import('./bar.json', { assert: { type: 'json' } });
251```
252
253Node.js supports the following `type` values, for which the assertion is
254mandatory:
255
256| Assertion `type` | Needed for       |
257| ---------------- | ---------------- |
258| `'json'`         | [JSON modules][] |
259
260## Builtin modules
261
262[Core modules][] provide named exports of their public API. A
263default export is also provided which is the value of the CommonJS exports.
264The default export can be used for, among other things, modifying the named
265exports. Named exports of builtin modules are updated only by calling
266[`module.syncBuiltinESMExports()`][].
267
268```js
269import EventEmitter from 'node:events';
270const e = new EventEmitter();
271```
272
273```js
274import { readFile } from 'node:fs';
275readFile('./foo.txt', (err, source) => {
276  if (err) {
277    console.error(err);
278  } else {
279    console.log(source);
280  }
281});
282```
283
284```js
285import fs, { readFileSync } from 'node:fs';
286import { syncBuiltinESMExports } from 'node:module';
287import { Buffer } from 'node:buffer';
288
289fs.readFileSync = () => Buffer.from('Hello, ESM');
290syncBuiltinESMExports();
291
292fs.readFileSync === readFileSync;
293```
294
295## `import()` expressions
296
297[Dynamic `import()`][] is supported in both CommonJS and ES modules. In CommonJS
298modules it can be used to load ES modules.
299
300## `import.meta`
301
302* {Object}
303
304The `import.meta` meta property is an `Object` that contains the following
305properties.
306
307### `import.meta.url`
308
309* {string} The absolute `file:` URL of the module.
310
311This is defined exactly the same as it is in browsers providing the URL of the
312current module file.
313
314This enables useful patterns such as relative file loading:
315
316```js
317import { readFileSync } from 'node:fs';
318const buffer = readFileSync(new URL('./data.proto', import.meta.url));
319```
320
321### `import.meta.resolve(specifier[, parent])`
322
323<!--
324added:
325  - v13.9.0
326  - v12.16.2
327changes:
328  - version:
329      - v16.2.0
330      - v14.18.0
331    pr-url: https://github.com/nodejs/node/pull/38587
332    description: Add support for WHATWG `URL` object to `parentURL` parameter.
333-->
334
335> Stability: 1 - Experimental
336
337This feature is only available with the `--experimental-import-meta-resolve`
338command flag enabled.
339
340* `specifier` {string} The module specifier to resolve relative to `parent`.
341* `parent` {string|URL} The absolute parent module URL to resolve from. If none
342  is specified, the value of `import.meta.url` is used as the default.
343* Returns: {Promise}
344
345Provides a module-relative resolution function scoped to each module, returning
346the URL string.
347
348<!-- eslint-skip -->
349
350```js
351const dependencyAsset = await import.meta.resolve('component-lib/asset.css');
352```
353
354`import.meta.resolve` also accepts a second argument which is the parent module
355from which to resolve from:
356
357<!-- eslint-skip -->
358
359```js
360await import.meta.resolve('./dep', import.meta.url);
361```
362
363This function is asynchronous because the ES module resolver in Node.js is
364allowed to be asynchronous.
365
366## Interoperability with CommonJS
367
368### `import` statements
369
370An `import` statement can reference an ES module or a CommonJS module.
371`import` statements are permitted only in ES modules, but dynamic [`import()`][]
372expressions are supported in CommonJS for loading ES modules.
373
374When importing [CommonJS modules](#commonjs-namespaces), the
375`module.exports` object is provided as the default export. Named exports may be
376available, provided by static analysis as a convenience for better ecosystem
377compatibility.
378
379### `require`
380
381The CommonJS module `require` always treats the files it references as CommonJS.
382
383Using `require` to load an ES module is not supported because ES modules have
384asynchronous execution. Instead, use [`import()`][] to load an ES module
385from a CommonJS module.
386
387### CommonJS Namespaces
388
389CommonJS modules consist of a `module.exports` object which can be of any type.
390
391When importing a CommonJS module, it can be reliably imported using the ES
392module default import or its corresponding sugar syntax:
393
394<!-- eslint-disable no-duplicate-imports -->
395
396```js
397import { default as cjs } from 'cjs';
398
399// The following import statement is "syntax sugar" (equivalent but sweeter)
400// for `{ default as cjsSugar }` in the above import statement:
401import cjsSugar from 'cjs';
402
403console.log(cjs);
404console.log(cjs === cjsSugar);
405// Prints:
406//   <module.exports>
407//   true
408```
409
410The ECMAScript Module Namespace representation of a CommonJS module is always
411a namespace with a `default` export key pointing to the CommonJS
412`module.exports` value.
413
414This Module Namespace Exotic Object can be directly observed either when using
415`import * as m from 'cjs'` or a dynamic import:
416
417<!-- eslint-skip -->
418
419```js
420import * as m from 'cjs';
421console.log(m);
422console.log(m === await import('cjs'));
423// Prints:
424//   [Module] { default: <module.exports> }
425//   true
426```
427
428For better compatibility with existing usage in the JS ecosystem, Node.js
429in addition attempts to determine the CommonJS named exports of every imported
430CommonJS module to provide them as separate ES module exports using a static
431analysis process.
432
433For example, consider a CommonJS module written:
434
435```cjs
436// cjs.cjs
437exports.name = 'exported';
438```
439
440The preceding module supports named imports in ES modules:
441
442<!-- eslint-disable no-duplicate-imports -->
443
444```js
445import { name } from './cjs.cjs';
446console.log(name);
447// Prints: 'exported'
448
449import cjs from './cjs.cjs';
450console.log(cjs);
451// Prints: { name: 'exported' }
452
453import * as m from './cjs.cjs';
454console.log(m);
455// Prints: [Module] { default: { name: 'exported' }, name: 'exported' }
456```
457
458As can be seen from the last example of the Module Namespace Exotic Object being
459logged, the `name` export is copied off of the `module.exports` object and set
460directly on the ES module namespace when the module is imported.
461
462Live binding updates or new exports added to `module.exports` are not detected
463for these named exports.
464
465The detection of named exports is based on common syntax patterns but does not
466always correctly detect named exports. In these cases, using the default
467import form described above can be a better option.
468
469Named exports detection covers many common export patterns, reexport patterns
470and build tool and transpiler outputs. See [cjs-module-lexer][] for the exact
471semantics implemented.
472
473### Differences between ES modules and CommonJS
474
475#### No `require`, `exports`, or `module.exports`
476
477In most cases, the ES module `import` can be used to load CommonJS modules.
478
479If needed, a `require` function can be constructed within an ES module using
480[`module.createRequire()`][].
481
482#### No `__filename` or `__dirname`
483
484These CommonJS variables are not available in ES modules.
485
486`__filename` and `__dirname` use cases can be replicated via
487[`import.meta.url`][].
488
489#### No Addon Loading
490
491[Addons][] are not currently supported with ES module imports.
492
493They can instead be loaded with [`module.createRequire()`][] or
494[`process.dlopen`][].
495
496#### No `require.resolve`
497
498Relative resolution can be handled via `new URL('./local', import.meta.url)`.
499
500For a complete `require.resolve` replacement, there is a flagged experimental
501[`import.meta.resolve`][] API.
502
503Alternatively `module.createRequire()` can be used.
504
505#### No `NODE_PATH`
506
507`NODE_PATH` is not part of resolving `import` specifiers. Please use symlinks
508if this behavior is desired.
509
510#### No `require.extensions`
511
512`require.extensions` is not used by `import`. The expectation is that loader
513hooks can provide this workflow in the future.
514
515#### No `require.cache`
516
517`require.cache` is not used by `import` as the ES module loader has its own
518separate cache.
519
520<i id="esm_experimental_json_modules"></i>
521
522## JSON modules
523
524> Stability: 1 - Experimental
525
526JSON files can be referenced by `import`:
527
528```js
529import packageConfig from './package.json' assert { type: 'json' };
530```
531
532The `assert { type: 'json' }` syntax is mandatory; see [Import Assertions][].
533
534The imported JSON only exposes a `default` export. There is no support for named
535exports. A cache entry is created in the CommonJS cache to avoid duplication.
536The same object is returned in CommonJS if the JSON module has already been
537imported from the same path.
538
539<i id="esm_experimental_wasm_modules"></i>
540
541## Wasm modules
542
543> Stability: 1 - Experimental
544
545Importing WebAssembly modules is supported under the
546`--experimental-wasm-modules` flag, allowing any `.wasm` files to be
547imported as normal modules while also supporting their module imports.
548
549This integration is in line with the
550[ES Module Integration Proposal for WebAssembly][].
551
552For example, an `index.mjs` containing:
553
554```js
555import * as M from './module.wasm';
556console.log(M);
557```
558
559executed under:
560
561```bash
562node --experimental-wasm-modules index.mjs
563```
564
565would provide the exports interface for the instantiation of `module.wasm`.
566
567<i id="esm_experimental_top_level_await"></i>
568
569## Top-level `await`
570
571<!-- YAML
572added: v14.8.0
573-->
574
575The `await` keyword may be used in the top level body of an ECMAScript module.
576
577Assuming an `a.mjs` with
578
579```js
580export const five = await Promise.resolve(5);
581```
582
583And a `b.mjs` with
584
585```js
586import { five } from './a.mjs';
587
588console.log(five); // Logs `5`
589```
590
591```bash
592node b.mjs # works
593```
594
595If a top level `await` expression never resolves, the `node` process will exit
596with a `13` [status code][].
597
598```js
599import { spawn } from 'node:child_process';
600import { execPath } from 'node:process';
601
602spawn(execPath, [
603  '--input-type=module',
604  '--eval',
605  // Never-resolving Promise:
606  'await new Promise(() => {})',
607]).once('exit', (code) => {
608  console.log(code); // Logs `13`
609});
610```
611
612## HTTPS and HTTP imports
613
614> Stability: 1 - Experimental
615
616Importing network based modules using `https:` and `http:` is supported under
617the `--experimental-network-imports` flag. This allows web browser-like imports
618to work in Node.js with a few differences due to application stability and
619security concerns that are different when running in a privileged environment
620instead of a browser sandbox.
621
622### Imports are limited to HTTP/1
623
624Automatic protocol negotiation for HTTP/2 and HTTP/3 is not yet supported.
625
626### HTTP is limited to loopback addresses
627
628`http:` is vulnerable to man-in-the-middle attacks and is not allowed to be
629used for addresses outside of the IPv4 address `127.0.0.0/8` (`127.0.0.1` to
630`127.255.255.255`) and the IPv6 address `::1`. Support for `http:` is intended
631to be used for local development.
632
633### Authentication is never sent to the destination server.
634
635`Authorization`, `Cookie`, and `Proxy-Authorization` headers are not sent to the
636server. Avoid including user info in parts of imported URLs. A security model
637for safely using these on the server is being worked on.
638
639### CORS is never checked on the destination server
640
641CORS is designed to allow a server to limit the consumers of an API to a
642specific set of hosts. This is not supported as it does not make sense for a
643server-based implementation.
644
645### Cannot load non-network dependencies
646
647These modules cannot access other modules that are not over `http:` or `https:`.
648To still access local modules while avoiding the security concern, pass in
649references to the local dependencies:
650
651```mjs
652// file.mjs
653import worker_threads from 'node:worker_threads';
654import { configure, resize } from 'https://example.com/imagelib.mjs';
655configure({ worker_threads });
656```
657
658```mjs
659// https://example.com/imagelib.mjs
660let worker_threads;
661export function configure(opts) {
662  worker_threads = opts.worker_threads;
663}
664export function resize(img, size) {
665  // Perform resizing in worker_thread to avoid main thread blocking
666}
667```
668
669### Network-based loading is not enabled by default
670
671For now, the `--experimental-network-imports` flag is required to enable loading
672resources over `http:` or `https:`. In the future, a different mechanism will be
673used to enforce this. Opt-in is required to prevent transitive dependencies
674inadvertently using potentially mutable state that could affect reliability
675of Node.js applications.
676
677<i id="esm_experimental_loaders"></i>
678
679## Loaders
680
681<!-- YAML
682added: v8.8.0
683changes:
684  - version:
685    - v18.6.0
686    pr-url: https://github.com/nodejs/node/pull/42623
687    description: Add support for chaining loaders.
688  - version: v16.12.0
689    pr-url: https://github.com/nodejs/node/pull/37468
690    description: Removed `getFormat`, `getSource`, `transformSource`, and
691                 `globalPreload`; added `load` hook and `getGlobalPreload` hook.
692-->
693
694> Stability: 1 - Experimental
695
696> This API is currently being redesigned and will still change.
697
698<!-- type=misc -->
699
700To customize the default module resolution, loader hooks can optionally be
701provided via a `--experimental-loader ./loader-name.mjs` argument to Node.js.
702
703When hooks are used they apply to the entry point and all `import` calls. They
704won't apply to `require` calls; those still follow [CommonJS][] rules.
705
706Loaders follow the pattern of `--require`:
707
708```console
709node \
710  --experimental-loader unpkg \
711  --experimental-loader http-to-https \
712  --experimental-loader cache-buster
713```
714
715These are called in the following sequence: `cache-buster` calls
716`http-to-https` which calls `unpkg`.
717
718### Hooks
719
720Hooks are part of a chain, even if that chain consists of only one custom
721(user-provided) hook and the default hook, which is always present. Hook
722functions nest: each one must always return a plain object, and chaining happens
723as a result of each function calling `next<hookName>()`, which is a reference
724to the subsequent loader’s hook.
725
726A hook that returns a value lacking a required property triggers an exception.
727A hook that returns without calling `next<hookName>()` _and_ without returning
728`shortCircuit: true` also triggers an exception. These errors are to help
729prevent unintentional breaks in the chain.
730
731#### `resolve(specifier, context, nextResolve)`
732
733<!-- YAML
734changes:
735  - version: v18.6.0
736    pr-url: https://github.com/nodejs/node/pull/42623
737    description: Add support for chaining resolve hooks. Each hook must either
738      call `nextResolve()` or include a `shortCircuit` property set to `true`
739      in its return.
740  - version:
741    - v17.1.0
742    - v16.14.0
743    pr-url: https://github.com/nodejs/node/pull/40250
744    description: Add support for import assertions.
745-->
746
747> The loaders API is being redesigned. This hook may disappear or its
748> signature may change. Do not rely on the API described below.
749
750* `specifier` {string}
751* `context` {Object}
752  * `conditions` {string\[]} Export conditions of the relevant `package.json`
753  * `importAssertions` {Object}
754  * `parentURL` {string|undefined} The module importing this one, or undefined
755    if this is the Node.js entry point
756* `nextResolve` {Function} The subsequent `resolve` hook in the chain, or the
757  Node.js default `resolve` hook after the last user-supplied `resolve` hook
758  * `specifier` {string}
759  * `context` {Object}
760* Returns: {Object}
761  * `format` {string|null|undefined} A hint to the load hook (it might be
762    ignored)
763    `'builtin' | 'commonjs' | 'json' | 'module' | 'wasm'`
764  * `shortCircuit` {undefined|boolean} A signal that this hook intends to
765    terminate the chain of `resolve` hooks. **Default:** `false`
766  * `url` {string} The absolute URL to which this input resolves
767
768The `resolve` hook chain is responsible for resolving file URL for a given
769module specifier and parent URL, and optionally its format (such as `'module'`)
770as a hint to the `load` hook. If a format is specified, the `load` hook is
771ultimately responsible for providing the final `format` value (and it is free to
772ignore the hint provided by `resolve`); if `resolve` provides a `format`, a
773custom `load` hook is required even if only to pass the value to the Node.js
774default `load` hook.
775
776The module specifier is the string in an `import` statement or
777`import()` expression.
778
779The parent URL is the URL of the module that imported this one, or `undefined`
780if this is the main entry point for the application.
781
782The `conditions` property in `context` is an array of conditions for
783[package exports conditions][Conditional Exports] that apply to this resolution
784request. They can be used for looking up conditional mappings elsewhere or to
785modify the list when calling the default resolution logic.
786
787The current [package exports conditions][Conditional Exports] are always in
788the `context.conditions` array passed into the hook. To guarantee _default
789Node.js module specifier resolution behavior_ when calling `defaultResolve`, the
790`context.conditions` array passed to it _must_ include _all_ elements of the
791`context.conditions` array originally passed into the `resolve` hook.
792
793```js
794export async function resolve(specifier, context, nextResolve) {
795  const { parentURL = null } = context;
796
797  if (Math.random() > 0.5) { // Some condition.
798    // For some or all specifiers, do some custom logic for resolving.
799    // Always return an object of the form {url: <string>}.
800    return {
801      shortCircuit: true,
802      url: parentURL ?
803        new URL(specifier, parentURL).href :
804        new URL(specifier).href,
805    };
806  }
807
808  if (Math.random() < 0.5) { // Another condition.
809    // When calling `defaultResolve`, the arguments can be modified. In this
810    // case it's adding another value for matching conditional exports.
811    return nextResolve(specifier, {
812      ...context,
813      conditions: [...context.conditions, 'another-condition'],
814    });
815  }
816
817  // Defer to the next hook in the chain, which would be the
818  // Node.js default resolve if this is the last user-specified loader.
819  return nextResolve(specifier);
820}
821```
822
823#### `load(url, context, nextLoad)`
824
825<!-- YAML
826changes:
827  - version: v18.6.0
828    pr-url: https://github.com/nodejs/node/pull/42623
829    description: Add support for chaining load hooks. Each hook must either
830      call `nextLoad()` or include a `shortCircuit` property set to `true` in
831      its return.
832-->
833
834> The loaders API is being redesigned. This hook may disappear or its
835> signature may change. Do not rely on the API described below.
836
837> In a previous version of this API, this was split across 3 separate, now
838> deprecated, hooks (`getFormat`, `getSource`, and `transformSource`).
839
840* `url` {string} The URL returned by the `resolve` chain
841* `context` {Object}
842  * `conditions` {string\[]} Export conditions of the relevant `package.json`
843  * `format` {string|null|undefined} The format optionally supplied by the
844    `resolve` hook chain
845  * `importAssertions` {Object}
846* `nextLoad` {Function} The subsequent `load` hook in the chain, or the
847  Node.js default `load` hook after the last user-supplied `load` hook
848  * `specifier` {string}
849  * `context` {Object}
850* Returns: {Object}
851  * `format` {string}
852  * `shortCircuit` {undefined|boolean} A signal that this hook intends to
853    terminate the chain of `resolve` hooks. **Default:** `false`
854  * `source` {string|ArrayBuffer|TypedArray} The source for Node.js to evaluate
855
856The `load` hook provides a way to define a custom method of determining how
857a URL should be interpreted, retrieved, and parsed. It is also in charge of
858validating the import assertion.
859
860The final value of `format` must be one of the following:
861
862| `format`     | Description                    | Acceptable types for `source` returned by `load`      |
863| ------------ | ------------------------------ | ----------------------------------------------------- |
864| `'builtin'`  | Load a Node.js builtin module  | Not applicable                                        |
865| `'commonjs'` | Load a Node.js CommonJS module | Not applicable                                        |
866| `'json'`     | Load a JSON file               | { [`string`][], [`ArrayBuffer`][], [`TypedArray`][] } |
867| `'module'`   | Load an ES module              | { [`string`][], [`ArrayBuffer`][], [`TypedArray`][] } |
868| `'wasm'`     | Load a WebAssembly module      | { [`ArrayBuffer`][], [`TypedArray`][] }               |
869
870The value of `source` is ignored for type `'builtin'` because currently it is
871not possible to replace the value of a Node.js builtin (core) module. The value
872of `source` is ignored for type `'commonjs'` because the CommonJS module loader
873does not provide a mechanism for the ES module loader to override the
874[CommonJS module return value](#commonjs-namespaces). This limitation might be
875overcome in the future.
876
877> **Caveat**: The ESM `load` hook and namespaced exports from CommonJS modules
878> are incompatible. Attempting to use them together will result in an empty
879> object from the import. This may be addressed in the future.
880
881> These types all correspond to classes defined in ECMAScript.
882
883* The specific [`ArrayBuffer`][] object is a [`SharedArrayBuffer`][].
884* The specific [`TypedArray`][] object is a [`Uint8Array`][].
885
886If the source value of a text-based format (i.e., `'json'`, `'module'`)
887is not a string, it is converted to a string using [`util.TextDecoder`][].
888
889The `load` hook provides a way to define a custom method for retrieving the
890source code of an ES module specifier. This would allow a loader to potentially
891avoid reading files from disk. It could also be used to map an unrecognized
892format to a supported one, for example `yaml` to `module`.
893
894```js
895export async function load(url, context, nextLoad) {
896  const { format } = context;
897
898  if (Math.random() > 0.5) { // Some condition
899    /*
900      For some or all URLs, do some custom logic for retrieving the source.
901      Always return an object of the form {
902        format: <string>,
903        source: <string|buffer>,
904      }.
905    */
906    return {
907      format,
908      shortCircuit: true,
909      source: '...',
910    };
911  }
912
913  // Defer to the next hook in the chain.
914  return nextLoad(url);
915}
916```
917
918In a more advanced scenario, this can also be used to transform an unsupported
919source to a supported one (see [Examples](#examples) below).
920
921#### `globalPreload()`
922
923<!-- YAML
924changes:
925  - version: v18.6.0
926    pr-url: https://github.com/nodejs/node/pull/42623
927    description: Add support for chaining globalPreload hooks.
928-->
929
930> The loaders API is being redesigned. This hook may disappear or its
931> signature may change. Do not rely on the API described below.
932
933> In a previous version of this API, this hook was named
934> `getGlobalPreloadCode`.
935
936* `context` {Object} Information to assist the preload code
937  * `port` {MessagePort}
938* Returns: {string} Code to run before application startup
939
940Sometimes it might be necessary to run some code inside of the same global
941scope that the application runs in. This hook allows the return of a string
942that is run as a sloppy-mode script on startup.
943
944Similar to how CommonJS wrappers work, the code runs in an implicit function
945scope. The only argument is a `require`-like function that can be used to load
946builtins like "fs": `getBuiltin(request: string)`.
947
948If the code needs more advanced `require` features, it has to construct
949its own `require` using  `module.createRequire()`.
950
951```js
952export function globalPreload(context) {
953  return `\
954globalThis.someInjectedProperty = 42;
955console.log('I just set some globals!');
956
957const { createRequire } = getBuiltin('module');
958const { cwd } = getBuiltin('process');
959
960const require = createRequire(cwd() + '/<preload>');
961// [...]
962`;
963}
964```
965
966In order to allow communication between the application and the loader, another
967argument is provided to the preload code: `port`. This is available as a
968parameter to the loader hook and inside of the source text returned by the hook.
969Some care must be taken in order to properly call [`port.ref()`][] and
970[`port.unref()`][] to prevent a process from being in a state where it won't
971close normally.
972
973```js
974/**
975 * This example has the application context send a message to the loader
976 * and sends the message back to the application context
977 */
978export function globalPreload({ port }) {
979  port.onmessage = (evt) => {
980    port.postMessage(evt.data);
981  };
982  return `\
983    port.postMessage('console.log("I went to the Loader and back");');
984    port.onmessage = (evt) => {
985      eval(evt.data);
986    };
987  `;
988}
989```
990
991### Examples
992
993The various loader hooks can be used together to accomplish wide-ranging
994customizations of the Node.js code loading and evaluation behaviors.
995
996#### HTTPS loader
997
998In current Node.js, specifiers starting with `https://` are experimental (see
999[HTTPS and HTTP imports][]).
1000
1001The loader below registers hooks to enable rudimentary support for such
1002specifiers. While this may seem like a significant improvement to Node.js core
1003functionality, there are substantial downsides to actually using this loader:
1004performance is much slower than loading files from disk, there is no caching,
1005and there is no security.
1006
1007```js
1008// https-loader.mjs
1009import { get } from 'node:https';
1010
1011export function load(url, context, nextLoad) {
1012  // For JavaScript to be loaded over the network, we need to fetch and
1013  // return it.
1014  if (url.startsWith('https://')) {
1015    return new Promise((resolve, reject) => {
1016      get(url, (res) => {
1017        let data = '';
1018        res.setEncoding('utf8');
1019        res.on('data', (chunk) => data += chunk);
1020        res.on('end', () => resolve({
1021          // This example assumes all network-provided JavaScript is ES module
1022          // code.
1023          format: 'module',
1024          shortCircuit: true,
1025          source: data,
1026        }));
1027      }).on('error', (err) => reject(err));
1028    });
1029  }
1030
1031  // Let Node.js handle all other URLs.
1032  return nextLoad(url);
1033}
1034```
1035
1036```js
1037// main.mjs
1038import { VERSION } from 'https://coffeescript.org/browser-compiler-modern/coffeescript.js';
1039
1040console.log(VERSION);
1041```
1042
1043With the preceding loader, running
1044`node --experimental-loader ./https-loader.mjs ./main.mjs`
1045prints the current version of CoffeeScript per the module at the URL in
1046`main.mjs`.
1047
1048#### Transpiler loader
1049
1050Sources that are in formats Node.js doesn't understand can be converted into
1051JavaScript using the [`load` hook][load hook].
1052
1053This is less performant than transpiling source files before running
1054Node.js; a transpiler loader should only be used for development and testing
1055purposes.
1056
1057```js
1058// coffeescript-loader.mjs
1059import { readFile } from 'node:fs/promises';
1060import { dirname, extname, resolve as resolvePath } from 'node:path';
1061import { cwd } from 'node:process';
1062import { fileURLToPath, pathToFileURL } from 'node:url';
1063import CoffeeScript from 'coffeescript';
1064
1065const baseURL = pathToFileURL(`${cwd()}/`).href;
1066
1067export async function load(url, context, nextLoad) {
1068  if (extensionsRegex.test(url)) {
1069    // Now that we patched resolve to let CoffeeScript URLs through, we need to
1070    // tell Node.js what format such URLs should be interpreted as. Because
1071    // CoffeeScript transpiles into JavaScript, it should be one of the two
1072    // JavaScript formats: 'commonjs' or 'module'.
1073
1074    // CoffeeScript files can be either CommonJS or ES modules, so we want any
1075    // CoffeeScript file to be treated by Node.js the same as a .js file at the
1076    // same location. To determine how Node.js would interpret an arbitrary .js
1077    // file, search up the file system for the nearest parent package.json file
1078    // and read its "type" field.
1079    const format = await getPackageType(url);
1080    // When a hook returns a format of 'commonjs', `source` is ignored.
1081    // To handle CommonJS files, a handler needs to be registered with
1082    // `require.extensions` in order to process the files with the CommonJS
1083    // loader. Avoiding the need for a separate CommonJS handler is a future
1084    // enhancement planned for ES module loaders.
1085    if (format === 'commonjs') {
1086      return {
1087        format,
1088        shortCircuit: true,
1089      };
1090    }
1091
1092    const { source: rawSource } = await nextLoad(url, { ...context, format });
1093    // This hook converts CoffeeScript source code into JavaScript source code
1094    // for all imported CoffeeScript files.
1095    const transformedSource = coffeeCompile(rawSource.toString(), url);
1096
1097    return {
1098      format,
1099      shortCircuit: true,
1100      source: transformedSource,
1101    };
1102  }
1103
1104  // Let Node.js handle all other URLs.
1105  return nextLoad(url);
1106}
1107
1108async function getPackageType(url) {
1109  // `url` is only a file path during the first iteration when passed the
1110  // resolved url from the load() hook
1111  // an actual file path from load() will contain a file extension as it's
1112  // required by the spec
1113  // this simple truthy check for whether `url` contains a file extension will
1114  // work for most projects but does not cover some edge-cases (such as
1115  // extensionless files or a url ending in a trailing space)
1116  const isFilePath = !!extname(url);
1117  // If it is a file path, get the directory it's in
1118  const dir = isFilePath ?
1119    dirname(fileURLToPath(url)) :
1120    url;
1121  // Compose a file path to a package.json in the same directory,
1122  // which may or may not exist
1123  const packagePath = resolvePath(dir, 'package.json');
1124  // Try to read the possibly nonexistent package.json
1125  const type = await readFile(packagePath, { encoding: 'utf8' })
1126    .then((filestring) => JSON.parse(filestring).type)
1127    .catch((err) => {
1128      if (err?.code !== 'ENOENT') console.error(err);
1129    });
1130  // Ff package.json existed and contained a `type` field with a value, voila
1131  if (type) return type;
1132  // Otherwise, (if not at the root) continue checking the next directory up
1133  // If at the root, stop and return false
1134  return dir.length > 1 && getPackageType(resolvePath(dir, '..'));
1135}
1136```
1137
1138```coffee
1139# main.coffee
1140import { scream } from './scream.coffee'
1141console.log scream 'hello, world'
1142
1143import { version } from 'node:process'
1144console.log "Brought to you by Node.js version #{version}"
1145```
1146
1147```coffee
1148# scream.coffee
1149export scream = (str) -> str.toUpperCase()
1150```
1151
1152With the preceding loader, running
1153`node --experimental-loader ./coffeescript-loader.mjs main.coffee`
1154causes `main.coffee` to be turned into JavaScript after its source code is
1155loaded from disk but before Node.js executes it; and so on for any `.coffee`,
1156`.litcoffee` or `.coffee.md` files referenced via `import` statements of any
1157loaded file.
1158
1159#### "import map" loader
1160
1161The previous two loaders defined `load` hooks. This is an example of a loader
1162that does its work via the `resolve` hook. This loader reads an
1163`import-map.json` file that specifies which specifiers to override to another
1164URL (this is a very simplistic implemenation of a small subset of the
1165"import maps" specification).
1166
1167```js
1168// import-map-loader.js
1169import fs from 'node:fs/promises';
1170
1171const { imports } = JSON.parse(await fs.readFile('import-map.json'));
1172
1173export async function resolve(specifier, context, nextResolve) {
1174  if (Object.hasOwn(imports, specifier)) {
1175    return nextResolve(imports[specifier], context);
1176  }
1177
1178  return nextResolve(specifier, context);
1179}
1180```
1181
1182Let's assume we have these files:
1183
1184```js
1185// main.js
1186import 'a-module';
1187```
1188
1189```json
1190// import-map.json
1191{
1192  "imports": {
1193    "a-module": "./some-module.js"
1194  }
1195}
1196```
1197
1198```js
1199// some-module.js
1200console.log('some module!');
1201```
1202
1203If you run `node --experimental-loader ./import-map-loader.js main.js`
1204the output will be `some module!`.
1205
1206## Resolution and loading algorithm
1207
1208### Features
1209
1210The default resolver has the following properties:
1211
1212* FileURL-based resolution as is used by ES modules
1213* Relative and absolute URL resolution
1214* No default extensions
1215* No folder mains
1216* Bare specifier package resolution lookup through node\_modules
1217* Does not fail on unknown extensions or protocols
1218* Can optionally provide a hint of the format to the loading phase
1219
1220The default loader has the following properties
1221
1222* Support for builtin module loading via `node:` URLs
1223* Support for "inline" module loading via `data:` URLs
1224* Support for `file:` module loading
1225* Fails on any other URL protocol
1226* Fails on unknown extensions for `file:` loading
1227  (supports only `.cjs`, `.js`, and `.mjs`)
1228
1229### Resolution algorithm
1230
1231The algorithm to load an ES module specifier is given through the
1232**ESM\_RESOLVE** method below. It returns the resolved URL for a
1233module specifier relative to a parentURL.
1234
1235The resolution algorithm determines the full resolved URL for a module
1236load, along with its suggested module format. The resolution algorithm
1237does not determine whether the resolved URL protocol can be loaded,
1238or whether the file extensions are permitted, instead these validations
1239are applied by Node.js during the load phase
1240(for example, if it was asked to load a URL that has a protocol that is
1241not `file:`, `data:`, `node:`, or if `--experimental-network-imports`
1242is enabled, `https:`).
1243
1244The algorithm also tries to determine the format of the file based
1245on the extension (see `ESM_FILE_FORMAT` algorithm below). If it does
1246not recognize the file extension (eg if it is not `.mjs`, `.cjs`, or
1247`.json`), then a format of `undefined` is returned,
1248which will throw during the load phase.
1249
1250The algorithm to determine the module format of a resolved URL is
1251provided by **ESM\_FILE\_FORMAT**, which returns the unique module
1252format for any file. The _"module"_ format is returned for an ECMAScript
1253Module, while the _"commonjs"_ format is used to indicate loading through the
1254legacy CommonJS loader. Additional formats such as _"addon"_ can be extended in
1255future updates.
1256
1257In the following algorithms, all subroutine errors are propagated as errors
1258of these top-level routines unless stated otherwise.
1259
1260_defaultConditions_ is the conditional environment name array,
1261`["node", "import"]`.
1262
1263The resolver can throw the following errors:
1264
1265* _Invalid Module Specifier_: Module specifier is an invalid URL, package name
1266  or package subpath specifier.
1267* _Invalid Package Configuration_: package.json configuration is invalid or
1268  contains an invalid configuration.
1269* _Invalid Package Target_: Package exports or imports define a target module
1270  for the package that is an invalid type or string target.
1271* _Package Path Not Exported_: Package exports do not define or permit a target
1272  subpath in the package for the given module.
1273* _Package Import Not Defined_: Package imports do not define the specifier.
1274* _Module Not Found_: The package or module requested does not exist.
1275* _Unsupported Directory Import_: The resolved path corresponds to a directory,
1276  which is not a supported target for module imports.
1277
1278### Resolution Algorithm Specification
1279
1280**ESM\_RESOLVE**(_specifier_, _parentURL_)
1281
1282> 1. Let _resolved_ be **undefined**.
1283> 2. If _specifier_ is a valid URL, then
1284>    1. Set _resolved_ to the result of parsing and reserializing
1285>       _specifier_ as a URL.
1286> 3. Otherwise, if _specifier_ starts with _"/"_, _"./"_, or _"../"_, then
1287>    1. Set _resolved_ to the URL resolution of _specifier_ relative to
1288>       _parentURL_.
1289> 4. Otherwise, if _specifier_ starts with _"#"_, then
1290>    1. Set _resolved_ to the result of
1291>       **PACKAGE\_IMPORTS\_RESOLVE**(_specifier_,
1292>       _parentURL_, _defaultConditions_).
1293> 5. Otherwise,
1294>    1. Note: _specifier_ is now a bare specifier.
1295>    2. Set _resolved_ the result of
1296>       **PACKAGE\_RESOLVE**(_specifier_, _parentURL_).
1297> 6. Let _format_ be **undefined**.
1298> 7. If _resolved_ is a _"file:"_ URL, then
1299>    1. If _resolved_ contains any percent encodings of _"/"_ or _"\\"_ (_"%2F"_
1300>       and _"%5C"_ respectively), then
1301>       1. Throw an _Invalid Module Specifier_ error.
1302>    2. If the file at _resolved_ is a directory, then
1303>       1. Throw an _Unsupported Directory Import_ error.
1304>    3. If the file at _resolved_ does not exist, then
1305>       1. Throw a _Module Not Found_ error.
1306>    4. Set _resolved_ to the real path of _resolved_, maintaining the
1307>       same URL querystring and fragment components.
1308>    5. Set _format_ to the result of **ESM\_FILE\_FORMAT**(_resolved_).
1309> 8. Otherwise,
1310>    1. Set _format_ the module format of the content type associated with the
1311>       URL _resolved_.
1312> 9. Return _format_ and _resolved_ to the loading phase
1313
1314**PACKAGE\_RESOLVE**(_packageSpecifier_, _parentURL_)
1315
1316> 1. Let _packageName_ be **undefined**.
1317> 2. If _packageSpecifier_ is an empty string, then
1318>    1. Throw an _Invalid Module Specifier_ error.
1319> 3. If _packageSpecifier_ is a Node.js builtin module name, then
1320>    1. Return the string _"node:"_ concatenated with _packageSpecifier_.
1321> 4. If _packageSpecifier_ does not start with _"@"_, then
1322>    1. Set _packageName_ to the substring of _packageSpecifier_ until the first
1323>       _"/"_ separator or the end of the string.
1324> 5. Otherwise,
1325>    1. If _packageSpecifier_ does not contain a _"/"_ separator, then
1326>       1. Throw an _Invalid Module Specifier_ error.
1327>    2. Set _packageName_ to the substring of _packageSpecifier_
1328>       until the second _"/"_ separator or the end of the string.
1329> 6. If _packageName_ starts with _"."_ or contains _"\\"_ or _"%"_, then
1330>    1. Throw an _Invalid Module Specifier_ error.
1331> 7. Let _packageSubpath_ be _"."_ concatenated with the substring of
1332>    _packageSpecifier_ from the position at the length of _packageName_.
1333> 8. If _packageSubpath_ ends in _"/"_, then
1334>    1. Throw an _Invalid Module Specifier_ error.
1335> 9. Let _selfUrl_ be the result of
1336>    **PACKAGE\_SELF\_RESOLVE**(_packageName_, _packageSubpath_, _parentURL_).
1337> 10. If _selfUrl_ is not **undefined**, return _selfUrl_.
1338> 11. While _parentURL_ is not the file system root,
1339>     1. Let _packageURL_ be the URL resolution of _"node\_modules/"_
1340>        concatenated with _packageSpecifier_, relative to _parentURL_.
1341>     2. Set _parentURL_ to the parent folder URL of _parentURL_.
1342>     3. If the folder at _packageURL_ does not exist, then
1343>        1. Continue the next loop iteration.
1344>     4. Let _pjson_ be the result of **READ\_PACKAGE\_JSON**(_packageURL_).
1345>     5. If _pjson_ is not **null** and _pjson_._exports_ is not **null** or
1346>        **undefined**, then
1347>        1. Return the result of **PACKAGE\_EXPORTS\_RESOLVE**(_packageURL_,
1348>           _packageSubpath_, _pjson.exports_, _defaultConditions_).
1349>     6. Otherwise, if _packageSubpath_ is equal to _"."_, then
1350>        1. If _pjson.main_ is a string, then
1351>           1. Return the URL resolution of _main_ in _packageURL_.
1352>     7. Otherwise,
1353>        1. Return the URL resolution of _packageSubpath_ in _packageURL_.
1354> 12. Throw a _Module Not Found_ error.
1355
1356**PACKAGE\_SELF\_RESOLVE**(_packageName_, _packageSubpath_, _parentURL_)
1357
1358> 1. Let _packageURL_ be the result of **LOOKUP\_PACKAGE\_SCOPE**(_parentURL_).
1359> 2. If _packageURL_ is **null**, then
1360>    1. Return **undefined**.
1361> 3. Let _pjson_ be the result of **READ\_PACKAGE\_JSON**(_packageURL_).
1362> 4. If _pjson_ is **null** or if _pjson_._exports_ is **null** or
1363>    **undefined**, then
1364>    1. Return **undefined**.
1365> 5. If _pjson.name_ is equal to _packageName_, then
1366>    1. Return the result of **PACKAGE\_EXPORTS\_RESOLVE**(_packageURL_,
1367>       _packageSubpath_, _pjson.exports_, _defaultConditions_).
1368> 6. Otherwise, return **undefined**.
1369
1370**PACKAGE\_EXPORTS\_RESOLVE**(_packageURL_, _subpath_, _exports_, _conditions_)
1371
1372> 1. If _exports_ is an Object with both a key starting with _"."_ and a key not
1373>    starting with _"."_, throw an _Invalid Package Configuration_ error.
1374> 2. If _subpath_ is equal to _"."_, then
1375>    1. Let _mainExport_ be **undefined**.
1376>    2. If _exports_ is a String or Array, or an Object containing no keys
1377>       starting with _"."_, then
1378>       1. Set _mainExport_ to _exports_.
1379>    3. Otherwise if _exports_ is an Object containing a _"."_ property, then
1380>       1. Set _mainExport_ to _exports_\[_"."_].
1381>    4. If _mainExport_ is not **undefined**, then
1382>       1. Let _resolved_ be the result of **PACKAGE\_TARGET\_RESOLVE**(
1383>          _packageURL_, _mainExport_, **null**, **false**, _conditions_).
1384>       2. If _resolved_ is not **null** or **undefined**, return _resolved_.
1385> 3. Otherwise, if _exports_ is an Object and all keys of _exports_ start with
1386>    _"."_, then
1387>    1. Let _matchKey_ be the string _"./"_ concatenated with _subpath_.
1388>    2. Let _resolved_ be the result of **PACKAGE\_IMPORTS\_EXPORTS\_RESOLVE**(
1389>       _matchKey_, _exports_, _packageURL_, **false**, _conditions_).
1390>    3. If _resolved_ is not **null** or **undefined**, return _resolved_.
1391> 4. Throw a _Package Path Not Exported_ error.
1392
1393**PACKAGE\_IMPORTS\_RESOLVE**(_specifier_, _parentURL_, _conditions_)
1394
1395> 1. Assert: _specifier_ begins with _"#"_.
1396> 2. If _specifier_ is exactly equal to _"#"_ or starts with _"#/"_, then
1397>    1. Throw an _Invalid Module Specifier_ error.
1398> 3. Let _packageURL_ be the result of **LOOKUP\_PACKAGE\_SCOPE**(_parentURL_).
1399> 4. If _packageURL_ is not **null**, then
1400>    1. Let _pjson_ be the result of **READ\_PACKAGE\_JSON**(_packageURL_).
1401>    2. If _pjson.imports_ is a non-null Object, then
1402>       1. Let _resolved_ be the result of
1403>          **PACKAGE\_IMPORTS\_EXPORTS\_RESOLVE**(
1404>          _specifier_, _pjson.imports_, _packageURL_, **true**, _conditions_).
1405>       2. If _resolved_ is not **null** or **undefined**, return _resolved_.
1406> 5. Throw a _Package Import Not Defined_ error.
1407
1408**PACKAGE\_IMPORTS\_EXPORTS\_RESOLVE**(_matchKey_, _matchObj_, _packageURL_,
1409_isImports_, _conditions_)
1410
1411> 1. If _matchKey_ is a key of _matchObj_ and does not contain _"\*"_, then
1412>    1. Let _target_ be the value of _matchObj_\[_matchKey_].
1413>    2. Return the result of **PACKAGE\_TARGET\_RESOLVE**(_packageURL_,
1414>       _target_, **null**, _isImports_, _conditions_).
1415> 2. Let _expansionKeys_ be the list of keys of _matchObj_ containing only a
1416>    single _"\*"_, sorted by the sorting function **PATTERN\_KEY\_COMPARE**
1417>    which orders in descending order of specificity.
1418> 3. For each key _expansionKey_ in _expansionKeys_, do
1419>    1. Let _patternBase_ be the substring of _expansionKey_ up to but excluding
1420>       the first _"\*"_ character.
1421>    2. If _matchKey_ starts with but is not equal to _patternBase_, then
1422>       1. Let _patternTrailer_ be the substring of _expansionKey_ from the
1423>          index after the first _"\*"_ character.
1424>       2. If _patternTrailer_ has zero length, or if _matchKey_ ends with
1425>          _patternTrailer_ and the length of _matchKey_ is greater than or
1426>          equal to the length of _expansionKey_, then
1427>          1. Let _target_ be the value of _matchObj_\[_expansionKey_].
1428>          2. Let _patternMatch_ be the substring of _matchKey_ starting at the
1429>             index of the length of _patternBase_ up to the length of
1430>             _matchKey_ minus the length of _patternTrailer_.
1431>          3. Return the result of **PACKAGE\_TARGET\_RESOLVE**(_packageURL_,
1432>             _target_, _patternMatch_, _isImports_, _conditions_).
1433> 4. Return **null**.
1434
1435**PATTERN\_KEY\_COMPARE**(_keyA_, _keyB_)
1436
1437> 1. Assert: _keyA_ ends with _"/"_ or contains only a single _"\*"_.
1438> 2. Assert: _keyB_ ends with _"/"_ or contains only a single _"\*"_.
1439> 3. Let _baseLengthA_ be the index of _"\*"_ in _keyA_ plus one, if _keyA_
1440>    contains _"\*"_, or the length of _keyA_ otherwise.
1441> 4. Let _baseLengthB_ be the index of _"\*"_ in _keyB_ plus one, if _keyB_
1442>    contains _"\*"_, or the length of _keyB_ otherwise.
1443> 5. If _baseLengthA_ is greater than _baseLengthB_, return -1.
1444> 6. If _baseLengthB_ is greater than _baseLengthA_, return 1.
1445> 7. If _keyA_ does not contain _"\*"_, return 1.
1446> 8. If _keyB_ does not contain _"\*"_, return -1.
1447> 9. If the length of _keyA_ is greater than the length of _keyB_, return -1.
1448> 10. If the length of _keyB_ is greater than the length of _keyA_, return 1.
1449> 11. Return 0.
1450
1451**PACKAGE\_TARGET\_RESOLVE**(_packageURL_, _target_, _patternMatch_,
1452_isImports_, _conditions_)
1453
1454> 1. If _target_ is a String, then
1455>    1. If _target_ does not start with _"./"_, then
1456>       1. If _isImports_ is **false**, or if _target_ starts with _"../"_ or
1457>          _"/"_, or if _target_ is a valid URL, then
1458>          1. Throw an _Invalid Package Target_ error.
1459>       2. If _patternMatch_ is a String, then
1460>          1. Return **PACKAGE\_RESOLVE**(_target_ with every instance of _"\*"_
1461>             replaced by _patternMatch_, _packageURL_ + _"/"_).
1462>       3. Return **PACKAGE\_RESOLVE**(_target_, _packageURL_ + _"/"_).
1463>    2. If _target_ split on _"/"_ or _"\\"_ contains any _""_, _"."_, _".."_,
1464>       or _"node\_modules"_ segments after the first _"."_ segment, case
1465>       insensitive and including percent encoded variants, throw an _Invalid
1466>       Package Target_ error.
1467>    3. Let _resolvedTarget_ be the URL resolution of the concatenation of
1468>       _packageURL_ and _target_.
1469>    4. Assert: _resolvedTarget_ is contained in _packageURL_.
1470>    5. If _patternMatch_ is **null**, then
1471>       1. Return _resolvedTarget_.
1472>    6. If _patternMatch_ split on _"/"_ or _"\\"_ contains any _""_, _"."_,
1473>       _".."_, or _"node\_modules"_ segments, case insensitive and including
1474>       percent encoded variants, throw an _Invalid Module Specifier_ error.
1475>    7. Return the URL resolution of _resolvedTarget_ with every instance of
1476>       _"\*"_ replaced with _patternMatch_.
1477> 2. Otherwise, if _target_ is a non-null Object, then
1478>    1. If _exports_ contains any index property keys, as defined in ECMA-262
1479>       [6.1.7 Array Index][], throw an _Invalid Package Configuration_ error.
1480>    2. For each property _p_ of _target_, in object insertion order as,
1481>       1. If _p_ equals _"default"_ or _conditions_ contains an entry for _p_,
1482>          then
1483>          1. Let _targetValue_ be the value of the _p_ property in _target_.
1484>          2. Let _resolved_ be the result of **PACKAGE\_TARGET\_RESOLVE**(
1485>             _packageURL_, _targetValue_, _patternMatch_, _isImports_,
1486>             _conditions_).
1487>          3. If _resolved_ is equal to **undefined**, continue the loop.
1488>          4. Return _resolved_.
1489>    3. Return **undefined**.
1490> 3. Otherwise, if _target_ is an Array, then
1491>    1. If \_target.length is zero, return **null**.
1492>    2. For each item _targetValue_ in _target_, do
1493>       1. Let _resolved_ be the result of **PACKAGE\_TARGET\_RESOLVE**(
1494>          _packageURL_, _targetValue_, _patternMatch_, _isImports_,
1495>          _conditions_), continuing the loop on any _Invalid Package Target_
1496>          error.
1497>       2. If _resolved_ is **undefined**, continue the loop.
1498>       3. Return _resolved_.
1499>    3. Return or throw the last fallback resolution **null** return or error.
1500> 4. Otherwise, if _target_ is _null_, return **null**.
1501> 5. Otherwise throw an _Invalid Package Target_ error.
1502
1503**ESM\_FILE\_FORMAT**(_url_)
1504
1505> 1. Assert: _url_ corresponds to an existing file.
1506> 2. If _url_ ends in _".mjs"_, then
1507>    1. Return _"module"_.
1508> 3. If _url_ ends in _".cjs"_, then
1509>    1. Return _"commonjs"_.
1510> 4. If _url_ ends in _".json"_, then
1511>    1. Return _"json"_.
1512> 5. Let _packageURL_ be the result of **LOOKUP\_PACKAGE\_SCOPE**(_url_).
1513> 6. Let _pjson_ be the result of **READ\_PACKAGE\_JSON**(_packageURL_).
1514> 7. If _pjson?.type_ exists and is _"module"_, then
1515>    1. If _url_ ends in _".js"_, then
1516>       1. Return _"module"_.
1517>    2. Return **undefined**.
1518> 8. Otherwise,
1519>    1. Return **undefined**.
1520
1521**LOOKUP\_PACKAGE\_SCOPE**(_url_)
1522
1523> 1. Let _scopeURL_ be _url_.
1524> 2. While _scopeURL_ is not the file system root,
1525>    1. Set _scopeURL_ to the parent URL of _scopeURL_.
1526>    2. If _scopeURL_ ends in a _"node\_modules"_ path segment, return **null**.
1527>    3. Let _pjsonURL_ be the resolution of _"package.json"_ within
1528>       _scopeURL_.
1529>    4. if the file at _pjsonURL_ exists, then
1530>       1. Return _scopeURL_.
1531> 3. Return **null**.
1532
1533**READ\_PACKAGE\_JSON**(_packageURL_)
1534
1535> 1. Let _pjsonURL_ be the resolution of _"package.json"_ within _packageURL_.
1536> 2. If the file at _pjsonURL_ does not exist, then
1537>    1. Return **null**.
1538> 3. If the file at _packageURL_ does not parse as valid JSON, then
1539>    1. Throw an _Invalid Package Configuration_ error.
1540> 4. Return the parsed JSON source of the file at _pjsonURL_.
1541
1542### Customizing ESM specifier resolution algorithm
1543
1544> Stability: 1 - Experimental
1545
1546> Do not rely on this flag. We plan to remove it once the
1547> [Loaders API][] has advanced to the point that equivalent functionality can
1548> be achieved via custom loaders.
1549
1550The current specifier resolution does not support all default behavior of
1551the CommonJS loader. One of the behavior differences is automatic resolution
1552of file extensions and the ability to import directories that have an index
1553file.
1554
1555The `--experimental-specifier-resolution=[mode]` flag can be used to customize
1556the extension resolution algorithm. The default mode is `explicit`, which
1557requires the full path to a module be provided to the loader. To enable the
1558automatic extension resolution and importing from directories that include an
1559index file use the `node` mode.
1560
1561```console
1562$ node index.mjs
1563success!
1564$ node index # Failure!
1565Error: Cannot find module
1566$ node --experimental-specifier-resolution=node index
1567success!
1568```
1569
1570<!-- Note: The cjs-module-lexer link should be kept in-sync with the deps version -->
1571
1572[6.1.7 Array Index]: https://tc39.es/ecma262/#integer-index
1573[Addons]: addons.md
1574[CommonJS]: modules.md
1575[Conditional exports]: packages.md#conditional-exports
1576[Core modules]: modules.md#core-modules
1577[Determining module system]: packages.md#determining-module-system
1578[Dynamic `import()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import
1579[ES Module Integration Proposal for WebAssembly]: https://github.com/webassembly/esm-integration
1580[HTTPS and HTTP imports]: #https-and-http-imports
1581[Import Assertions]: #import-assertions
1582[Import Assertions proposal]: https://github.com/tc39/proposal-import-assertions
1583[JSON modules]: #json-modules
1584[Loaders API]: #loaders
1585[Node.js Module Resolution And Loading Algorithm]: #resolution-algorithm-specification
1586[Terminology]: #terminology
1587[URL]: https://url.spec.whatwg.org/
1588[`"exports"`]: packages.md#exports
1589[`"type"`]: packages.md#type
1590[`--input-type`]: cli.md#--input-typetype
1591[`ArrayBuffer`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer
1592[`SharedArrayBuffer`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer
1593[`TypedArray`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray
1594[`Uint8Array`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array
1595[`data:` URLs]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs
1596[`export`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export
1597[`import()`]: #import-expressions
1598[`import.meta.resolve`]: #importmetaresolvespecifier-parent
1599[`import.meta.url`]: #importmetaurl
1600[`import`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import
1601[`module.createRequire()`]: module.md#modulecreaterequirefilename
1602[`module.syncBuiltinESMExports()`]: module.md#modulesyncbuiltinesmexports
1603[`package.json`]: packages.md#nodejs-packagejson-field-definitions
1604[`port.ref()`]: https://nodejs.org/dist/latest-v17.x/docs/api/worker_threads.html#portref
1605[`port.unref()`]: https://nodejs.org/dist/latest-v17.x/docs/api/worker_threads.html#portunref
1606[`process.dlopen`]: process.md#processdlopenmodule-filename-flags
1607[`string`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String
1608[`util.TextDecoder`]: util.md#class-utiltextdecoder
1609[cjs-module-lexer]: https://github.com/nodejs/cjs-module-lexer/tree/1.2.2
1610[custom https loader]: #https-loader
1611[load hook]: #loadurl-context-nextload
1612[percent-encoded]: url.md#percent-encoding-in-urls
1613[special scheme]: https://url.spec.whatwg.org/#special-scheme
1614[status code]: process.md#exit-codes
1615[the official standard format]: https://tc39.github.io/ecma262/#sec-modules
1616[url.pathToFileURL]: url.md#urlpathtofileurlpath
1617