Modules: ECMAScript modules#

History
VersionChanges
v22.0.0

Drop support for import assertions.

v23.1.0, v22.12.0, v20.18.3, v18.20.5

Import attributes are no longer experimental.

v21.0.0, v20.10.0, v18.20.0

Add experimental support for import attributes.

v20.0.0, v18.19.0

Module customization hooks are executed off the main thread.

v18.6.0, v16.17.0

Add support for chaining module customization hooks.

v17.1.0, v16.14.0

Add experimental support for import assertions.

v17.0.0, v16.12.0

Consolidate customization hooks, removedgetFormat,getSource,transformSource, andgetGlobalPreloadCode hooks addedload andglobalPreload hooks allowed returningformat from eitherresolve orload hooks.

v14.8.0

Unflag Top-Level Await.

v15.3.0, v14.17.0, v12.22.0

Stabilize modules implementation.

v14.13.0, v12.20.0

Support for detection of CommonJS named exports.

v14.0.0, v13.14.0, v12.20.0

Remove experimental modules warning.

v13.2.0, v12.17.0

Loading ECMAScript modules no longer requires a command-line flag.

v12.0.0

Add support for ES modules using.js file extension viapackage.json"type" field.

v8.5.0

Added in: v8.5.0

Stability: 2 - Stable

Introduction#

ECMAScript modules arethe official standard format to package JavaScriptcode for reuse. Modules are defined using a variety ofimport andexport statements.

The following example of an ES module exports a function:

// addTwo.mjsfunctionaddTwo(num) {return num +2;}export { addTwo };

The following example of an ES module imports the function fromaddTwo.mjs:

// app.mjsimport { addTwo }from'./addTwo.mjs';// Prints: 6console.log(addTwo(4));

Node.js fully supports ECMAScript modules as they are currently specified andprovides interoperability between them and its original module format,CommonJS.

Enabling#

Node.js has two module systems:CommonJS modules and ECMAScript modules.

Authors can tell Node.js to interpret JavaScript as an ES module via the.mjsfile extension, thepackage.json"type" field with a value"module",or the--input-type flag with a value of"module". These are explicitmarkers of code being intended to run as an ES module.

Inversely, authors can explicitly tell Node.js to interpret JavaScript asCommonJS via the.cjs file extension, thepackage.json"type" fieldwith a value"commonjs", or the--input-type flag with a value of"commonjs".

When code lacks explicit markers for either module system, Node.js will inspectthe source code of a module to look for ES module syntax. If such syntax isfound, Node.js will run the code as an ES module; otherwise it will run themodule as CommonJS. SeeDetermining module system for more details.

Packages#

This section was moved toModules: Packages.

import Specifiers#

Terminology#

Thespecifier of animport statement is the string after thefrom keyword,e.g.'node:path' inimport { sep } from 'node:path'. Specifiers are alsoused inexport from statements, and as the argument to animport()expression.

There are three types of specifiers:

  • Relative specifiers like'./startup.js' or'../config.mjs'. They referto a path relative to the location of the importing file.The file extensionis always necessary for these.

  • Bare specifiers like'some-package' or'some-package/shuffle'. They canrefer to the main entry point of a package by the package name, or aspecific feature module within a package prefixed by the package name as perthe examples respectively.Including the file extension is only necessaryfor packages without an"exports" field.

  • Absolute specifiers like'file:///opt/nodejs/config.js'. They referdirectly and explicitly to a full path.

Bare specifier resolutions are handled by theNode.js moduleresolution and loading algorithm.All other specifier resolutions are always only resolved withthe standard relativeURL resolution semantics.

Like in CommonJS, module files within packages can be accessed by appending apath to the package name unless the package'spackage.json contains an"exports" field, in which case files within packages can only be accessedvia the paths defined in"exports".

For details on these package resolution rules that apply to bare specifiers inthe Node.js module resolution, see thepackages documentation.

Mandatory file extensions#

A file extension must be provided when using theimport keyword to resolverelative or absolute specifiers. Directory indexes (e.g.'./startup/index.js')must also be fully specified.

This behavior matches howimport behaves in browser environments, assuming atypically configured server.

URLs#

ES modules are resolved and cached as URLs. This means that special charactersmust bepercent-encoded, such as# with%23 and? with%3F.

file:,node:, anddata: URL schemes are supported. A specifier like'https://example.com/app.js' is not supported natively in Node.js unless usingacustom HTTPS loader.

file: URLs#

Modules are loaded multiple times if theimport specifier used to resolvethem has a different query or fragment.

