Skip to content
Permalink
Browse files
esm: unflag --experimental-modules
PR-URL: #29866
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Myles Borins <myles.borins@gmail.com>
  • Loading branch information
guybedford authored and MylesBorins committed Nov 12, 2019
1 parent cc6f99d commit 796f3d0af49164314868c4778af90eca356f1fef
Showing 95 changed files with 194 additions and 331 deletions.
@@ -161,8 +161,8 @@ Currently, overriding `Error.prepareStackTrace` is ignored when the
added: v12.0.0
-->

To be used in conjunction with `--experimental-modules`. Sets the resolution
algorithm for resolving specifiers. Valid options are `explicit` and `node`.
Sets the resolution algorithm for resolving ES module specifiers. Valid options
are `explicit` and `node`.

The default is `explicit`, which requires providing the full path to a
module. The `node` mode will enable support for optional file extensions and
@@ -191,7 +191,8 @@ Enable experimental JSON support for the ES Module loader.
added: v8.5.0
-->

Enable experimental ES module support and caching modules.
Enable latest experimental modules features (currently
`--experimental-conditional-exports` and `--experimental-self-resolve`).

### `--experimental-policy`
<!-- YAML
@@ -342,9 +343,8 @@ Specify ICU data load path. (Overrides `NODE_ICU_DATA`.)
added: v12.0.0
-->

Used with `--experimental-modules`, this configures Node.js to interpret string
input as CommonJS or as an ES module. String input is input via `--eval`,
`--print`, or `STDIN`.
This configures Node.js to interpret string input as CommonJS or as an ES
module. String input is input via `--eval`, `--print`, or `STDIN`.

Valid values are `"commonjs"` and `"module"`. The default is `"commonjs"`.

@@ -409,7 +409,7 @@ endpoint on `http://host:port/json/list`.
added: v9.0.0
-->

Specify the `module` of a custom [experimental ECMAScript Module][] loader.
Specify the `module` of a custom [experimental ECMAScript Module loader][].
`module` may be either a path to a file, or an ECMAScript Module name.

### `--max-http-header-size=size`
@@ -1330,7 +1330,7 @@ greater than `4` (its current default value). For more information, see the
[debugger]: debugger.html
[debugging security implications]: https://nodejs.org/en/docs/guides/debugging-getting-started/#security-implications
[emit_warning]: process.html#process_process_emitwarning_warning_type_code_ctor
[experimental ECMAScript Module]: esm.html#esm_resolve_hook
[experimental ECMAScript Module loader]: esm.html#esm_resolve_hook
[libuv threadpool documentation]: http://docs.libuv.org/en/latest/threadpool.html
[remote code execution]: https://www.owasp.org/index.php/Code_Injection
[context-aware]: addons.html#addons_context_aware_addons
@@ -27,12 +27,9 @@ specifier resolution, and default behavior.

<!-- type=misc -->

The `--experimental-modules` flag can be used to enable support for
ECMAScript modules (ES modules).

Once enabled, Node.js will treat the following as ES modules when passed to
`node` as the initial input, or when referenced by `import` statements within
ES module code:
Experimental support for ECMAScript modules is enabled by default.
Node.js will treat the following as ES modules when passed to `node` as the
initial input, or when referenced by `import` statements within ES module code:

* Files ending in `.mjs`.

@@ -80,7 +77,7 @@ until the root of the volume is reached.

```sh
# In same folder as above package.json
node --experimental-modules my-app.js # Runs as ES module
node my-app.js # Runs as ES module
```

If the nearest parent `package.json` lacks a `"type"` field, or contains
@@ -114,9 +111,8 @@ own `package.json` file, so each project’s dependencies have their own package
scopes. A `package.json` lacking a `"type"` field is treated as if it contained
`"type": "commonjs"`.

The package scope applies not only to initial entry points (`node
--experimental-modules my-app.js`) but also to files referenced by `import`
statements and `import()` expressions.
The package scope applies not only to initial entry points (`node my-app.js`)
but also to files referenced by `import` statements and `import()` expressions.

