1# Modules: ECMAScript modules 2 3<!--introduced_in=v8.5.0--> 4<!-- type=misc --> 5<!-- YAML 6added: v8.5.0 7changes: 8 - version: 9 - v14.17.0 10 pr-url: https://github.com/nodejs/node/pull/35781 11 description: Stabilize modules implementation. 12 - version: 13 - v14.13.0 14 pr-url: https://github.com/nodejs/node/pull/35249 15 description: Support for detection of CommonJS named exports. 16 - version: v14.8.0 17 pr-url: https://github.com/nodejs/node/pull/34558 18 description: Unflag Top-Level Await. 19 - version: 20 - v14.0.0 21 - v13.14.0 22 pr-url: https://github.com/nodejs/node/pull/31974 23 description: Remove experimental modules warning. 24 - version: 25 - v13.2.0 26 - v12.17.0 27 pr-url: https://github.com/nodejs/node/pull/29866 28 description: Loading ECMAScript modules no longer requires a command-line flag. 29 - version: v12.0.0 30 pr-url: https://github.com/nodejs/node/pull/26745 31 description: 32 Add support for ES modules using `.js` file extension via `package.json` 33 `"type"` field. 34--> 35 36> Stability: 2 - Stable 37 38## Introduction 39 40<!--name=esm--> 41 42ECMAScript modules are [the official standard format][] to package JavaScript 43code for reuse. Modules are defined using a variety of [`import`][] and 44[`export`][] statements. 45 46The following example of an ES module exports a function: 47 48```js 49// addTwo.mjs 50function addTwo(num) { 51 return num + 2; 52} 53 54export { addTwo }; 55``` 56 57The following example of an ES module imports the function from `addTwo.mjs`: 58 59```js 60// app.mjs 61import { addTwo } from './addTwo.mjs'; 62 63// Prints: 6 64console.log(addTwo(4)); 65``` 66 67Node.js fully supports ECMAScript modules as they are currently specified and 68provides interoperability between them and its original module format, 69[CommonJS][]. 70 71<!-- Anchors to make sure old links find a target --> 72<i id="esm_package_json_type_field"></i> 73<i id="esm_package_scope_and_file_extensions"></i> 74<i id="esm_input_type_flag"></i> 75 76## Enabling 77 78<!-- type=misc --> 79 80Node.js treats JavaScript code as CommonJS modules by default. 81Authors can tell Node.js to treat JavaScript code as ECMAScript modules 82via the `.mjs` file extension, the `package.json` [`"type"`][] field, or the 83`--input-type` flag. See 84[Modules: Packages](packages.md#packages_determining_module_system) for more 85details. 86 87<!-- Anchors to make sure old links find a target --> 88<i id="esm_package_entry_points"></i> 89<i id="esm_main_entry_point_export"></i> 90<i id="esm_subpath_exports"></i> 91<i id="esm_package_exports_fallbacks"></i> 92<i id="esm_exports_sugar"></i> 93<i id="esm_conditional_exports"></i> 94<i id="esm_nested_conditions"></i> 95<i id="esm_self_referencing_a_package_using_its_name"></i> 96<i id="esm_internal_package_imports"></i> 97<i id="esm_dual_commonjs_es_module_packages"></i> 98<i id="esm_dual_package_hazard"></i> 99<i id="esm_writing_dual_packages_while_avoiding_or_minimizing_hazards"></i> 100<i id="esm_approach_1_use_an_es_module_wrapper"></i> 101<i id="esm_approach_2_isolate_state"></i> 102 103## Packages 104 105This section was moved to [Modules: Packages](packages.md). 106 107## `import` Specifiers 108 109### Terminology 110 111The _specifier_ of an `import` statement is the string after the `from` keyword, 112e.g. `'path'` in `import { sep } from 'path'`. Specifiers are also used in 113`export from` statements, and as the argument to an `import()` expression. 114 115There are three types of specifiers: 116 117* _Relative specifiers_ like `'./startup.js'` or `'../config.mjs'`. They refer 118 to a path relative to the location of the importing file. _The file extension 119 is always necessary for these._ 120 121* _Bare specifiers_ like `'some-package'` or `'some-package/shuffle'`. They can 122 refer to the main entry point of a package by the package name, or a 123 specific feature module within a package prefixed by the package name as per 124 the examples respectively. _Including the file extension is only necessary 125 for packages without an [`"exports"`][] field._ 126 127* _Absolute specifiers_ like `'file:///opt/nodejs/config.js'`. They refer 128 directly and explicitly to a full path. 129 130Bare specifier resolutions are handled by the [Node.js module resolution 131algorithm][]. All other specifier resolutions are always only resolved with 132the standard relative [URL][] resolution semantics. 133 134Like in CommonJS, module files within packages can be accessed by appending a 135path to the package name unless the package’s [`package.json`][] contains an 136[`"exports"`][] field, in which case files within packages can only be accessed 137via the paths defined in [`"exports"`][]. 138 139For details on these package resolution rules that apply to bare specifiers in 140the Node.js module resolution, see the [packages documentation](packages.md). 141 142### Mandatory file extensions 143 144A file extension must be provided when using the `import` keyword to resolve 145relative or absolute specifiers. Directory indexes (e.g. `'./startup/index.js'`) 146must also be fully specified. 147 148This behavior matches how `import` behaves in browser environments, assuming a 149typically configured server. 150 151### URLs 152 153ES modules are resolved and cached as URLs. This means that files containing 154special characters such as `#` and `?` need to be escaped. 155 156`file:`, `node:`, and `data:` URL schemes are supported. A specifier like 157`'https://example.com/app.js'` is not supported natively in Node.js unless using 158a [custom HTTPS loader][]. 159 160#### `file:` URLs 161 162Modules are loaded multiple times if the `import` specifier used to resolve 163them has a different query or fragment. 164 165```js 166import './foo.mjs?query=1'; // loads ./foo.mjs with query of "?query=1" 167import './foo.mjs?query=2'; // loads ./foo.mjs with query of "?query=2" 168``` 169 170The volume root may be referenced via `/`, `//` or `file:///`. Given the 171differences between [URL][] and path resolution (such as percent encoding 172details), it is recommended to use [url.pathToFileURL][] when importing a path. 173 174#### `data:` Imports 175 176<!-- YAML 177added: v12.10.0 178--> 179 180[`data:` URLs][] are supported for importing with the following MIME types: 181 182* `text/javascript` for ES Modules 183* `application/json` for JSON (requires [`--experimental-json-modules`](cli.md#cli_experimental_json_modules) flag) 184* `application/wasm` for Wasm (requires [`--experimental-wasm-modules`](cli.md#cli_experimental_wasm_modules) flag) 185 186`data:` URLs only resolve [_Bare specifiers_][Terminology] for builtin modules 187and [_Absolute specifiers_][Terminology]. Resolving 188[_Relative specifiers_][Terminology] does not work because `data:` is not a 189[special scheme][]. For example, attempting to load `./foo` 190from `data:text/javascript,import "./foo";` fails to resolve because there 191is no concept of relative resolution for `data:` URLs. An example of a `data:` 192URLs being used is: 193 194```js 195import 'data:text/javascript,console.log("hello!");'; 196import _ from 'data:application/json,"world!"'; 197``` 198 199#### `node:` Imports 200 201<!-- YAML 202added: 203 - v14.13.1 204 - v12.20.0 205changes: 206 - version: v14.18.0 207 pr-url: https://github.com/nodejs/node/pull/37246 208 description: Added `node:` import support to `require(...)`. 209--> 210 211`node:` URLs are supported as an alternative means to load Node.js builtin 212modules. This URL scheme allows for builtin modules to be referenced by valid 213absolute URL strings. 214 215```js 216import fs from 'node:fs/promises'; 217``` 218 219## Builtin modules 220 221[Core modules][] provide named exports of their public API. A 222default export is also provided which is the value of the CommonJS exports. 223The default export can be used for, among other things, modifying the named 224exports. Named exports of builtin modules are updated only by calling 225[`module.syncBuiltinESMExports()`][]. 226 227```js 228import EventEmitter from 'events'; 229const e = new EventEmitter(); 230``` 231 232```js 233import { readFile } from 'fs'; 234readFile('./foo.txt', (err, source) => { 235 if (err) { 236 console.error(err); 237 } else { 238 console.log(source); 239 } 240}); 241``` 242 243```js 244import fs, { readFileSync } from 'fs'; 245import { syncBuiltinESMExports } from 'module'; 246 247fs.readFileSync = () => Buffer.from('Hello, ESM'); 248syncBuiltinESMExports(); 249 250fs.readFileSync === readFileSync; 251``` 252 253## `import()` expressions 254 255[Dynamic `import()`][] is supported in both CommonJS and ES modules. In CommonJS 256modules it can be used to load ES modules. 257 258## `import.meta` 259 260* {Object} 261 262The `import.meta` meta property is an `Object` that contains the following 263properties. 264 265### `import.meta.url` 266 267* {string} The absolute `file:` URL of the module. 268 269This is defined exactly the same as it is in browsers providing the URL of the 270current module file. 271 272This enables useful patterns such as relative file loading: 273 274```js 275import { readFileSync } from 'fs'; 276const buffer = readFileSync(new URL('./data.proto', import.meta.url)); 277``` 278 279### `import.meta.resolve(specifier[, parent])` 280<!-- 281added: 282 - v13.9.0 283 - v12.16.2 284changes: 285 - version: v14.18.0 286 pr-url: https://github.com/nodejs/node/pull/38587 287 description: Add support for WHATWG `URL` object to `parentURL` parameter. 288--> 289 290> Stability: 1 - Experimental 291 292This feature is only available with the `--experimental-import-meta-resolve` 293command flag enabled. 294 295* `specifier` {string} The module specifier to resolve relative to `parent`. 296* `parent` {string} The absolute parent module URL to resolve from. If none 297 is specified, the value of `import.meta.url` is used as the default. 298* Returns: {Promise} 299 300Provides a module-relative resolution function scoped to each module, returning 301the URL string. 302 303<!-- eslint-skip --> 304```js 305const dependencyAsset = await import.meta.resolve('component-lib/asset.css'); 306``` 307 308`import.meta.resolve` also accepts a second argument which is the parent module 309from which to resolve from: 310 311<!-- eslint-skip --> 312```js 313await import.meta.resolve('./dep', import.meta.url); 314``` 315 316This function is asynchronous because the ES module resolver in Node.js is 317allowed to be asynchronous. 318 319## Interoperability with CommonJS 320 321### `import` statements 322 323An `import` statement can reference an ES module or a CommonJS module. 324`import` statements are permitted only in ES modules, but dynamic [`import()`][] 325expressions are supported in CommonJS for loading ES modules. 326 327When importing [CommonJS modules](#esm_commonjs_namespaces), the 328`module.exports` object is provided as the default export. Named exports may be 329available, provided by static analysis as a convenience for better ecosystem 330compatibility. 331 332### `require` 333 334The CommonJS module `require` always treats the files it references as CommonJS. 335 336Using `require` to load an ES module is not supported because ES modules have 337asynchronous execution. Instead, use [`import()`][] to load an ES module 338from a CommonJS module. 339 340### CommonJS Namespaces 341 342CommonJS modules consist of a `module.exports` object which can be of any type. 343 344When importing a CommonJS module, it can be reliably imported using the ES 345module default import or its corresponding sugar syntax: 346 347<!-- eslint-disable no-duplicate-imports --> 348```js 349import { default as cjs } from 'cjs'; 350 351// The following import statement is "syntax sugar" (equivalent but sweeter) 352// for `{ default as cjsSugar }` in the above import statement: 353import cjsSugar from 'cjs'; 354 355console.log(cjs); 356console.log(cjs === cjsSugar); 357// Prints: 358// <module.exports> 359// true 360``` 361 362The ECMAScript Module Namespace representation of a CommonJS module is always 363a namespace with a `default` export key pointing to the CommonJS 364`module.exports` value. 365 366This Module Namespace Exotic Object can be directly observed either when using 367`import * as m from 'cjs'` or a dynamic import: 368 369<!-- eslint-skip --> 370```js 371import * as m from 'cjs'; 372console.log(m); 373console.log(m === await import('cjs')); 374// Prints: 375// [Module] { default: <module.exports> } 376// true 377``` 378 379For better compatibility with existing usage in the JS ecosystem, Node.js 380in addition attempts to determine the CommonJS named exports of every imported 381CommonJS module to provide them as separate ES module exports using a static 382analysis process. 383 384For example, consider a CommonJS module written: 385 386```cjs 387// cjs.cjs 388exports.name = 'exported'; 389``` 390 391The preceding module supports named imports in ES modules: 392 393<!-- eslint-disable no-duplicate-imports --> 394```js 395import { name } from './cjs.cjs'; 396console.log(name); 397// Prints: 'exported' 398 399import cjs from './cjs.cjs'; 400console.log(cjs); 401// Prints: { name: 'exported' } 402 403import * as m from './cjs.cjs'; 404console.log(m); 405// Prints: [Module] { default: { name: 'exported' }, name: 'exported' } 406``` 407 408As can be seen from the last example of the Module Namespace Exotic Object being 409logged, the `name` export is copied off of the `module.exports` object and set 410directly on the ES module namespace when the module is imported. 411 412Live binding updates or new exports added to `module.exports` are not detected 413for these named exports. 414 415The detection of named exports is based on common syntax patterns but does not 416always correctly detect named exports. In these cases, using the default 417import form described above can be a better option. 418 419Named exports detection covers many common export patterns, reexport patterns 420and build tool and transpiler outputs. See [cjs-module-lexer][] for the exact 421semantics implemented. 422 423### Differences between ES modules and CommonJS 424 425#### No `require`, `exports` or `module.exports` 426 427In most cases, the ES module `import` can be used to load CommonJS modules. 428 429If needed, a `require` function can be constructed within an ES module using 430[`module.createRequire()`][]. 431 432#### No `__filename` or `__dirname` 433 434These CommonJS variables are not available in ES modules. 435 436`__filename` and `__dirname` use cases can be replicated via 437[`import.meta.url`][]. 438 439#### No JSON Module Loading 440 441JSON imports are still experimental and only supported via the 442`--experimental-json-modules` flag. 443 444Local JSON files can be loaded relative to `import.meta.url` with `fs` directly: 445 446<!-- eslint-skip --> 447```js 448import { readFile } from 'fs/promises'; 449const json = JSON.parse(await readFile(new URL('./dat.json', import.meta.url))); 450``` 451 452Alternatively `module.createRequire()` can be used. 453 454#### No Native Module Loading 455 456Native modules are not currently supported with ES module imports. 457 458They can instead be loaded with [`module.createRequire()`][] or 459[`process.dlopen`][]. 460 461#### No `require.resolve` 462 463Relative resolution can be handled via `new URL('./local', import.meta.url)`. 464 465For a complete `require.resolve` replacement, there is a flagged experimental 466[`import.meta.resolve`][] API. 467 468Alternatively `module.createRequire()` can be used. 469 470#### No `NODE_PATH` 471 472`NODE_PATH` is not part of resolving `import` specifiers. Please use symlinks 473if this behavior is desired. 474 475#### No `require.extensions` 476 477`require.extensions` is not used by `import`. The expectation is that loader 478hooks can provide this workflow in the future. 479 480#### No `require.cache` 481 482`require.cache` is not used by `import` as the ES module loader has its own 483separate cache. 484 485<i id="esm_experimental_json_modules"></i> 486 487## JSON modules 488 489> Stability: 1 - Experimental 490 491Currently importing JSON modules are only supported in the `commonjs` mode 492and are loaded using the CJS loader. [WHATWG JSON modules specification][] are 493still being standardized, and are experimentally supported by including the 494additional flag `--experimental-json-modules` when running Node.js. 495 496When the `--experimental-json-modules` flag is included, both the 497`commonjs` and `module` mode use the new experimental JSON 498loader. The imported JSON only exposes a `default`. There is no 499support for named exports. A cache entry is created in the CommonJS 500cache to avoid duplication. The same object is returned in 501CommonJS if the JSON module has already been imported from the 502same path. 503 504Assuming an `index.mjs` with 505 506<!-- eslint-skip --> 507```js 508import packageConfig from './package.json'; 509``` 510 511The `--experimental-json-modules` flag is needed for the module 512to work. 513 514```bash 515node index.mjs # fails 516node --experimental-json-modules index.mjs # works 517``` 518 519<i id="esm_experimental_wasm_modules"></i> 520 521## Wasm modules 522 523> Stability: 1 - Experimental 524 525Importing Web Assembly modules is supported under the 526`--experimental-wasm-modules` flag, allowing any `.wasm` files to be 527imported as normal modules while also supporting their module imports. 528 529This integration is in line with the 530[ES Module Integration Proposal for Web Assembly][]. 531 532For example, an `index.mjs` containing: 533 534```js 535import * as M from './module.wasm'; 536console.log(M); 537``` 538 539executed under: 540 541```bash 542node --experimental-wasm-modules index.mjs 543``` 544 545would provide the exports interface for the instantiation of `module.wasm`. 546 547<i id="esm_experimental_top_level_await"></i> 548 549## Top-level `await` 550 551<!-- YAML 552added: v14.8.0 553--> 554 555> Stability: 1 - Experimental 556 557The `await` keyword may be used in the top level body of an ECMAScript module. 558 559Assuming an `a.mjs` with 560 561```js 562export const five = await Promise.resolve(5); 563``` 564 565And a `b.mjs` with 566 567```js 568import { five } from './a.mjs'; 569 570console.log(five); // Logs `5` 571``` 572 573```bash 574node b.mjs # works 575``` 576 577If a top level `await` expression never resolves, the `node` process will exit 578with a `13` [status code][]. 579 580```js 581import { spawn } from 'child_process'; 582import { execPath } from 'process'; 583 584spawn(execPath, [ 585 '--input-type=module', 586 '--eval', 587 // Never-resolving Promise: 588 'await new Promise(() => {})', 589]).once('exit', (code) => { 590 console.log(code); // Logs `13` 591}); 592``` 593 594<i id="esm_experimental_loaders"></i> 595 596## Loaders 597 598> Stability: 1 - Experimental 599 600**Note: This API is currently being redesigned and will still change.** 601 602<!-- type=misc --> 603 604To customize the default module resolution, loader hooks can optionally be 605provided via a `--experimental-loader ./loader-name.mjs` argument to Node.js. 606 607When hooks are used they only apply to ES module loading and not to any 608CommonJS modules loaded. 609 610### Hooks 611 612#### `resolve(specifier, context, defaultResolve)` 613 614> Note: The loaders API is being redesigned. This hook may disappear or its 615> signature may change. Do not rely on the API described below. 616 617* `specifier` {string} 618* `context` {Object} 619 * `conditions` {string[]} 620 * `parentURL` {string} 621* `defaultResolve` {Function} 622* Returns: {Object} 623 * `url` {string} 624 625The `resolve` hook returns the resolved file URL for a given module specifier 626and parent URL. The module specifier is the string in an `import` statement or 627`import()` expression, and the parent URL is the URL of the module that imported 628this one, or `undefined` if this is the main entry point for the application. 629 630The `conditions` property on the `context` is an array of conditions for 631[Conditional exports][] that apply to this resolution request. They can be used 632for looking up conditional mappings elsewhere or to modify the list when calling 633the default resolution logic. 634 635The current [package exports conditions][Conditional Exports] are always in 636the `context.conditions` array passed into the hook. To guarantee _default 637Node.js module specifier resolution behavior_ when calling `defaultResolve`, the 638`context.conditions` array passed to it _must_ include _all_ elements of the 639`context.conditions` array originally passed into the `resolve` hook. 640 641```js 642/** 643 * @param {string} specifier 644 * @param {{ 645 * conditions: !Array<string>, 646 * parentURL: !(string | undefined), 647 * }} context 648 * @param {Function} defaultResolve 649 * @returns {Promise<{ url: string }>} 650 */ 651export async function resolve(specifier, context, defaultResolve) { 652 const { parentURL = null } = context; 653 if (Math.random() > 0.5) { // Some condition. 654 // For some or all specifiers, do some custom logic for resolving. 655 // Always return an object of the form {url: <string>}. 656 return { 657 url: parentURL ? 658 new URL(specifier, parentURL).href : 659 new URL(specifier).href, 660 }; 661 } 662 if (Math.random() < 0.5) { // Another condition. 663 // When calling `defaultResolve`, the arguments can be modified. In this 664 // case it's adding another value for matching conditional exports. 665 return defaultResolve(specifier, { 666 ...context, 667 conditions: [...context.conditions, 'another-condition'], 668 }); 669 } 670 // Defer to Node.js for all other specifiers. 671 return defaultResolve(specifier, context, defaultResolve); 672} 673``` 674 675#### `getFormat(url, context, defaultGetFormat)` 676 677> Note: The loaders API is being redesigned. This hook may disappear or its 678> signature may change. Do not rely on the API described below. 679 680* `url` {string} 681* `context` {Object} 682* `defaultGetFormat` {Function} 683* Returns: {Object} 684 * `format` {string} 685 686The `getFormat` hook provides a way to define a custom method of determining how 687a URL should be interpreted. The `format` returned also affects what the 688acceptable forms of source values are for a module when parsing. This can be one 689of the following: 690 691| `format` | Description | Acceptable Types For `source` Returned by `getSource` or `transformSource` | 692| ------------ | ------------------------------ | -------------------------------------------------------------------------- | 693| `'builtin'` | Load a Node.js builtin module | Not applicable | 694| `'commonjs'` | Load a Node.js CommonJS module | Not applicable | 695| `'json'` | Load a JSON file | { [`string`][], [`ArrayBuffer`][], [`TypedArray`][] } | 696| `'module'` | Load an ES module | { [`string`][], [`ArrayBuffer`][], [`TypedArray`][] } | 697| `'wasm'` | Load a WebAssembly module | { [`ArrayBuffer`][], [`TypedArray`][] } | 698 699Note: These types all correspond to classes defined in ECMAScript. 700 701* The specific [`ArrayBuffer`][] object is a [`SharedArrayBuffer`][]. 702* The specific [`TypedArray`][] object is a [`Uint8Array`][]. 703 704Note: If the source value of a text-based format (i.e., `'json'`, `'module'`) is 705not a string, it is converted to a string using [`util.TextDecoder`][]. 706 707```js 708/** 709 * @param {string} url 710 * @param {Object} context (currently empty) 711 * @param {Function} defaultGetFormat 712 * @returns {Promise<{ format: string }>} 713 */ 714export async function getFormat(url, context, defaultGetFormat) { 715 if (Math.random() > 0.5) { // Some condition. 716 // For some or all URLs, do some custom logic for determining format. 717 // Always return an object of the form {format: <string>}, where the 718 // format is one of the strings in the preceding table. 719 return { 720 format: 'module', 721 }; 722 } 723 // Defer to Node.js for all other URLs. 724 return defaultGetFormat(url, context, defaultGetFormat); 725} 726``` 727 728#### `getSource(url, context, defaultGetSource)` 729 730> Note: The loaders API is being redesigned. This hook may disappear or its 731> signature may change. Do not rely on the API described below. 732 733* `url` {string} 734* `context` {Object} 735 * `format` {string} 736* `defaultGetSource` {Function} 737* Returns: {Object} 738 * `source` {string|SharedArrayBuffer|Uint8Array} 739 740The `getSource` hook provides a way to define a custom method for retrieving 741the source code of an ES module specifier. This would allow a loader to 742potentially avoid reading files from disk. 743 744```js 745/** 746 * @param {string} url 747 * @param {{ format: string }} context 748 * @param {Function} defaultGetSource 749 * @returns {Promise<{ source: !(string | SharedArrayBuffer | Uint8Array) }>} 750 */ 751export async function getSource(url, context, defaultGetSource) { 752 const { format } = context; 753 if (Math.random() > 0.5) { // Some condition. 754 // For some or all URLs, do some custom logic for retrieving the source. 755 // Always return an object of the form {source: <string|buffer>}. 756 return { 757 source: '...', 758 }; 759 } 760 // Defer to Node.js for all other URLs. 761 return defaultGetSource(url, context, defaultGetSource); 762} 763``` 764 765#### `transformSource(source, context, defaultTransformSource)` 766 767> Note: The loaders API is being redesigned. This hook may disappear or its 768> signature may change. Do not rely on the API described below. 769 770* `source` {string|SharedArrayBuffer|Uint8Array} 771* `context` {Object} 772 * `format` {string} 773 * `url` {string} 774* Returns: {Object} 775 * `source` {string|SharedArrayBuffer|Uint8Array} 776 777The `transformSource` hook provides a way to modify the source code of a loaded 778ES module file after the source string has been loaded but before Node.js has 779done anything with it. 780 781If this hook is used to convert unknown-to-Node.js file types into executable 782JavaScript, a resolve hook is also necessary in order to register any 783unknown-to-Node.js file extensions. See the [transpiler loader example][] below. 784 785```js 786/** 787 * @param {!(string | SharedArrayBuffer | Uint8Array)} source 788 * @param {{ 789 * format: string, 790 * url: string, 791 * }} context 792 * @param {Function} defaultTransformSource 793 * @returns {Promise<{ source: !(string | SharedArrayBuffer | Uint8Array) }>} 794 */ 795export async function transformSource(source, context, defaultTransformSource) { 796 const { url, format } = context; 797 if (Math.random() > 0.5) { // Some condition. 798 // For some or all URLs, do some custom logic for modifying the source. 799 // Always return an object of the form {source: <string|buffer>}. 800 return { 801 source: '...', 802 }; 803 } 804 // Defer to Node.js for all other sources. 805 return defaultTransformSource(source, context, defaultTransformSource); 806} 807``` 808 809#### `getGlobalPreloadCode()` 810 811> Note: The loaders API is being redesigned. This hook may disappear or its 812> signature may change. Do not rely on the API described below. 813 814* Returns: {string} 815 816Sometimes it might be necessary to run some code inside of the same global scope 817that the application runs in. This hook allows the return of a string that is 818run as sloppy-mode script on startup. 819 820Similar to how CommonJS wrappers work, the code runs in an implicit function 821scope. The only argument is a `require`-like function that can be used to load 822builtins like "fs": `getBuiltin(request: string)`. 823 824If the code needs more advanced `require` features, it has to construct 825its own `require` using `module.createRequire()`. 826 827```js 828/** 829 * @returns {string} Code to run before application startup 830 */ 831export function getGlobalPreloadCode() { 832 return `\ 833globalThis.someInjectedProperty = 42; 834console.log('I just set some globals!'); 835 836const { createRequire } = getBuiltin('module'); 837 838const require = createRequire(process.cwd() + '/<preload>'); 839// [...] 840`; 841} 842``` 843 844### Examples 845 846The various loader hooks can be used together to accomplish wide-ranging 847customizations of Node.js’ code loading and evaluation behaviors. 848 849#### HTTPS loader 850 851In current Node.js, specifiers starting with `https://` are unsupported. The 852loader below registers hooks to enable rudimentary support for such specifiers. 853While this may seem like a significant improvement to Node.js core 854functionality, there are substantial downsides to actually using this loader: 855performance is much slower than loading files from disk, there is no caching, 856and there is no security. 857 858```js 859// https-loader.mjs 860import { get } from 'https'; 861 862export function resolve(specifier, context, defaultResolve) { 863 const { parentURL = null } = context; 864 865 // Normally Node.js would error on specifiers starting with 'https://', so 866 // this hook intercepts them and converts them into absolute URLs to be 867 // passed along to the later hooks below. 868 if (specifier.startsWith('https://')) { 869 return { 870 url: specifier 871 }; 872 } else if (parentURL && parentURL.startsWith('https://')) { 873 return { 874 url: new URL(specifier, parentURL).href 875 }; 876 } 877 878 // Let Node.js handle all other specifiers. 879 return defaultResolve(specifier, context, defaultResolve); 880} 881 882export function getFormat(url, context, defaultGetFormat) { 883 // This loader assumes all network-provided JavaScript is ES module code. 884 if (url.startsWith('https://')) { 885 return { 886 format: 'module' 887 }; 888 } 889 890 // Let Node.js handle all other URLs. 891 return defaultGetFormat(url, context, defaultGetFormat); 892} 893 894export function getSource(url, context, defaultGetSource) { 895 // For JavaScript to be loaded over the network, we need to fetch and 896 // return it. 897 if (url.startsWith('https://')) { 898 return new Promise((resolve, reject) => { 899 get(url, (res) => { 900 let data = ''; 901 res.on('data', (chunk) => data += chunk); 902 res.on('end', () => resolve({ source: data })); 903 }).on('error', (err) => reject(err)); 904 }); 905 } 906 907 // Let Node.js handle all other URLs. 908 return defaultGetSource(url, context, defaultGetSource); 909} 910``` 911 912```js 913// main.mjs 914import { VERSION } from 'https://coffeescript.org/browser-compiler-modern/coffeescript.js'; 915 916console.log(VERSION); 917``` 918 919With the preceding loader, running 920`node --experimental-loader ./https-loader.mjs ./main.mjs` 921prints the current version of CoffeeScript per the module at the URL in 922`main.mjs`. 923 924#### Transpiler loader 925 926Sources that are in formats Node.js doesn’t understand can be converted into 927JavaScript using the [`transformSource` hook][]. Before that hook gets called, 928however, other hooks need to tell Node.js not to throw an error on unknown file 929types; and to tell Node.js how to load this new file type. 930 931This is less performant than transpiling source files before running 932Node.js; a transpiler loader should only be used for development and testing 933purposes. 934 935```js 936// coffeescript-loader.mjs 937import { URL, pathToFileURL } from 'url'; 938import CoffeeScript from 'coffeescript'; 939 940const baseURL = pathToFileURL(`${process.cwd()}/`).href; 941 942// CoffeeScript files end in .coffee, .litcoffee or .coffee.md. 943const extensionsRegex = /\.coffee$|\.litcoffee$|\.coffee\.md$/; 944 945export function resolve(specifier, context, defaultResolve) { 946 const { parentURL = baseURL } = context; 947 948 // Node.js normally errors on unknown file extensions, so return a URL for 949 // specifiers ending in the CoffeeScript file extensions. 950 if (extensionsRegex.test(specifier)) { 951 return { 952 url: new URL(specifier, parentURL).href 953 }; 954 } 955 956 // Let Node.js handle all other specifiers. 957 return defaultResolve(specifier, context, defaultResolve); 958} 959 960export function getFormat(url, context, defaultGetFormat) { 961 // Now that we patched resolve to let CoffeeScript URLs through, we need to 962 // tell Node.js what format such URLs should be interpreted as. For the 963 // purposes of this loader, all CoffeeScript URLs are ES modules. 964 if (extensionsRegex.test(url)) { 965 return { 966 format: 'module' 967 }; 968 } 969 970 // Let Node.js handle all other URLs. 971 return defaultGetFormat(url, context, defaultGetFormat); 972} 973 974export function transformSource(source, context, defaultTransformSource) { 975 const { url, format } = context; 976 977 if (extensionsRegex.test(url)) { 978 return { 979 source: CoffeeScript.compile(source, { bare: true }) 980 }; 981 } 982 983 // Let Node.js handle all other sources. 984 return defaultTransformSource(source, context, defaultTransformSource); 985} 986``` 987 988```coffee 989# main.coffee 990import { scream } from './scream.coffee' 991console.log scream 'hello, world' 992 993import { version } from 'process' 994console.log "Brought to you by Node.js version #{version}" 995``` 996 997```coffee 998# scream.coffee 999export scream = (str) -> str.toUpperCase() 1000``` 1001 1002With the preceding loader, running 1003`node --experimental-loader ./coffeescript-loader.mjs main.coffee` 1004causes `main.coffee` to be turned into JavaScript after its source code is 1005loaded from disk but before Node.js executes it; and so on for any `.coffee`, 1006`.litcoffee` or `.coffee.md` files referenced via `import` statements of any 1007loaded file. 1008 1009## Resolution algorithm 1010 1011### Features 1012 1013The resolver has the following properties: 1014 1015* FileURL-based resolution as is used by ES modules 1016* Support for builtin module loading 1017* Relative and absolute URL resolution 1018* No default extensions 1019* No folder mains 1020* Bare specifier package resolution lookup through node_modules 1021 1022### Resolver algorithm 1023 1024The algorithm to load an ES module specifier is given through the 1025**ESM_RESOLVE** method below. It returns the resolved URL for a 1026module specifier relative to a parentURL. 1027 1028The algorithm to determine the module format of a resolved URL is 1029provided by **ESM_FORMAT**, which returns the unique module 1030format for any file. The _"module"_ format is returned for an ECMAScript 1031Module, while the _"commonjs"_ format is used to indicate loading through the 1032legacy CommonJS loader. Additional formats such as _"addon"_ can be extended in 1033future updates. 1034 1035In the following algorithms, all subroutine errors are propagated as errors 1036of these top-level routines unless stated otherwise. 1037 1038_defaultConditions_ is the conditional environment name array, 1039`["node", "import"]`. 1040 1041The resolver can throw the following errors: 1042* _Invalid Module Specifier_: Module specifier is an invalid URL, package name 1043 or package subpath specifier. 1044* _Invalid Package Configuration_: package.json configuration is invalid or 1045 contains an invalid configuration. 1046* _Invalid Package Target_: Package exports or imports define a target module 1047 for the package that is an invalid type or string target. 1048* _Package Path Not Exported_: Package exports do not define or permit a target 1049 subpath in the package for the given module. 1050* _Package Import Not Defined_: Package imports do not define the specifier. 1051* _Module Not Found_: The package or module requested does not exist. 1052* _Unsupported Directory Import_: The resolved path corresponds to a directory, 1053 which is not a supported target for module imports. 1054 1055### Resolver Algorithm Specification 1056 1057**ESM_RESOLVE**(_specifier_, _parentURL_) 1058 1059> 1. Let _resolved_ be **undefined**. 1060> 1. If _specifier_ is a valid URL, then 1061> 1. Set _resolved_ to the result of parsing and reserializing 1062> _specifier_ as a URL. 1063> 1. Otherwise, if _specifier_ starts with _"/"_, _"./"_ or _"../"_, then 1064> 1. Set _resolved_ to the URL resolution of _specifier_ relative to 1065> _parentURL_. 1066> 1. Otherwise, if _specifier_ starts with _"#"_, then 1067> 1. Set _resolved_ to the destructured value of the result of 1068> **PACKAGE_IMPORTS_RESOLVE**(_specifier_, _parentURL_, 1069> _defaultConditions_). 1070> 1. Otherwise, 1071> 1. Note: _specifier_ is now a bare specifier. 1072> 1. Set _resolved_ the result of 1073> **PACKAGE_RESOLVE**(_specifier_, _parentURL_). 1074> 1. If _resolved_ contains any percent encodings of _"/"_ or _"\\"_ (_"%2f"_ 1075> and _"%5C"_ respectively), then 1076> 1. Throw an _Invalid Module Specifier_ error. 1077> 1. If the file at _resolved_ is a directory, then 1078> 1. Throw an _Unsupported Directory Import_ error. 1079> 1. If the file at _resolved_ does not exist, then 1080> 1. Throw a _Module Not Found_ error. 1081> 1. Set _resolved_ to the real path of _resolved_. 1082> 1. Let _format_ be the result of **ESM_FORMAT**(_resolved_). 1083> 1. Load _resolved_ as module format, _format_. 1084> 1. Return _resolved_. 1085 1086**PACKAGE_RESOLVE**(_packageSpecifier_, _parentURL_) 1087 1088> 1. Let _packageName_ be **undefined**. 1089> 1. If _packageSpecifier_ is an empty string, then 1090> 1. Throw an _Invalid Module Specifier_ error. 1091> 1. If _packageSpecifier_ does not start with _"@"_, then 1092> 1. Set _packageName_ to the substring of _packageSpecifier_ until the first 1093> _"/"_ separator or the end of the string. 1094> 1. Otherwise, 1095> 1. If _packageSpecifier_ does not contain a _"/"_ separator, then 1096> 1. Throw an _Invalid Module Specifier_ error. 1097> 1. Set _packageName_ to the substring of _packageSpecifier_ 1098> until the second _"/"_ separator or the end of the string. 1099> 1. If _packageName_ starts with _"."_ or contains _"\\"_ or _"%"_, then 1100> 1. Throw an _Invalid Module Specifier_ error. 1101> 1. Let _packageSubpath_ be _"."_ concatenated with the substring of 1102> _packageSpecifier_ from the position at the length of _packageName_. 1103> 1. Let _selfUrl_ be the result of 1104> **PACKAGE_SELF_RESOLVE**(_packageName_, _packageSubpath_, _parentURL_). 1105> 1. If _selfUrl_ is not **undefined**, return _selfUrl_. 1106> 1. If _packageSubpath_ is _"."_ and _packageName_ is a Node.js builtin 1107> module, then 1108> 1. Return the string _"node:"_ concatenated with _packageSpecifier_. 1109> 1. While _parentURL_ is not the file system root, 1110> 1. Let _packageURL_ be the URL resolution of _"node_modules/"_ 1111> concatenated with _packageSpecifier_, relative to _parentURL_. 1112> 1. Set _parentURL_ to the parent folder URL of _parentURL_. 1113> 1. If the folder at _packageURL_ does not exist, then 1114> 1. Set _parentURL_ to the parent URL path of _parentURL_. 1115> 1. Continue the next loop iteration. 1116> 1. Let _pjson_ be the result of **READ_PACKAGE_JSON**(_packageURL_). 1117> 1. If _pjson_ is not **null** and _pjson_._exports_ is not **null** or 1118> **undefined**, then 1119> 1. Let _exports_ be _pjson.exports_. 1120> 1. Return the _resolved_ destructured value of the result of 1121> **PACKAGE_EXPORTS_RESOLVE**(_packageURL_, _packageSubpath_, 1122> _pjson.exports_, _defaultConditions_). 1123> 1. Otherwise, if _packageSubpath_ is equal to _"."_, then 1124> 1. Return the result applying the legacy **LOAD_AS_DIRECTORY** 1125> CommonJS resolver to _packageURL_, throwing a _Module Not Found_ 1126> error for no resolution. 1127> 1. Otherwise, 1128> 1. Return the URL resolution of _packageSubpath_ in _packageURL_. 1129> 1. Throw a _Module Not Found_ error. 1130 1131**PACKAGE_SELF_RESOLVE**(_packageName_, _packageSubpath_, _parentURL_) 1132 1133> 1. Let _packageURL_ be the result of **READ_PACKAGE_SCOPE**(_parentURL_). 1134> 1. If _packageURL_ is **null**, then 1135> 1. Return **undefined**. 1136> 1. Let _pjson_ be the result of **READ_PACKAGE_JSON**(_packageURL_). 1137> 1. If _pjson_ is **null** or if _pjson_._exports_ is **null** or 1138> **undefined**, then 1139> 1. Return **undefined**. 1140> 1. If _pjson.name_ is equal to _packageName_, then 1141> 1. Return the _resolved_ destructured value of the result of 1142> **PACKAGE_EXPORTS_RESOLVE**(_packageURL_, _subpath_, _pjson.exports_, 1143> _defaultConditions_). 1144> 1. Otherwise, return **undefined**. 1145 1146**PACKAGE_EXPORTS_RESOLVE**(_packageURL_, _subpath_, _exports_, _conditions_) 1147 1148> 1. If _exports_ is an Object with both a key starting with _"."_ and a key not 1149> starting with _"."_, throw an _Invalid Package Configuration_ error. 1150> 1. If _subpath_ is equal to _"."_, then 1151> 1. Let _mainExport_ be **undefined**. 1152> 1. If _exports_ is a String or Array, or an Object containing no keys 1153> starting with _"."_, then 1154> 1. Set _mainExport_ to _exports_. 1155> 1. Otherwise if _exports_ is an Object containing a _"."_ property, then 1156> 1. Set _mainExport_ to _exports_\[_"."_\]. 1157> 1. If _mainExport_ is not **undefined**, then 1158> 1. Let _resolved_ be the result of **PACKAGE_TARGET_RESOLVE**( 1159> _packageURL_, _mainExport_, _""_, **false**, **false**, 1160> _conditions_). 1161> 1. If _resolved_ is not **null** or **undefined**, then 1162> 1. Return _resolved_. 1163> 1. Otherwise, if _exports_ is an Object and all keys of _exports_ start with 1164> _"."_, then 1165> 1. Let _matchKey_ be the string _"./"_ concatenated with _subpath_. 1166> 1. Let _resolvedMatch_ be result of **PACKAGE_IMPORTS_EXPORTS_RESOLVE**( 1167> _matchKey_, _exports_, _packageURL_, **false**, _conditions_). 1168> 1. If _resolvedMatch_._resolve_ is not **null** or **undefined**, then 1169> 1. Return _resolvedMatch_. 1170> 1. Throw a _Package Path Not Exported_ error. 1171 1172**PACKAGE_IMPORTS_RESOLVE**(_specifier_, _parentURL_, _conditions_) 1173 1174> 1. Assert: _specifier_ begins with _"#"_. 1175> 1. If _specifier_ is exactly equal to _"#"_ or starts with _"#/"_, then 1176> 1. Throw an _Invalid Module Specifier_ error. 1177> 1. Let _packageURL_ be the result of **READ_PACKAGE_SCOPE**(_parentURL_). 1178> 1. If _packageURL_ is not **null**, then 1179> 1. Let _pjson_ be the result of **READ_PACKAGE_JSON**(_packageURL_). 1180> 1. If _pjson.imports_ is a non-null Object, then 1181> 1. Let _resolvedMatch_ be the result of 1182> **PACKAGE_IMPORTS_EXPORTS_RESOLVE**(_specifier_, _pjson.imports_, 1183> _packageURL_, **true**, _conditions_). 1184> 1. If _resolvedMatch_._resolve_ is not **null** or **undefined**, then 1185> 1. Return _resolvedMatch_. 1186> 1. Throw a _Package Import Not Defined_ error. 1187 1188**PACKAGE_IMPORTS_EXPORTS_RESOLVE**(_matchKey_, _matchObj_, _packageURL_, 1189_isImports_, _conditions_) 1190 1191> 1. If _matchKey_ is a key of _matchObj_ and does not end in _"/"_ or contain 1192> _"*"_, then 1193> 1. Let _target_ be the value of _matchObj_\[_matchKey_\]. 1194> 1. Let _resolved_ be the result of **PACKAGE_TARGET_RESOLVE**( 1195> _packageURL_, _target_, _""_, **false**, _isImports_, _conditions_). 1196> 1. Return the object _{ resolved, exact: **true** }_. 1197> 1. Let _expansionKeys_ be the list of keys of _matchObj_ either ending in 1198> _"/"_ or containing only a single _"*"_, sorted by the sorting function 1199> **PATTERN_KEY_COMPARE** which orders in descending order of specificity. 1200> 1. For each key _expansionKey_ in _expansionKeys_, do 1201> 1. Let _patternBase_ be **null**. 1202> 1. If _expansionKey_ contains _"*"_, set _patternBase_ to the substring of 1203> _expansionKey_ up to but excluding the first _"*"_ character. 1204> 1. If _patternBase_ is not **null** and _matchKey_ starts with but is not 1205> equal to _patternBase_, then 1206> 1. Let _patternTrailer_ be the substring of _expansionKey_ from the 1207> index after the first _"*"_ character. 1208> 1. If _patternTrailer_ has zero length, or if _matchKey_ ends with 1209> _patternTrailer_ and the length of _matchKey_ is greater than or 1210> equal to the length of _expansionKey_, then 1211> 1. Let _target_ be the value of _matchObj_\[_expansionKey_\]. 1212> 1. Let _subpath_ be the substring of _matchKey_ starting at the 1213> index of the length of _patternBase_ up to the length of 1214> _matchKey_ minus the length of _patternTrailer_. 1215> 1. Let _resolved_ be the result of **PACKAGE_TARGET_RESOLVE**( 1216> _packageURL_, _target_, _subpath_, **true**, _isImports_, 1217> _conditions_). 1218> 1. Return the object _{ resolved, exact: **true** }_. 1219> 1. Otherwise if _patternBase_ is **null** and _matchKey_ starts with 1220> _expansionKey_, then 1221> 1. Let _target_ be the value of _matchObj_\[_expansionKey_\]. 1222> 1. Let _subpath_ be the substring of _matchKey_ starting at the 1223> index of the length of _expansionKey_. 1224> 1. Let _resolved_ be the result of **PACKAGE_TARGET_RESOLVE**( 1225> _packageURL_, _target_, _subpath_, **false**, _isImports_, 1226> _conditions_). 1227> 1. Return the object _{ resolved, exact: **false** }_. 1228> 1. Return the object _{ resolved: **null**, exact: **true** }_. 1229 1230**PATTERN_KEY_COMPARE**(_keyA_, _keyB_) 1231 1232> 1. Assert: _keyA_ ends with _"/"_ or contains only a single _"*"_. 1233> 1. Assert: _keyB_ ends with _"/"_ or contains only a single _"*"_. 1234> 1. Let _baseLengthA_ be the index of _"*"_ in _keyA_ plus one, if _keyA_ 1235> contains _"*"_, or the length of _keyA_ otherwise. 1236> 1. Let _baseLengthB_ be the index of _"*"_ in _keyB_ plus one, if _keyB_ 1237> contains _"*"_, or the length of _keyB_ otherwise. 1238> 1. If _baseLengthA_ is greater than _baseLengthB_, return -1. 1239> 1. If _baseLengthB_ is greater than _baseLengthA_, return 1. 1240> 1. If _keyA_ does not contain _"*"_, return 1. 1241> 1. If _keyB_ does not contain _"*"_, return -1. 1242> 1. If the length of _keyA_ is greater than the length of _keyB_, return -1. 1243> 1. If the length of _keyB_ is greater than the length of _keyA_, return 1. 1244> 1. Return 0. 1245 1246**PACKAGE_TARGET_RESOLVE**(_packageURL_, _target_, _subpath_, _pattern_, 1247_internal_, _conditions_) 1248 1249> 1. If _target_ is a String, then 1250> 1. If _pattern_ is **false**, _subpath_ has non-zero length and _target_ 1251> does not end with _"/"_, throw an _Invalid Module Specifier_ error. 1252> 1. If _target_ does not start with _"./"_, then 1253> 1. If _internal_ is **true** and _target_ does not start with _"../"_ or 1254> _"/"_ and is not a valid URL, then 1255> 1. If _pattern_ is **true**, then 1256> 1. Return **PACKAGE_RESOLVE**(_target_ with every instance of 1257> _"*"_ replaced by _subpath_, _packageURL_ + _"/"_)_. 1258> 1. Return **PACKAGE_RESOLVE**(_target_ + _subpath_, 1259> _packageURL_ + _"/"_)_. 1260> 1. Otherwise, throw an _Invalid Package Target_ error. 1261> 1. If _target_ split on _"/"_ or _"\\"_ contains any _"."_, _".."_ or 1262> _"node_modules"_ segments after the first segment, throw an 1263> _Invalid Package Target_ error. 1264> 1. Let _resolvedTarget_ be the URL resolution of the concatenation of 1265> _packageURL_ and _target_. 1266> 1. Assert: _resolvedTarget_ is contained in _packageURL_. 1267> 1. If _subpath_ split on _"/"_ or _"\\"_ contains any _"."_, _".."_ or 1268> _"node_modules"_ segments, throw an _Invalid Module Specifier_ error. 1269> 1. If _pattern_ is **true**, then 1270> 1. Return the URL resolution of _resolvedTarget_ with every instance of 1271> _"*"_ replaced with _subpath_. 1272> 1. Otherwise, 1273> 1. Return the URL resolution of the concatenation of _subpath_ and 1274> _resolvedTarget_. 1275> 1. Otherwise, if _target_ is a non-null Object, then 1276> 1. If _exports_ contains any index property keys, as defined in ECMA-262 1277> [6.1.7 Array Index][], throw an _Invalid Package Configuration_ error. 1278> 1. For each property _p_ of _target_, in object insertion order as, 1279> 1. If _p_ equals _"default"_ or _conditions_ contains an entry for _p_, 1280> then 1281> 1. Let _targetValue_ be the value of the _p_ property in _target_. 1282> 1. Let _resolved_ be the result of **PACKAGE_TARGET_RESOLVE**( 1283> _packageURL_, _targetValue_, _subpath_, _pattern_, _internal_, 1284> _conditions_). 1285> 1. If _resolved_ is equal to **undefined**, continue the loop. 1286> 1. Return _resolved_. 1287> 1. Return **undefined**. 1288> 1. Otherwise, if _target_ is an Array, then 1289> 1. If _target.length is zero, return **null**. 1290> 1. For each item _targetValue_ in _target_, do 1291> 1. Let _resolved_ be the result of **PACKAGE_TARGET_RESOLVE**( 1292> _packageURL_, _targetValue_, _subpath_, _pattern_, _internal_, 1293> _conditions_), continuing the loop on any _Invalid Package Target_ 1294> error. 1295> 1. If _resolved_ is **undefined**, continue the loop. 1296> 1. Return _resolved_. 1297> 1. Return or throw the last fallback resolution **null** return or error. 1298> 1. Otherwise, if _target_ is _null_, return **null**. 1299> 1. Otherwise throw an _Invalid Package Target_ error. 1300 1301**ESM_FORMAT**(_url_) 1302 1303> 1. Assert: _url_ corresponds to an existing file. 1304> 1. Let _pjson_ be the result of **READ_PACKAGE_SCOPE**(_url_). 1305> 1. If _url_ ends in _".mjs"_, then 1306> 1. Return _"module"_. 1307> 1. If _url_ ends in _".cjs"_, then 1308> 1. Return _"commonjs"_. 1309> 1. If _pjson?.type_ exists and is _"module"_, then 1310> 1. If _url_ ends in _".js"_, then 1311> 1. Return _"module"_. 1312> 1. Throw an _Unsupported File Extension_ error. 1313> 1. Otherwise, 1314> 1. Throw an _Unsupported File Extension_ error. 1315 1316**READ_PACKAGE_SCOPE**(_url_) 1317 1318> 1. Let _scopeURL_ be _url_. 1319> 1. While _scopeURL_ is not the file system root, 1320> 1. Set _scopeURL_ to the parent URL of _scopeURL_. 1321> 1. If _scopeURL_ ends in a _"node_modules"_ path segment, return **null**. 1322> 1. Let _pjson_ be the result of **READ_PACKAGE_JSON**(_scopeURL_). 1323> 1. If _pjson_ is not **null**, then 1324> 1. Return _pjson_. 1325> 1. Return **null**. 1326 1327**READ_PACKAGE_JSON**(_packageURL_) 1328 1329> 1. Let _pjsonURL_ be the resolution of _"package.json"_ within _packageURL_. 1330> 1. If the file at _pjsonURL_ does not exist, then 1331> 1. Return **null**. 1332> 1. If the file at _packageURL_ does not parse as valid JSON, then 1333> 1. Throw an _Invalid Package Configuration_ error. 1334> 1. Return the parsed JSON source of the file at _pjsonURL_. 1335 1336### Customizing ESM specifier resolution algorithm 1337 1338> Stability: 1 - Experimental 1339 1340The current specifier resolution does not support all default behavior of 1341the CommonJS loader. One of the behavior differences is automatic resolution 1342of file extensions and the ability to import directories that have an index 1343file. 1344 1345The `--experimental-specifier-resolution=[mode]` flag can be used to customize 1346the extension resolution algorithm. The default mode is `explicit`, which 1347requires the full path to a module be provided to the loader. To enable the 1348automatic extension resolution and importing from directories that include an 1349index file use the `node` mode. 1350 1351```console 1352$ node index.mjs 1353success! 1354$ node index # Failure! 1355Error: Cannot find module 1356$ node --experimental-specifier-resolution=node index 1357success! 1358``` 1359 1360<!-- Note: The cjs-module-lexer link should be kept in-sync with the deps version --> 1361[6.1.7 Array Index]: https://tc39.es/ecma262/#integer-index 1362[CommonJS]: modules.md 1363[Conditional exports]: packages.md#packages_conditional_exports 1364[Core modules]: modules.md#modules_core_modules 1365[Dynamic `import()`]: https://wiki.developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#Dynamic_Imports 1366[ES Module Integration Proposal for Web Assembly]: https://github.com/webassembly/esm-integration 1367[Node.js Module Resolution Algorithm]: #esm_resolver_algorithm_specification 1368[Terminology]: #esm_terminology 1369[URL]: https://url.spec.whatwg.org/ 1370[WHATWG JSON modules specification]: https://html.spec.whatwg.org/#creating-a-json-module-script 1371[`"exports"`]: packages.md#packages_exports 1372[`"type"`]: packages.md#packages_type 1373[`ArrayBuffer`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer 1374[`SharedArrayBuffer`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer 1375[`TypedArray`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray 1376[`Uint8Array`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array 1377[`data:` URLs]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs 1378[`export`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export 1379[`import()`]: #esm_import_expressions 1380[`import.meta.resolve`]: #esm_import_meta_resolve_specifier_parent 1381[`import.meta.url`]: #esm_import_meta_url 1382[`import`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import 1383[`module.createRequire()`]: module.md#module_module_createrequire_filename 1384[`module.syncBuiltinESMExports()`]: module.md#module_module_syncbuiltinesmexports 1385[`package.json`]: packages.md#packages_node_js_package_json_field_definitions 1386[`process.dlopen`]: process.md#process_process_dlopen_module_filename_flags 1387[`string`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String 1388[`transformSource` hook]: #esm_transformsource_source_context_defaulttransformsource 1389[`util.TextDecoder`]: util.md#util_class_util_textdecoder 1390[cjs-module-lexer]: https://github.com/guybedford/cjs-module-lexer/tree/1.2.2 1391[custom https loader]: #esm_https_loader 1392[special scheme]: https://url.spec.whatwg.org/#special-scheme 1393[status code]: process.md#process_exit_codes 1394[the official standard format]: https://tc39.github.io/ecma262/#sec-modules 1395[transpiler loader example]: #esm_transpiler_loader 1396[url.pathToFileURL]: url.md#url_url_pathtofileurl_path 1397