import'./foo.mjs?query=1';// loads ./foo.mjs with query of "?query=1"import'./foo.mjs?query=2';// loads ./foo.mjs with query of "?query=2"

The volume root may be referenced via/,//, orfile:///. Given thedifferences betweenURL and path resolution (such as percent encodingdetails), it is recommended to useurl.pathToFileURL when importing a path.

data: imports#
Added in: v12.10.0

data: URLs are supported for importing with the following MIME types:

  • text/javascript for ES modules
  • application/json for JSON
  • application/wasm for Wasm
import'data:text/javascript,console.log("hello!");';import _from'data:application/json,"world!"'with {type:'json' };

data: URLs only resolvebare specifiers for builtin modulesandabsolute specifiers. Resolvingrelative specifiers does not work becausedata: is not aspecial scheme. For example, attempting to load./foofromdata:text/javascript,import "./foo"; fails to resolve because thereis no concept of relative resolution fordata: URLs.

node: imports#
History
VersionChanges
v16.0.0, v14.18.0

Addednode: import support torequire(...).

v14.13.1, v12.20.0

Added in: v14.13.1, v12.20.0

node: URLs are supported as an alternative means to load Node.js builtinmodules. This URL scheme allows for builtin modules to be referenced by validabsolute URL strings.

import fsfrom'node:fs/promises';

Import attributes#

History
VersionChanges
v21.0.0, v20.10.0, v18.20.0

Switch from Import Assertions to Import Attributes.

v17.1.0, v16.14.0

Added in: v17.1.0, v16.14.0

Import attributes are an inline syntax for module importstatements to pass on more information alongside the module specifier.

import fooDatafrom'./foo.json'with {type:'json' };const {default: barData } =awaitimport('./bar.json', {with: {type:'json' } });

Node.js only supports thetype attribute, for which it supports the following values:

AttributetypeNeeded for
'json'JSON modules

Thetype: 'json' attribute is mandatory when importing JSON modules.

Built-in modules#

Built-in modules provide named exports of their public API. Adefault export is also provided which is the value of the CommonJS exports.The default export can be used for, among other things, modifying the namedexports. Named exports of built-in modules are updated only by callingmodule.syncBuiltinESMExports().

importEventEmitterfrom'node:events';const e =newEventEmitter();
import { readFile }from'node:fs';readFile('./foo.txt',(err, source) => {if (err) {console.error(err);  }else {console.log(source);  }});
import fs, { readFileSync }from'node:fs';import { syncBuiltinESMExports }from'node:module';import {Buffer }from'node:buffer';fs.readFileSync =() =>Buffer.from('Hello, ESM');syncBuiltinESMExports();fs.readFileSync === readFileSync;

When importing built-in modules, all the named exports (i.e. properties of the module exports object)are populated even if they are not individually accessed.This can make initial imports of built-in modules slightly slower compared to loading them withrequire() orprocess.getBuiltinModule(), where the module exports object is evaluated immediately,but some of its properties may only be initialized when first accessed individually.

import() expressions#

Dynamicimport() provides an asynchronous way to import modules. It issupported in both CommonJS and ES modules, and can be used to load both CommonJSand ES modules.

import.meta#

Theimport.meta meta property is anObject that contains the followingproperties. It is only supported in ES modules.

import.meta.dirname#

History
VersionChanges
v24.0.0, v22.16.0

This property is no longer experimental.

v21.2.0, v20.11.0

Added in: v21.2.0, v20.11.0

  • Type:<string> The directory name of the current module.

This is the same as thepath.dirname() of theimport.meta.filename.

Caveat: only present onfile: modules.

import.meta.filename#

History
VersionChanges
v24.0.0, v22.16.0

This property is no longer experimental.

v21.2.0, v20.11.0

Added in: v21.2.0, v20.11.0

  • Type:<string> The full absolute path and filename of the current module, withsymlinks resolved.

This is the same as theurl.fileURLToPath() of theimport.meta.url.

Caveat only local modules support this property. Modules not using thefile: protocol will not provide it.

import.meta.url#

  • Type:<string> The absolutefile: URL of the module.

This is defined exactly the same as it is in browsers providing the URL of thecurrent module file.

This enables useful patterns such as relative file loading:

import { readFileSync }from'node:fs';const buffer =readFileSync(newURL('./data.proto',import.meta.url));

import.meta.main#

Added in: v24.2.0, v22.18.0

Stability: 1.0 - Early development

  • Type:<boolean>true when the current module is the entry point of the current process;false otherwise.

Equivalent torequire.main === module in CommonJS.

