esm: unflag --experimental-wasm-modules

PR-URL: https://github.com/nodejs/node/pull/57038
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Stephen Belanger <admin@stephenbelanger.com>
Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
This commit is contained in:
Guy Bedford 2025-02-13 10:44:56 -08:00 committed by Guy Bedford
parent ec2b74a7dc
commit 0df15188d7
13 changed files with 49 additions and 89 deletions

View file

@ -33,8 +33,7 @@ If a file is found, its path will be passed to the
* The program was started with a command-line flag that forces the entry
point to be loaded with ECMAScript module loader, such as `--import`.
* The file has an `.mjs` or `.wasm` (with `--experimental-wasm-modules`)
extension.
* The file has an `.mjs` or `.wasm` extension.
* The file does not have a `.cjs` extension, and the nearest parent
`package.json` file contains a top-level [`"type"`][] field with a value of
`"module"`.
@ -49,7 +48,6 @@ entry point, the `node` command will accept as input only files with `.js`,
`.mjs`, or `.cjs` extensions. With the following flags, additional file
extensions are enabled:
* [`--experimental-wasm-modules`][] for files with `.wasm` extension.
* [`--experimental-addon-modules`][] for files with `.node` extension.
## Options
@ -1255,14 +1253,6 @@ changes:
Enable experimental WebAssembly System Interface (WASI) support.
### `--experimental-wasm-modules`
<!-- YAML
added: v12.3.0
-->
Enable experimental WebAssembly module support.
### `--experimental-webstorage`
<!-- YAML
@ -3404,7 +3394,6 @@ one is included in the list below.
* `--experimental-transform-types`
* `--experimental-vm-modules`
* `--experimental-wasi-unstable-preview1`
* `--experimental-wasm-modules`
* `--experimental-webstorage`
* `--force-context-aware`
* `--force-fips`
@ -3984,7 +3973,6 @@ node --stack-trace-limit=12 -p -e "Error.stackTraceLimit" # prints 12
[`--env-file`]: #--env-filefile
[`--experimental-addon-modules`]: #--experimental-addon-modules
[`--experimental-sea-config`]: single-executable-applications.md#generating-single-executable-preparation-blobs
[`--experimental-wasm-modules`]: #--experimental-wasm-modules
[`--heap-prof-dir`]: #--heap-prof-dir
[`--import`]: #--importmodule
[`--no-experimental-strip-types`]: #--no-experimental-strip-types

View file

@ -705,34 +705,23 @@ imported from the same path.
## Wasm modules
> Stability: 1 - Experimental
<!-- YAML
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/57038
description: Wasm modules no longer require the `--experimental-wasm-modules` flag.
-->
Importing both WebAssembly module instances and WebAssembly source phase
imports are supported under the `--experimental-wasm-modules` flag.
imports is supported.
Both of these integrations are in line with the
[ES Module Integration Proposal for WebAssembly][].
Instance imports allow any `.wasm` files to be imported as normal modules,
supporting their module imports in turn.
For example, an `index.js` containing:
```js
import * as M from './library.wasm';
console.log(M);
```
executed under:
```bash
node --experimental-wasm-modules index.mjs
```
would provide the exports interface for the instantiation of `library.wasm`.
### Wasm Source Phase Imports
> Stability: 1.2 - Release candidate
<!-- YAML
added: v24.0.0
-->
@ -766,6 +755,8 @@ const instance = await WebAssembly.instantiate(dynamicLibrary, importObject);
### JavaScript String Builtins
> Stability: 1.2 - Release candidate
<!-- YAML
added: REPLACEME
-->
@ -815,14 +806,36 @@ const { exports: { getLength } } = await WebAssembly.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, an `index.js` containing:
```js
import * as M from './library.wasm';
console.log(M);
```
executed under:
```bash
node index.mjs
```
would provide the exports interface for the instantiation of `library.wasm`.
### Reserved Wasm Namespaces
<!-- YAML
added: REPLACEME
-->
When importing WebAssembly modules through the ESM Integration, they cannot use
import module names or import/export names that start with reserved prefixes:
When importing WebAssembly module instances, they cannot use import module
names or import/export names that start with reserved prefixes:
* `wasm-js:` - reserved in all module import names, module names and export
names.
@ -1189,7 +1202,7 @@ _isImports_, _conditions_)
> 1. Return _"commonjs"_.
> 4. If _url_ ends in _".json"_, then
> 1. Return _"json"_.
> 5. If `--experimental-wasm-modules` is enabled and _url_ ends in
> 5. If _url_ ends in
> _".wasm"_, then
> 1. Return _"wasm"_.
> 6. If `--experimental-addon-modules` is enabled and _url_ ends in
@ -1207,9 +1220,8 @@ _isImports_, _conditions_)
> 1. Return _"module"_.
> 3. Return _"commonjs"_.
> 12. If _url_ does not have any extension, then
> 1. If _packageType_ is _"module"_ and `--experimental-wasm-modules` is
> enabled and the file at _url_ contains the header for a WebAssembly
> module, then
> 1. If _packageType_ is _"module"_ and the file at _url_ contains the
> "application/wasm" content type header for a WebAssembly module, then
> 1. Return _"wasm"_.
> 2. If _packageType_ is not **null**, then
> 1. Return _packageType_.

