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