Analogous to Python's__name__ == "__main__".

exportfunctionfoo() {return'Hello, world';}functionmain() {const message =foo();console.log(message);}if (import.meta.main)main();// `foo` can be imported from another module without possible side-effects from `main`

import.meta.resolve(specifier)#

History
VersionChanges
v20.6.0, v18.19.0

No longer behind--experimental-import-meta-resolve CLI flag, except for the non-standardparentURL parameter.

v20.6.0, v18.19.0

This API no longer throws when targetingfile: URLs that do not map to an existing file on the local FS.

v20.0.0, v18.19.0

This API now returns a string synchronously instead of a Promise.

v16.2.0, v14.18.0

Add support for WHATWGURL object toparentURL parameter.

v13.9.0, v12.16.2

Added in: v13.9.0, v12.16.2

Stability: 1.2 - Release candidate

  • specifier<string> The module specifier to resolve relative to thecurrent module.
  • Returns:<string> The absolute URL string that the specifier would resolve to.

import.meta.resolve is a module-relative resolution function scoped toeach module, returning the URL string.

const dependencyAsset =import.meta.resolve('component-lib/asset.css');// file:///app/node_modules/component-lib/asset.cssimport.meta.resolve('./dep.js');// file:///app/dep.js

All features of the Node.js module resolution are supported. Dependencyresolutions are subject to the permitted exports resolutions within the package.

Caveats:

  • This can result in synchronous file-system operations, whichcan impact performance similarly torequire.resolve.
  • This feature is not available within custom loaders (it wouldcreate a deadlock).

Non-standard API:

When using the--experimental-import-meta-resolve flag, that function acceptsa second argument:

  • parent<string> |<URL> An optional absolute parent module URL to resolve from.Default:import.meta.url

Interoperability with CommonJS#

import statements#

Animport statement can reference an ES module or a CommonJS module.import statements are permitted only in ES modules, but dynamicimport()expressions are supported in CommonJS for loading ES modules.

When importingCommonJS modules, themodule.exports object is provided as the default export. Named exports may beavailable, provided by static analysis as a convenience for better ecosystemcompatibility.

require#

The CommonJS modulerequire currently only supports loading synchronous ESmodules (that is, ES modules that do not use top-levelawait).

SeeLoading ECMAScript modules usingrequire() for details.

CommonJS Namespaces#

History
VersionChanges
v23.0.0

Added'module.exports' export marker to CJS namespaces.

v14.13.0

Added in: v14.13.0

CommonJS modules consist of amodule.exports object which can be of any type.

To support this, when importing CommonJS from an ECMAScript module, a namespacewrapper for the CommonJS module is constructed, which always provides adefault export key pointing to the CommonJSmodule.exports value.

In addition, a heuristic static analysis is performed against the source text ofthe CommonJS module to get a best-effort static list of exports to provide onthe namespace from values onmodule.exports. This is necessary since thesenamespaces must be constructed prior to the evaluation of the CJS module.

These CommonJS namespace objects also provide thedefault export as a'module.exports' named export, in order to unambiguously indicate that theirrepresentation in CommonJS uses this value, and not the namespace value. Thismirrors the semantics of the handling of the'module.exports' export name inrequire(esm) interop support.

When importing a CommonJS module, it can be reliably imported using the ESmodule default import or its corresponding sugar syntax:

import {defaultas cjs }from'cjs';// Identical to the aboveimport cjsSugarfrom'cjs';console.log(cjs);console.log(cjs === cjsSugar);// Prints://   <module.exports>//   true

This Module Namespace Exotic Object can be directly observed either when usingimport * as m from 'cjs' or a dynamic import:

import *as mfrom'cjs';console.log(m);console.log(m ===awaitimport('cjs'));// Prints://   [Module] { default: <module.exports>, 'module.exports': <module.exports> }//   true

For better compatibility with existing usage in the JS ecosystem, Node.jsin addition attempts to determine the CommonJS named exports of every importedCommonJS module to provide them as separate ES module exports using a staticanalysis process.

For example, consider a CommonJS module written:

// cjs.cjsexports.name ='exported';

The preceding module supports named imports in ES modules:

import { name }from'./cjs.cjs';console.log(name);// Prints: 'exported'import cjsfrom'./cjs.cjs';console.log(cjs);// Prints: { name: 'exported' }import *as mfrom'./cjs.cjs';console.log(m);// Prints://   [Module] {//     default: { name: 'exported' },//     'module.exports': { name: 'exported' },//     name: 'exported'//   }