View file

@ -180,9 +180,6 @@
"experimental-vm-modules": {
"type": "boolean"
},
"experimental-wasm-modules": {
"type": "boolean"
},
"experimental-websocket": {
"type": "boolean"
},

View file

@ -223,9 +223,6 @@ Enable experimental ES module support in VM module.
Enable experimental WebAssembly System Interface support. This
flag is no longer required as WASI is enabled by default.
.
.It Fl -experimental-wasm-modules
Enable experimental WebAssembly module support.
.
.It Fl -experimental-quic
Enable the experimental QUIC support.
.

View file

@ -9,7 +9,6 @@ const { getValidatedPath } = require('internal/fs/utils');
const fsBindings = internalBinding('fs');
const { internal: internalConstants } = internalBinding('constants');
const experimentalWasmModules = getOptionValue('--experimental-wasm-modules');
const experimentalAddonModules = getOptionValue('--experimental-addon-modules');
const extensionFormatMap = {
@ -18,12 +17,9 @@ const extensionFormatMap = {
'.js': 'module',
'.json': 'json',
'.mjs': 'module',
'.wasm': 'wasm',
};
if (experimentalWasmModules) {
extensionFormatMap['.wasm'] = 'wasm';
}
if (experimentalAddonModules) {
extensionFormatMap['.node'] = 'addon';
}
@ -46,7 +42,7 @@ function mimeToFormat(mime) {
) !== null
) { return 'module'; }
if (mime === 'application/json') { return 'json'; }
if (experimentalWasmModules && mime === 'application/wasm') { return 'wasm'; }
if (mime === 'application/wasm') { return 'wasm'; }
return null;
}
@ -58,7 +54,6 @@ function mimeToFormat(mime) {
* @returns {'wasm'|'module'}
*/
function getFormatOfExtensionlessFile(url) {
if (!experimentalWasmModules) { return 'module'; }
const path = getValidatedPath(url);
switch (fsBindings.getFormatOfExtensionlessFile(path)) {
case internalConstants.EXTENSIONLESS_FORMAT_WASM:

View file

@ -495,8 +495,6 @@ translators.set('json', function jsonStrategy(url, source) {
*/
const wasmInstances = new SafeWeakMap();
translators.set('wasm', async function(url, source) {
emitExperimentalWarning('Importing WebAssembly modules');
assertBufferSource(source, false, 'load');
debug(`Translating WASMModule ${url}`);
@ -546,6 +544,7 @@ translators.set('wasm', async function(url, source) {
const createDynamicModule = require('internal/modules/esm/create_dynamic_module');
const { module } = createDynamicModule([...importsList], [...exportsList], url, (reflect) => {
emitExperimentalWarning('Importing WebAssembly module instances');
for (const impt of importsList) {
const importNs = reflect.imports[impt];
const wasmInstance = wasmInstances.get(importNs);

View file

@ -773,9 +773,7 @@ static ExitCode ProcessGlobalArgsInternal(std::vector<std::string>* args,
env_opts->abort_on_uncaught_exception = true;
}
if (env_opts->experimental_wasm_modules) {
v8_args.emplace_back("--js-source-phase-imports");
}
#ifdef __POSIX__
// Block SIGPROF signals when sleeping in epoll_wait/kevent/etc. Avoids the

View file

@ -536,10 +536,7 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() {
kAllowedInEnvvar);
AddAlias("--loader", "--experimental-loader");
AddOption("--experimental-modules", "", NoOp{}, kAllowedInEnvvar);
AddOption("--experimental-wasm-modules",
"experimental ES Module support for webassembly modules",
&EnvironmentOptions::experimental_wasm_modules,
kAllowedInEnvvar);
AddOption("--experimental-wasm-modules", "", NoOp{}, kAllowedInEnvvar);
AddOption("--experimental-import-meta-resolve",
"experimental ES Module import.meta.resolve() parentURL support",
&EnvironmentOptions::experimental_import_meta_resolve,

View file

@ -133,7 +133,6 @@ class EnvironmentOptions : public Options {
std::string localstorage_file;
bool experimental_global_navigator = true;
bool experimental_global_web_crypto = true;
bool experimental_wasm_modules = false;
bool experimental_import_meta_resolve = false;
std::string input_type; // Value of --input-type
bool entry_is_url = false;

View file

@ -9,7 +9,6 @@ describe('ESM: WASM modules', { concurrency: !process.env.TEST_PARALLEL }, () =>
it('should load exports', async () => {
const { code, stderr, stdout } = await spawnPromisified(execPath, [
'--no-warnings',
'--experimental-wasm-modules',
'--input-type=module',
'--eval',
[
@ -32,7 +31,6 @@ describe('ESM: WASM modules', { concurrency: !process.env.TEST_PARALLEL }, () =>
it('should not allow code injection through export names', async () => {
const { code, stderr, stdout } = await spawnPromisified(execPath, [
'--no-warnings',
'--experimental-wasm-modules',
'--input-type=module',
'--eval',
`import * as wasmExports from ${JSON.stringify(fixtures.fileURL('es-modules/export-name-code-injection.wasm'))};`,
@ -46,7 +44,6 @@ describe('ESM: WASM modules', { concurrency: !process.env.TEST_PARALLEL }, () =>
it('should allow non-identifier export names', async () => {
const { code, stderr, stdout } = await spawnPromisified(execPath, [
'--no-warnings',
'--experimental-wasm-modules',
'--input-type=module',
'--eval',
[
@ -64,7 +61,6 @@ describe('ESM: WASM modules', { concurrency: !process.env.TEST_PARALLEL }, () =>
it('should properly handle all WebAssembly global types', async () => {
const { code, stderr, stdout } = await spawnPromisified(execPath, [
'--no-warnings',
'--experimental-wasm-modules',
'--input-type=module',
'--eval',
[
@ -211,7 +207,6 @@ describe('ESM: WASM modules', { concurrency: !process.env.TEST_PARALLEL }, () =>
it('should properly escape import names as well', async () => {
const { code, stderr, stdout } = await spawnPromisified(execPath, [
'--no-warnings',
'--experimental-wasm-modules',
'--input-type=module',
'--eval',
[
@ -226,22 +221,20 @@ describe('ESM: WASM modules', { concurrency: !process.env.TEST_PARALLEL }, () =>
strictEqual(code, 0);
});
it('should emit experimental warning', async () => {
it('should emit experimental warning for module instances', async () => {
const { code, signal, stderr } = await spawnPromisified(execPath, [
'--experimental-wasm-modules',
fixtures.path('es-modules/wasm-modules.mjs'),
]);
strictEqual(code, 0);
strictEqual(signal, null);
match(stderr, /ExperimentalWarning/);
match(stderr, /WebAssembly/);
match(stderr, /Importing WebAssembly module instances/);
});
it('should support top-level execution', async () => {
const { code, stderr, stdout } = await spawnPromisified(execPath, [
'--no-warnings',
'--experimental-wasm-modules',
fixtures.path('es-modules/top-level-wasm.wasm'),
]);
@ -253,7 +246,6 @@ describe('ESM: WASM modules', { concurrency: !process.env.TEST_PARALLEL }, () =>
it('should support static source phase imports', async () => {
const { code, stderr, stdout } = await spawnPromisified(execPath, [
'--no-warnings',
'--experimental-wasm-modules',
'--input-type=module',
'--eval',
[
@ -274,7 +266,6 @@ describe('ESM: WASM modules', { concurrency: !process.env.TEST_PARALLEL }, () =>
it('should support dynamic source phase imports', async () => {
const { code, stderr, stdout } = await spawnPromisified(execPath, [
'--no-warnings',
'--experimental-wasm-modules',
'--input-type=module',
'--eval',
[
@ -296,7 +287,6 @@ describe('ESM: WASM modules', { concurrency: !process.env.TEST_PARALLEL }, () =>
it('should not execute source phase imports', async () => {
const { code, stderr, stdout } = await spawnPromisified(execPath, [
'--no-warnings',
'--experimental-wasm-modules',
'--input-type=module',
'--eval',
[
@ -315,7 +305,6 @@ describe('ESM: WASM modules', { concurrency: !process.env.TEST_PARALLEL }, () =>
it('should not execute dynamic source phase imports', async () => {
const { code, stderr, stdout } = await spawnPromisified(execPath, [
'--no-warnings',
'--experimental-wasm-modules',
'--input-type=module',
'--eval',
`await import.source(${JSON.stringify(fixtures.fileURL('es-modules/unimportable.wasm'))})`,
@ -330,7 +319,6 @@ describe('ESM: WASM modules', { concurrency: !process.env.TEST_PARALLEL }, () =>
const fileUrl = fixtures.fileURL('es-modules/wasm-source-phase.js');
const { code, stderr, stdout } = await spawnPromisified(execPath, [
'--no-warnings',
'--experimental-wasm-modules',
'--input-type=module',
'--eval',
[
@ -353,7 +341,6 @@ describe('ESM: WASM modules', { concurrency: !process.env.TEST_PARALLEL }, () =>
const fileUrl = fixtures.fileURL('es-modules/wasm-source-phase.js');
const { code, stderr, stdout } = await spawnPromisified(execPath, [
'--no-warnings',
'--experimental-wasm-modules',
'--input-type=module',
'--eval',
`import source nosource from ${JSON.stringify(fileUrl)};`,
@ -367,7 +354,6 @@ describe('ESM: WASM modules', { concurrency: !process.env.TEST_PARALLEL }, () =>
it('should throw for vm source phase static import', async () => {
const { code, stderr, stdout } = await spawnPromisified(execPath, [
'--no-warnings',
'--experimental-wasm-modules',
'--experimental-vm-modules',
'--input-type=module',
'--eval',
@ -386,7 +372,6 @@ describe('ESM: WASM modules', { concurrency: !process.env.TEST_PARALLEL }, () =>
it('should throw for vm source phase dynamic import', async () => {
const { code, stderr, stdout } = await spawnPromisified(execPath, [
'--no-warnings',
'--experimental-wasm-modules',
'--experimental-vm-modules',
'--input-type=module',
'--eval',
@ -407,7 +392,6 @@ describe('ESM: WASM modules', { concurrency: !process.env.TEST_PARALLEL }, () =>
it('should reject wasm: import names', async () => {
const { code, stderr, stdout } = await spawnPromisified(execPath, [
'--no-warnings',
'--experimental-wasm-modules',
'--input-type=module',
'--eval',
`import(${JSON.stringify(fixtures.fileURL('es-modules/invalid-import-name.wasm'))})`,
@ -421,7 +405,6 @@ describe('ESM: WASM modules', { concurrency: !process.env.TEST_PARALLEL }, () =>
it('should reject wasm-js: import names', async () => {
const { code, stderr, stdout } = await spawnPromisified(execPath, [
'--no-warnings',
'--experimental-wasm-modules',
'--input-type=module',
'--eval',
`import(${JSON.stringify(fixtures.fileURL('es-modules/invalid-import-name-wasm-js.wasm'))})`,
@ -435,7 +418,6 @@ describe('ESM: WASM modules', { concurrency: !process.env.TEST_PARALLEL }, () =>
it('should reject wasm-js: import module names', async () => {
const { code, stderr, stdout } = await spawnPromisified(execPath, [
'--no-warnings',
'--experimental-wasm-modules',
'--input-type=module',
'--eval',
`import(${JSON.stringify(fixtures.fileURL('es-modules/invalid-import-module.wasm'))})`,
@ -449,7 +431,6 @@ describe('ESM: WASM modules', { concurrency: !process.env.TEST_PARALLEL }, () =>
it('should reject wasm: export names', async () => {
const { code, stderr, stdout } = await spawnPromisified(execPath, [
'--no-warnings',
'--experimental-wasm-modules',
'--input-type=module',
'--eval',
`import(${JSON.stringify(fixtures.fileURL('es-modules/invalid-export-name.wasm'))})`,
@ -463,7 +444,6 @@ describe('ESM: WASM modules', { concurrency: !process.env.TEST_PARALLEL }, () =>
it('should reject wasm-js: export names', async () => {
const { code, stderr, stdout } = await spawnPromisified(execPath, [
'--no-warnings',
'--experimental-wasm-modules',
'--input-type=module',
'--eval',
`import(${JSON.stringify(fixtures.fileURL('es-modules/invalid-export-name-wasm-js.wasm'))})`,
@ -477,7 +457,6 @@ describe('ESM: WASM modules', { concurrency: !process.env.TEST_PARALLEL }, () =>
it('should support js-string builtins', async () => {
const { code, stderr, stdout } = await spawnPromisified(execPath, [
'--no-warnings',
'--experimental-wasm-modules',
'--input-type=module',
'--eval',
[

View file

@ -1,6 +1,5 @@
// Flags: --no-experimental-wasm-modules
// This tests that module.registerHooks() can be used to support unknown formats, like
// import(wasm) (without --experimental-wasm-modules).
// import(wasm)
import '../common/index.mjs';
import assert from 'node:assert';

View file

@ -1,8 +1,7 @@
// Flags: --no-experimental-wasm-modules
'use strict';
// This tests that module.registerHooks() can be used to support unknown formats, like
// require(wasm) and import(wasm) (without --experimental-wasm-modules).
// require(wasm) and import(wasm)
const common = require('../common');
const assert = require('assert');

View file

@ -118,6 +118,7 @@ assert(undocumented.delete('--debug-arraybuffer-allocations'));
assert(undocumented.delete('--no-debug-arraybuffer-allocations'));
assert(undocumented.delete('--es-module-specifier-resolution'));
assert(undocumented.delete('--experimental-fetch'));
assert(undocumented.delete('--experimental-wasm-modules'));
assert(undocumented.delete('--experimental-global-customevent'));
assert(undocumented.delete('--experimental-global-webcrypto'));
assert(undocumented.delete('--experimental-report'));