```js
// my-app.js, in an ES module package scope because there is a package.json
@@ -169,11 +165,9 @@ piped to `node` via `STDIN`, will be treated as ES modules when the
`--input-type=module` flag is set.

```sh
node --experimental-modules --input-type=module --eval \
"import { sep } from 'path'; console.log(sep);"
node --input-type=module --eval "import { sep } from 'path'; console.log(sep);"
echo "import { sep } from 'path'; console.log(sep);" | \
node --experimental-modules --input-type=module
echo "import { sep } from 'path'; console.log(sep);" | node --input-type=module
```

For completeness there is also `--input-type=commonjs`, for explicitly running
@@ -927,8 +921,8 @@ The `--experimental-json-modules` flag is needed for the module
to work.
```bash
node --experimental-modules index.mjs # fails
node --experimental-modules --experimental-json-modules index.mjs # works
node index.mjs # fails
node --experimental-json-modules index.mjs # works
```
## Experimental Wasm Modules
@@ -950,7 +944,7 @@ console.log(M);
executed under:
```bash
node --experimental-modules --experimental-wasm-modules index.mjs
node --experimental-wasm-modules index.mjs
```
would provide the exports interface for the instantiation of `module.wasm`.
@@ -1061,7 +1055,7 @@ export async function resolve(specifier,
With this loader, running:
```console
NODE_OPTIONS='--experimental-modules --experimental-loader ./custom-loader.mjs' node x.js
NODE_OPTIONS='--experimental-loader ./custom-loader.mjs' node x.js
```
would load the module `x.js` as an ES module with relative resolution support
@@ -1352,11 +1346,11 @@ automatic extension resolution and importing from directories that include an
index file use the `node` mode.
```bash
$ node --experimental-modules index.mjs
$ node index.mjs
success!
$ node --experimental-modules index #Failure!
$ node index # Failure!
Error: Cannot find module
$ node --experimental-modules --es-module-specifier-resolution=node index
$ node --es-module-specifier-resolution=node index
success!
```
@@ -88,8 +88,8 @@ changes:
* `importModuleDynamically` {Function} Called during evaluation of this module
when `import()` is called. If this option is not specified, calls to
`import()` will reject with [`ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING`][].
This option is part of the experimental API for the `--experimental-modules`
flag, and should not be considered stable.
This option is part of the experimental modules API, and should not be
considered stable.
* `specifier` {string} specifier passed to `import()`
* `module` {vm.Module}
* Returns: {Module Namespace Object|vm.Module} Returning a `vm.Module` is
@@ -854,8 +854,8 @@ changes:
* `importModuleDynamically` {Function} Called during evaluation of this module
when `import()` is called. If this option is not specified, calls to
`import()` will reject with [`ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING`][].
This option is part of the experimental API for the `--experimental-modules`
flag, and should not be considered stable.
This option is part of the experimental modules API, and should not be
considered stable.
* `specifier` {string} specifier passed to `import()`
* `module` {vm.Module}
* Returns: {Module Namespace Object|vm.Module} Returning a `vm.Module` is
@@ -951,8 +951,8 @@ changes:
* `importModuleDynamically` {Function} Called during evaluation of this module
when `import()` is called. If this option is not specified, calls to
`import()` will reject with [`ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING`][].
This option is part of the experimental API for the `--experimental-modules`
flag, and should not be considered stable.
This option is part of the experimental modules API, and should not be
considered stable.
* `specifier` {string} specifier passed to `import()`
* `module` {vm.Module}
* Returns: {Module Namespace Object|vm.Module} Returning a `vm.Module` is
@@ -1028,8 +1028,8 @@ changes:
* `importModuleDynamically` {Function} Called during evaluation of this module
when `import()` is called. If this option is not specified, calls to
`import()` will reject with [`ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING`][].
This option is part of the experimental API for the `--experimental-modules`
flag, and should not be considered stable.
This option is part of the experimental modules API, and should not be
considered stable.
* `specifier` {string} specifier passed to `import()`
* `module` {vm.Module}
* Returns: {Module Namespace Object|vm.Module} Returning a `vm.Module` is
@@ -120,7 +120,7 @@ Enable experimental support for "require" and "node" conditional export targets.
Enable experimental JSON interop support for the ES Module loader.
.
.It Fl -experimental-modules
Enable experimental ES module support and caching modules.
Enable experimental latest experimental modules features.
.
.It Fl -experimental-resolve-self
Enable experimental support for a package to load itself.
@@ -208,8 +208,7 @@ It uses the Chrome DevTools Protocol.
.It Fl -experimental-loader Ns = Ns Ar module
Specify the
.Ar module
as a custom loader, to load
.Fl -experimental-modules .
to use as a custom module loader.
.
.It Fl -max-http-header-size Ns = Ns Ar size
Specify the maximum size of HTTP headers in bytes. Defaults to 8KB.
@@ -211,23 +211,21 @@ function requireWithFallbackInDeps(request) {
}

// This is exposed for public loaders
NativeModule.prototype.compileForPublicLoader = function(needToSyncExports) {
NativeModule.prototype.compileForPublicLoader = function() {
if (!this.canBeRequiredByUsers) {
// No code because this is an assertion against bugs
// eslint-disable-next-line no-restricted-syntax
throw new Error(`Should not compile ${this.id} for public use`);
}
this.compile();
if (needToSyncExports) {
if (!this.exportKeys) {
// When using --expose-internals, we do not want to reflect the named
// exports from core modules as this can trigger unnecessary getters.
const internal = this.id.startsWith('internal/');
this.exportKeys = internal ? [] : Object.keys(this.exports);
}
this.getESMFacade();
this.syncExports();
if (!this.exportKeys) {
// When using --expose-internals, we do not want to reflect the named
// exports from core modules as this can trigger unnecessary getters.
const internal = this.id.startsWith('internal/');
this.exportKeys = internal ? [] : Object.keys(this.exports);
}
this.getESMFacade();
this.syncExports();
return this.exports;
};

@@ -401,24 +401,15 @@ function initializeESMLoader() {
// Create this WeakMap in js-land because V8 has no C++ API for WeakMap.
internalBinding('module_wrap').callbackMap = new SafeWeakMap();

const experimentalModules = getOptionValue('--experimental-modules');
const experimentalVMModules = getOptionValue('--experimental-vm-modules');
if (experimentalModules || experimentalVMModules) {
if (experimentalModules) {
process.emitWarning(
'The ESM module loader is experimental.',
'ExperimentalWarning', undefined);
}
const {
setImportModuleDynamicallyCallback,
setInitializeImportMetaObjectCallback
} = internalBinding('module_wrap');
const esm = require('internal/process/esm_loader');
// Setup per-isolate callbacks that locate data or callbacks that we keep
// track of for different ESM modules.
setInitializeImportMetaObjectCallback(esm.initializeImportMetaObject);
setImportModuleDynamicallyCallback(esm.importModuleDynamicallyCallback);
}
const {
setImportModuleDynamicallyCallback,
setInitializeImportMetaObjectCallback
} = internalBinding('module_wrap');
const esm = require('internal/process/esm_loader');
// Setup per-isolate callbacks that locate data or callbacks that we keep
// track of for different ESM modules.
setInitializeImportMetaObjectCallback(esm.initializeImportMetaObject);
setImportModuleDynamicallyCallback(esm.importModuleDynamicallyCallback);
}

function initializeFrozenIntrinsics() {
@@ -460,9 +451,6 @@ function resolveMainPath(main) {
}

function shouldUseESMLoader(mainPath) {
const experimentalModules = getOptionValue('--experimental-modules');
if (!experimentalModules)
return false;
const userLoader = getOptionValue('--experimental-loader');
if (userLoader)
return true;
@@ -47,21 +47,18 @@ if (process.argv[1] && process.argv[1] !== '-') {

function checkSyntax(source, filename) {
const { getOptionValue } = require('internal/options');
const experimentalModules = getOptionValue('--experimental-modules');
if (experimentalModules) {
let isModule = false;
if (filename === '[stdin]' || filename === '[eval]') {
isModule = getOptionValue('--input-type') === 'module';
} else {
const resolve = require('internal/modules/esm/default_resolve');
const { format } = resolve(pathToFileURL(filename).toString());
isModule = format === 'module';
}
if (isModule) {
const { ModuleWrap } = internalBinding('module_wrap');
new ModuleWrap(filename, undefined, source, 0, 0);
return;
}
let isModule = false;
if (filename === '[stdin]' || filename === '[eval]') {
isModule = getOptionValue('--input-type') === 'module';
} else {
const resolve = require('internal/modules/esm/default_resolve');
const { format } = resolve(pathToFileURL(filename).toString());
isModule = format === 'module';
}
if (isModule) {
const { ModuleWrap } = internalBinding('module_wrap');
new ModuleWrap(filename, undefined, source, 0, 0);
return;
}

wrapSafe(filename, source);
@@ -10,7 +10,6 @@ const CJSModule = require('internal/modules/cjs/loader').Module;

markBootstrapComplete();

// Note: this loads the module through the ESM loader if
// --experimental-loader is provided or --experimental-modules is on
// and the module is determined to be an ES module
// Note: this loads the module through the ESM loader if the module is
// determined to be an ES module
CJSModule.runMain(process.argv[1]);
@@ -6,8 +6,6 @@ const {
ERR_UNKNOWN_BUILTIN_MODULE
} = require('internal/errors').codes;
const { NativeModule } = require('internal/bootstrap/loaders');
const { getOptionValue } = require('internal/options');
const experimentalModules = getOptionValue('--experimental-modules');

const { validateString } = require('internal/validators');
const path = require('path');
@@ -16,11 +14,11 @@ const { URL } = require('url');

const debug = require('internal/util/debuglog').debuglog('module');

function loadNativeModule(filename, request, experimentalModules) {
function loadNativeModule(filename, request) {
const mod = NativeModule.map.get(filename);
if (mod) {
debug('load native module %s', request);
mod.compileForPublicLoader(experimentalModules);
mod.compileForPublicLoader();
return mod;
}
}
@@ -45,10 +43,7 @@ function makeRequireFunction(mod, redirects) {
const href = destination.href;
if (destination.protocol === 'node:') {
const specifier = destination.pathname;
const mod = loadNativeModule(
specifier,
href,
experimentalModules);
const mod = loadNativeModule(specifier, href);
if (mod && mod.canBeRequiredByUsers) {
return mod.exports;
}

0 comments on commit 796f3d0

Please sign in to comment.