As can be seen from the last example of the Module Namespace Exotic Object beinglogged, thename export is copied off of themodule.exports object and setdirectly on the ES module namespace when the module is imported.

Live binding updates or new exports added tomodule.exports are not detectedfor these named exports.

The detection of named exports is based on common syntax patterns but does notalways correctly detect named exports. In these cases, using the defaultimport form described above can be a better option.

Named exports detection covers many common export patterns, reexport patternsand build tool and transpiler outputs. Seecjs-module-lexer for the exactsemantics implemented.

Differences between ES modules and CommonJS#

Norequire,exports, ormodule.exports#

In most cases, the ES moduleimport can be used to load CommonJS modules.

If needed, arequire function can be constructed within an ES module usingmodule.createRequire().

No__filename or__dirname#

These CommonJS variables are not available in ES modules.

__filename and__dirname use cases can be replicated viaimport.meta.filename andimport.meta.dirname.

No Addon Loading#

Addons are not currently supported with ES module imports.

They can instead be loaded withmodule.createRequire() orprocess.dlopen.

Norequire.main#

To replacerequire.main === module, there is theimport.meta.main API.

Norequire.resolve#

Relative resolution can be handled vianew URL('./local', import.meta.url).

For a completerequire.resolve replacement, there is theimport.meta.resolve API.

Alternativelymodule.createRequire() can be used.

NoNODE_PATH#

NODE_PATH is not part of resolvingimport specifiers. Please use symlinksif this behavior is desired.

Norequire.extensions#

require.extensions is not used byimport. Module customization hooks canprovide a replacement.

Norequire.cache#

require.cache is not used byimport as the ES module loader has its ownseparate cache.

JSON modules#

History
VersionChanges
v23.1.0, v22.12.0, v20.18.3, v18.20.5

JSON modules are no longer experimental.

JSON files can be referenced byimport:

import packageConfigfrom'./package.json'with {type:'json' };

Thewith { type: 'json' } syntax is mandatory; seeImport Attributes.

The imported JSON only exposes adefault export. There is no support for namedexports. A cache entry is created in the CommonJS cache to avoid duplication.The same object is returned in CommonJS if the JSON module has already beenimported from the same path.

Wasm modules#

History
VersionChanges
v24.5.0, v22.19.0

Wasm modules no longer require the--experimental-wasm-modules flag.

Importing both WebAssembly module instances and WebAssembly source phaseimports is supported.

Both of these integrations are in line with theES Module Integration Proposal for WebAssembly.

Wasm Source Phase Imports#

Stability: 1.2 - Release candidate

Added in: v24.0.0

TheSource Phase Imports proposal allows theimport source keywordcombination to import aWebAssembly.Module object directly, instead of gettinga module instance already instantiated with its dependencies.

This is useful when needing custom instantiations for Wasm, while stillresolving and loading it through the ES module integration.

For example, to create multiple instances of a module, or to pass custom importsinto a new instance oflibrary.wasm:

import source libraryModulefrom'./library.wasm';const instance1 =awaitWebAssembly.instantiate(libraryModule, importObject1);const instance2 =awaitWebAssembly.instantiate(libraryModule, importObject2);

In addition to the static source phase, there is also a dynamic variant of thesource phase via theimport.source dynamic phase import syntax:

const dynamicLibrary =awaitimport.source('./library.wasm');const instance =awaitWebAssembly.instantiate(dynamicLibrary, importObject);

JavaScript String Builtins#

Stability: 1.2 - Release candidate

Added in: v24.5.0, v22.19.0

When importing WebAssembly modules, theWebAssembly JS String Builtins Proposal is automatically enabled through theESM Integration. This allows WebAssembly modules to directly use efficientcompile-time string builtins from thewasm:js-string namespace.

For example, the following Wasm module exports a stringgetLength function usingthewasm:js-stringlength builtin:

(module  ;; Compile-time import of the string length builtin.  (import "wasm:js-string" "length" (func $string_length (param externref) (result i32)))  ;; Define getLength, taking a JS value parameter assumed to be a string,  ;; calling string length on it and returning the result.  (func $getLength (param $str externref) (result i32)    local.get $str    call $string_length  )  ;; Export the getLength function.  (export "getLength" (func $get_length)))
import { getLength }from'./string-len.wasm';getLength('foo');// Returns 3.

Wasm builtins are compile-time imports that are linked during module compilationrather than during instantiation. They do not behave like normal module graphimports and they cannot be inspected viaWebAssembly.Module.imports(mod)or virtualized unless recompiling the module using the directWebAssembly.compile API with string builtins disabled.

