diff --git a/doc/api/cli.md b/doc/api/cli.md index a551a3fff9cec6..cfdc4e39ebd8d6 100644 --- a/doc/api/cli.md +++ b/doc/api/cli.md @@ -280,14 +280,6 @@ effort to report stack traces relative to the original source file. Overriding `Error.prepareStackTrace` prevents `--enable-source-maps` from modifying the stack trace. -### `--experimental-fetch` - - - -Enable experimental support for the [Fetch API][]. - ### `--experimental-global-webcrypto` + +Disable experimental support for the [Fetch API][]. + ### `--no-experimental-repl-await` -> Stability: 1 - Experimental. Enable this API with the [`--experimental-fetch`][] +> Stability: 1 - Experimental. Disable this API with the [`--no-experimental-fetch`][] > CLI flag. A browser-compatible implementation of the [`fetch()`][] function. @@ -395,7 +395,7 @@ A browser-compatible implementation of the [`fetch()`][] function. added: REPLACEME --> -> Stability: 1 - Experimental. Enable this API with the [`--experimental-fetch`][] +> Stability: 1 - Experimental. Disable this API with the [`--no-experimental-fetch`][] > CLI flag. A browser-compatible implementation of {FormData}. @@ -421,7 +421,7 @@ Node.js this is different. The top-level scope is not the global scope; added: v17.5.0 --> -> Stability: 1 - Experimental. Enable this API with the [`--experimental-fetch`][] +> Stability: 1 - Experimental. Disable this API with the [`--no-experimental-fetch`][] > CLI flag. A browser-compatible implementation of {Headers}. @@ -526,7 +526,7 @@ This variable may appear to be global but is not. See [`require()`][]. added: v17.5.0 --> -> Stability: 1 - Experimental. Enable this API with the [`--experimental-fetch`][] +> Stability: 1 - Experimental. Disable this API with the [`--no-experimental-fetch`][] > CLI flag. A browser-compatible implementation of {Response}. @@ -537,7 +537,7 @@ A browser-compatible implementation of {Response}. added: v17.5.0 --> -> Stability: 1 - Experimental. Enable this API with the [`--experimental-fetch`][] +> Stability: 1 - Experimental. Disable this API with the [`--no-experimental-fetch`][] > CLI flag. A browser-compatible implementation of {Request}. @@ -660,8 +660,8 @@ The object that acts as the namespace for all W3C [Mozilla Developer Network][webassembly-mdn] for usage and compatibility. [Web Crypto API]: webcrypto.md -[`--experimental-fetch`]: cli.md#--experimental-fetch [`--experimental-global-webcrypto`]: cli.md#--experimental-global-webcrypto +[`--no-experimental-fetch`]: cli.md#--no-experimental-fetch [`AbortController`]: https://developer.mozilla.org/en-US/docs/Web/API/AbortController [`DOMException`]: https://developer.mozilla.org/en-US/docs/Web/API/DOMException [`EventTarget` and `Event` API]: events.md#eventtarget-and-event-api diff --git a/doc/node.1 b/doc/node.1 index 972487be1218ee..27b3365140cc57 100644 --- a/doc/node.1 +++ b/doc/node.1 @@ -139,9 +139,6 @@ Requires Node.js to be built with .It Fl -enable-source-maps Enable Source Map V3 support for stack traces. . -.It Fl -experimental-fetch -Enable experimental support for the Fetch API. -. .It Fl -experimental-global-webcrypto Expose the Web Crypto API on the global scope. . @@ -159,6 +156,9 @@ Enable experimental support for loading modules using `import` over `https:`. .It Fl -experimental-policy Use the specified file as a security policy. . +.It Fl -no-experimental-fetch +Disable experimental support for the Fetch API. +. .It Fl -no-experimental-repl-await Disable top-level await keyword support in REPL. . diff --git a/lib/internal/bootstrap/pre_execution.js b/lib/internal/bootstrap/pre_execution.js index 2d24c250918640..33a594d35fcbb0 100644 --- a/lib/internal/bootstrap/pre_execution.js +++ b/lib/internal/bootstrap/pre_execution.js @@ -2,6 +2,7 @@ const { NumberParseInt, + ObjectDefineProperties, ObjectDefineProperty, ObjectGetOwnPropertyDescriptor, SafeMap, @@ -152,18 +153,46 @@ function setupWarningHandler() { // https://fetch.spec.whatwg.org/ function setupFetch() { if (process.config.variables.node_no_browser_globals || - !getOptionValue('--experimental-fetch')) { + getOptionValue('--no-experimental-fetch')) { return; } - emitExperimentalWarning('Fetch'); + let undici; + function lazyUndici() { + if (undici) { + return undici; + } + + emitExperimentalWarning('The Fetch API'); + undici = require('internal/deps/undici/undici'); + return undici; + } + + async function fetch(input, init = undefined) { + return lazyUndici().fetch(input, init); + } + + defineOperation(globalThis, 'fetch', fetch); - const undici = require('internal/deps/undici/undici'); - defineOperation(globalThis, 'fetch', undici.fetch); - exposeInterface(globalThis, 'FormData', undici.FormData); - exposeInterface(globalThis, 'Headers', undici.Headers); - exposeInterface(globalThis, 'Request', undici.Request); - exposeInterface(globalThis, 'Response', undici.Response); + function lazyInterface(name) { + return { + configurable: true, + enumerable: false, + get() { + return lazyUndici()[name]; + }, + set(value) { + exposeInterface(globalThis, name, value); + } + }; + } + + ObjectDefineProperties(globalThis, { + FormData: lazyInterface('FormData'), + Headers: lazyInterface('Headers'), + Request: lazyInterface('Request'), + Response: lazyInterface('Response'), + }); } // TODO(aduh95): move this to internal/bootstrap/browser when the CLI flag is diff --git a/src/node_options.cc b/src/node_options.cc index ab3b736e07d8e9..b8b6d85f39e4ed 100644 --- a/src/node_options.cc +++ b/src/node_options.cc @@ -318,7 +318,8 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() { AddOption("--experimental-fetch", "experimental Fetch API", &EnvironmentOptions::experimental_fetch, - kAllowedInEnvironment); + kAllowedInEnvironment, + true); AddOption("--experimental-global-webcrypto", "expose experimental Web Crypto API on the global scope", &EnvironmentOptions::experimental_global_web_crypto, diff --git a/src/node_options.h b/src/node_options.h index 0ded5d89beef7c..3335c12b8cdcf7 100644 --- a/src/node_options.h +++ b/src/node_options.h @@ -107,7 +107,7 @@ class EnvironmentOptions : public Options { std::vector conditions; std::string dns_result_order; bool enable_source_maps = false; - bool experimental_fetch = false; + bool experimental_fetch = true; bool experimental_global_web_crypto = false; bool experimental_https_modules = false; std::string experimental_specifier_resolution; diff --git a/test/common/index.js b/test/common/index.js index d550d6b8fd76bd..b69d726e8ef323 100644 --- a/test/common/index.js +++ b/test/common/index.js @@ -301,13 +301,7 @@ if (global.structuredClone) { } if (global.fetch) { - knownGlobals.push( - global.fetch, - global.FormData, - global.Request, - global.Response, - global.Headers, - ); + knownGlobals.push(fetch); } if (hasCrypto && global.crypto) { knownGlobals.push(global.crypto); diff --git a/test/parallel/test-fetch-disabled.mjs b/test/parallel/test-fetch-disabled.mjs index 839cdf8f2ac947..f06d484701c3ec 100644 --- a/test/parallel/test-fetch-disabled.mjs +++ b/test/parallel/test-fetch-disabled.mjs @@ -1,3 +1,4 @@ +// Flags: --no-experimental-fetch import '../common/index.mjs'; import assert from 'assert'; diff --git a/test/parallel/test-fetch.mjs b/test/parallel/test-fetch.mjs index d435ec3fa6e2b5..2ec4a63e70f032 100644 --- a/test/parallel/test-fetch.mjs +++ b/test/parallel/test-fetch.mjs @@ -1,6 +1,4 @@ -// Flags: --experimental-fetch --no-warnings - -import '../common/index.mjs'; +import * as common from '../common/index.mjs'; import assert from 'assert'; import events from 'events'; @@ -12,6 +10,11 @@ assert.strictEqual(typeof globalThis.Headers, 'function'); assert.strictEqual(typeof globalThis.Request, 'function'); assert.strictEqual(typeof globalThis.Response, 'function'); +common.expectWarning( + 'ExperimentalWarning', + 'The Fetch API is an experimental feature. This feature could change at any time' +); + const server = http.createServer((req, res) => { // TODO: Remove this once keep-alive behavior can be disabled from the client // side. diff --git a/test/parallel/test-global.js b/test/parallel/test-global.js index 2425ceaff8a650..3585062bf310e5 100644 --- a/test/parallel/test-global.js +++ b/test/parallel/test-global.js @@ -54,6 +54,7 @@ builtinModules.forEach((moduleName) => { 'setInterval', 'setTimeout', 'structuredClone', + 'fetch', ]; assert.deepStrictEqual(new Set(Object.keys(global)), new Set(expected)); }