Importing a module in the source phase before it has been instantiated will alsouse the compile-time builtins automatically:

import source modfrom'./string-len.wasm';const {exports: { getLength } } =awaitWebAssembly.instantiate(mod, {});getLength('foo');// Also returns 3.

Wasm Instance Phase Imports#

Stability: 1.1 - Active development

Instance imports allow any.wasm files to be imported as normal modules,supporting their module imports in turn.

For example, anindex.js containing:

import *as Mfrom'./library.wasm';console.log(M);

executed under:

node index.mjs

would provide the exports interface for the instantiation oflibrary.wasm.

Reserved Wasm Namespaces#

Added in: v24.5.0, v22.19.0

When importing WebAssembly module instances, they cannot use import modulenames or import/export names that start with reserved prefixes:

  • wasm-js: - reserved in all module import names, module names and exportnames.
  • wasm: - reserved in module import names and export names (imported modulenames are allowed in order to support future builtin polyfills).

Importing a module using the above reserved names will throw aWebAssembly.LinkError.

Top-levelawait#

Added in: v14.8.0

Theawait keyword may be used in the top level body of an ECMAScript module.

Assuming ana.mjs with

exportconst five =awaitPromise.resolve(5);

And ab.mjs with

import { five }from'./a.mjs';console.log(five);// Logs `5`
node b.mjs# works

If a top levelawait expression never resolves, thenode process will exitwith a13status code.

import { spawn }from'node:child_process';import { execPath }from'node:process';spawn(execPath, ['--input-type=module','--eval',// Never-resolving Promise:'await new Promise(() => {})',]).once('exit',(code) => {console.log(code);// Logs `13`});

Loaders#

The former Loaders documentation is now atModules: Customization hooks.

Resolution and loading algorithm#

Features#

The default resolver has the following properties:

  • FileURL-based resolution as is used by ES modules
  • Relative and absolute URL resolution
  • No default extensions
  • No folder mains
  • Bare specifier package resolution lookup through node_modules
  • Does not fail on unknown extensions or protocols
  • Can optionally provide a hint of the format to the loading phase

The default loader has the following properties

  • Support for builtin module loading vianode: URLs
  • Support for "inline" module loading viadata: URLs
  • Support forfile: module loading
  • Fails on any other URL protocol
  • Fails on unknown extensions forfile: loading(supports only.cjs,.js, and.mjs)

Resolution algorithm#

The algorithm to load an ES module specifier is given through theESM_RESOLVE method below. It returns the resolved URL for amodule specifier relative to a parentURL.

The resolution algorithm determines the full resolved URL for a moduleload, along with its suggested module format. The resolution algorithmdoes not determine whether the resolved URL protocol can be loaded,or whether the file extensions are permitted, instead these validationsare applied by Node.js during the load phase(for example, if it was asked to load a URL that has a protocol that isnotfile:,data: ornode:.

The algorithm also tries to determine the format of the file basedon the extension (seeESM_FILE_FORMAT algorithm below). If it doesnot recognize the file extension (eg if it is not.mjs,.cjs, or.json), then a format ofundefined is returned,which will throw during the load phase.

The algorithm to determine the module format of a resolved URL isprovided byESM_FILE_FORMAT, which returns the unique moduleformat for any file. The"module" format is returned for an ECMAScriptModule, while the"commonjs" format is used to indicate loading through thelegacy CommonJS loader. Additional formats such as"addon" can be extended infuture updates.

In the following algorithms, all subroutine errors are propagated as errorsof these top-level routines unless stated otherwise.

defaultConditions is the conditional environment name array,["node", "import"].

The resolver can throw the following errors:

  • Invalid Module Specifier: Module specifier is an invalid URL, package nameor package subpath specifier.
  • Invalid Package Configuration: package.json configuration is invalid orcontains an invalid configuration.
  • Invalid Package Target: Package exports or imports define a target modulefor the package that is an invalid type or string target.
  • Package Path Not Exported: Package exports do not define or permit a targetsubpath in the package for the given module.
  • Package Import Not Defined: Package imports do not define the specifier.
  • Module Not Found: The package or module requested does not exist.
  • Unsupported Directory Import: The resolved path corresponds to a directory,which is not a supported target for module imports.

Resolution Algorithm Specification#

ESM_RESOLVE(specifier,parentURL)

  1. Letresolved beundefined.
  2. Ifspecifier is a valid URL, then
    1. Setresolved to the result of parsing and reserializingspecifier as a URL.
  3. Otherwise, ifspecifier starts with"/","./", or"../", then
    1. Setresolved to the URL resolution ofspecifier relative toparentURL.
  4. Otherwise, ifspecifier starts with"#", then
    1. Setresolved to the result ofPACKAGE_IMPORTS_RESOLVE(specifier,parentURL,defaultConditions).
  5. Otherwise,
    1. Note:specifier is now a bare specifier.
    2. Setresolved the result ofPACKAGE_RESOLVE(specifier,parentURL).
  6. Letformat beundefined.
  7. Ifresolved is a"file:" URL, then
    1. Ifresolved contains any percent encodings of"/" or"\" ("%2F"and"%5C" respectively), then
      1. Throw anInvalid Module Specifier error.
    2. If the file atresolved is a directory, then
      1. Throw anUnsupported Directory Import error.
    3. If the file atresolved does not exist, then
      1. Throw aModule Not Found error.
    4. Setresolved to the real path ofresolved, maintaining thesame URL querystring and fragment components.
    5. Setformat to the result ofESM_FILE_FORMAT(resolved).
  8. Otherwise,
    1. Setformat the module format of the content type associated with theURLresolved.
  9. Returnformat andresolved to the loading phase

PACKAGE_RESOLVE(packageSpecifier,parentURL)

  1. LetpackageName beundefined.
  2. IfpackageSpecifier is an empty string, then
    1. Throw anInvalid Module Specifier error.
  3. IfpackageSpecifier is a Node.js builtin module name, then
    1. Return the string"node:" concatenated withpackageSpecifier.
  4. IfpackageSpecifier does not start with"@", then
    1. SetpackageName to the substring ofpackageSpecifier until the first"/" separator or the end of the string.
  5. Otherwise,
    1. IfpackageSpecifier does not contain a"/" separator, then
      1. Throw anInvalid Module Specifier error.
    2. SetpackageName to the substring ofpackageSpecifieruntil the second"/" separator or the end of the string.
  6. IfpackageName starts with"." or contains"\" or"%", then
    1. Throw anInvalid Module Specifier error.
  7. LetpackageSubpath be"." concatenated with the substring ofpackageSpecifier from the position at the length ofpackageName.
  8. LetselfUrl be the result ofPACKAGE_SELF_RESOLVE(packageName,packageSubpath,parentURL).
  9. IfselfUrl is notundefined, returnselfUrl.
  10. WhileparentURL is not the file system root,
    1. LetpackageURL be the URL resolution of"node_modules/"concatenated withpackageName, relative toparentURL.
    2. SetparentURL to the parent folder URL ofparentURL.
    3. If the folder atpackageURL does not exist, then
      1. Continue the next loop iteration.
    4. Letpjson be the result ofREAD_PACKAGE_JSON(packageURL).
    5. Ifpjson is notnull andpjson.exports is notnull orundefined, then
      1. Return the result ofPACKAGE_EXPORTS_RESOLVE(packageURL,packageSubpath,pjson.exports,defaultConditions).
    6. Otherwise, ifpackageSubpath is equal to".", then
      1. Ifpjson.main is a string, then
        1. Return the URL resolution ofmain inpackageURL.
    7. Otherwise,
      1. Return the URL resolution ofpackageSubpath inpackageURL.
  11. Throw aModule Not Found error.

PACKAGE_SELF_RESOLVE(packageName,packageSubpath,parentURL)

  1. LetpackageURL be the result ofLOOKUP_PACKAGE_SCOPE(parentURL).
  2. IfpackageURL isnull, then
    1. Returnundefined.
  3. Letpjson be the result ofREAD_PACKAGE_JSON(packageURL).
  4. Ifpjson isnull or ifpjson.exports isnull orundefined, then
    1. Returnundefined.
  5. Ifpjson.name is equal topackageName, then
    1. Return the result ofPACKAGE_EXPORTS_RESOLVE(packageURL,packageSubpath,pjson.exports,defaultConditions).
  6. Otherwise, returnundefined.

PACKAGE_EXPORTS_RESOLVE(packageURL,subpath,exports,conditions)

Note: This function is directly invoked by the CommonJS resolution algorithm.

  1. Ifexports is an Object with both a key starting with"." and a key notstarting with".", throw anInvalid Package Configuration error.
  2. Ifsubpath is equal to".", then
    1. LetmainExport beundefined.
    2. Ifexports is a String or Array, or an Object containing no keysstarting with".", then
      1. SetmainExport toexports.
    3. Otherwise ifexports is an Object containing a"." property, then
      1. SetmainExport toexports["."].
    4. IfmainExport is notundefined, then
      1. Letresolved be the result ofPACKAGE_TARGET_RESOLVE(packageURL,mainExport,null,false,conditions).
      2. Ifresolved is notnull orundefined, returnresolved.
  3. Otherwise, ifexports is an Object and all keys ofexports start with".", then
    1. Assert:subpath begins with"./".
    2. Letresolved be the result ofPACKAGE_IMPORTS_EXPORTS_RESOLVE(subpath,exports,packageURL,false,conditions).
    3. Ifresolved is notnull orundefined, returnresolved.
  4. Throw aPackage Path Not Exported error.

PACKAGE_IMPORTS_RESOLVE(specifier,parentURL,conditions)

Note: This function is directly invoked by the CommonJS resolution algorithm.

  1. Assert:specifier begins with"#".
  2. Ifspecifier is exactly equal to"#" or starts with"#/", then
    1. Throw anInvalid Module Specifier error.
  3. LetpackageURL be the result ofLOOKUP_PACKAGE_SCOPE(parentURL).
  4. IfpackageURL is notnull, then
    1. Letpjson be the result ofREAD_PACKAGE_JSON(packageURL).
    2. Ifpjson.imports is a non-null Object, then
      1. Letresolved be the result ofPACKAGE_IMPORTS_EXPORTS_RESOLVE(specifier,pjson.imports,packageURL,true,conditions).
      2. Ifresolved is notnull orundefined, returnresolved.
  5. Throw aPackage Import Not Defined error.

PACKAGE_IMPORTS_EXPORTS_RESOLVE(matchKey,matchObj,packageURL,isImports,conditions)

  1. IfmatchKey ends in"/", then
    1. Throw anInvalid Module Specifier error.
  2. IfmatchKey is a key ofmatchObj and does not contain"*", then
    1. Lettarget be the value ofmatchObj[matchKey].
    2. Return the result ofPACKAGE_TARGET_RESOLVE(packageURL,target,null,isImports,conditions).
  3. LetexpansionKeys be the list of keys ofmatchObj containing only asingle"*", sorted by the sorting functionPATTERN_KEY_COMPAREwhich orders in descending order of specificity.
  4. For each keyexpansionKey inexpansionKeys, do
    1. LetpatternBase be the substring ofexpansionKey up to but excludingthe first"*" character.
    2. IfmatchKey starts with but is not equal topatternBase, then
      1. LetpatternTrailer be the substring ofexpansionKey from theindex after the first"*" character.
      2. IfpatternTrailer has zero length, or ifmatchKey ends withpatternTrailer and the length ofmatchKey is greater than orequal to the length ofexpansionKey, then
        1. Lettarget be the value ofmatchObj[expansionKey].
        2. LetpatternMatch be the substring ofmatchKey starting at theindex of the length ofpatternBase up to the length ofmatchKey minus the length ofpatternTrailer.
        3. Return the result ofPACKAGE_TARGET_RESOLVE(packageURL,target,patternMatch,isImports,conditions).
  5. Returnnull.

PATTERN_KEY_COMPARE(keyA,keyB)

  1. Assert:keyA contains only a single"*".
  2. Assert:keyB contains only a single"*".
  3. LetbaseLengthA be the index of"*" inkeyA.
  4. LetbaseLengthB be the index of"*" inkeyB.
  5. IfbaseLengthA is greater thanbaseLengthB, return -1.
  6. IfbaseLengthB is greater thanbaseLengthA, return 1.
  7. If the length ofkeyA is greater than the length ofkeyB, return -1.
  8. If the length ofkeyB is greater than the length ofkeyA, return 1.
  9. Return 0.

PACKAGE_TARGET_RESOLVE(packageURL,target,patternMatch,isImports,conditions)

  1. Iftarget is a String, then
    1. Iftarget does not start with"./", then
      1. IfisImports isfalse, or iftarget starts with"../" or"/", or iftarget is a valid URL, then
        1. Throw anInvalid Package Target error.
      2. IfpatternMatch is a String, then
        1. ReturnPACKAGE_RESOLVE(target with every instance of"*"replaced bypatternMatch,packageURL +"/").
      3. ReturnPACKAGE_RESOLVE(target,packageURL +"/").
    2. Iftarget split on"/" or"\" contains any"",".","..",or"node_modules" segments after the first"." segment, caseinsensitive and including percent encoded variants, throw anInvalidPackage Target error.
    3. LetresolvedTarget be the URL resolution of the concatenation ofpackageURL andtarget.
    4. Assert:packageURL is contained inresolvedTarget.
    5. IfpatternMatch isnull, then
      1. ReturnresolvedTarget.
    6. IfpatternMatch split on"/" or"\" contains any"",".","..", or"node_modules" segments, case insensitive and includingpercent encoded variants, throw anInvalid Module Specifier error.
    7. Return the URL resolution ofresolvedTarget with every instance of"*" replaced withpatternMatch.
  2. Otherwise, iftarget is a non-null Object, then
    1. Iftarget contains any index property keys, as defined in ECMA-2626.1.7 Array Index, throw anInvalid Package Configuration error.
    2. For each propertyp oftarget, in object insertion order as,
      1. Ifp equals"default" orconditions contains an entry forp,then
        1. LettargetValue be the value of thep property intarget.
        2. Letresolved be the result ofPACKAGE_TARGET_RESOLVE(packageURL,targetValue,patternMatch,isImports,conditions).
        3. Ifresolved is equal toundefined, continue the loop.
        4. Returnresolved.
    3. Returnundefined.
  3. Otherwise, iftarget is an Array, then
    1. If _target.length is zero, returnnull.
    2. For each itemtargetValue intarget, do
      1. Letresolved be the result ofPACKAGE_TARGET_RESOLVE(packageURL,targetValue,patternMatch,isImports,conditions), continuing the loop on anyInvalid Package Targeterror.
      2. Ifresolved isundefined, continue the loop.
      3. Returnresolved.
    3. Return or throw the last fallback resolutionnull return or error.
  4. Otherwise, iftarget isnull, returnnull.
  5. Otherwise throw anInvalid Package Target error.

ESM_FILE_FORMAT(url)

  1. Assert:url corresponds to an existing file.
  2. Ifurl ends in".mjs", then
    1. Return"module".
  3. Ifurl ends in".cjs", then
    1. Return"commonjs".
  4. Ifurl ends in".json", then
    1. Return"json".
  5. Ifurl ends in".wasm", then
    1. Return"wasm".
  6. If--experimental-addon-modules is enabled andurl ends in".node", then
    1. Return"addon".
  7. LetpackageURL be the result ofLOOKUP_PACKAGE_SCOPE(url).
  8. Letpjson be the result ofREAD_PACKAGE_JSON(packageURL).
  9. LetpackageType benull.
  10. Ifpjson?.type is"module" or"commonjs", then
    1. SetpackageType topjson.type.
  11. Ifurl ends in".js", then
    1. IfpackageType is notnull, then
      1. ReturnpackageType.
    2. If the result ofDETECT_MODULE_SYNTAX(source) is true, then
      1. Return"module".
    3. Return"commonjs".
  12. Ifurl does not have any extension, then
    1. IfpackageType is"module" and the file aturl contains the"application/wasm" content type header for a WebAssembly module, then
      1. Return"wasm".
    2. IfpackageType is notnull, then
      1. ReturnpackageType.
    3. If the result ofDETECT_MODULE_SYNTAX(source) is true, then
      1. Return"module".
    4. Return"commonjs".
  13. Returnundefined (will throw during load phase).

LOOKUP_PACKAGE_SCOPE(url)

  1. LetscopeURL beurl.
  2. WhilescopeURL is not the file system root,
    1. SetscopeURL to the parent URL ofscopeURL.
    2. IfscopeURL ends in a"node_modules" path segment, returnnull.
    3. LetpjsonURL be the resolution of"package.json" withinscopeURL.
    4. if the file atpjsonURL exists, then
      1. ReturnscopeURL.
  3. Returnnull.

READ_PACKAGE_JSON(packageURL)

  1. LetpjsonURL be the resolution of"package.json" withinpackageURL.
  2. If the file atpjsonURL does not exist, then
    1. Returnnull.
  3. If the file atpackageURL does not parse as valid JSON, then
    1. Throw anInvalid Package Configuration error.
  4. Return the parsed JSON source of the file atpjsonURL.

DETECT_MODULE_SYNTAX(source)

  1. Parsesource as an ECMAScript module.
  2. If the parse is successful, then
    1. Ifsource contains top-levelawait, staticimport orexportstatements, orimport.meta, returntrue.
    2. Ifsource contains a top-level lexical declaration (const,let,orclass) of any of the CommonJS wrapper variables (require,exports,module,__filename, or__dirname) then returntrue.
  3. Else returnfalse.

Customizing ESM specifier resolution algorithm#

Module customization hooks provide a mechanism for customizing the ESMspecifier resolution algorithm. An example that provides CommonJS-styleresolution for ESM specifiers iscommonjs-extension-resolution-loader.