From ce5688782e277459681538ce1658e8b0ee4189af Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Wed, 31 Jan 2024 18:44:23 +0100 Subject: [PATCH] lib: define FormData and fetch etc. in the built-in snapshot Now that --experimental-fetch is true by default, define the dependent interfaces in the built-in snapshot and only delete them at run time when --no-experimental-fetch is set. PR-URL: https://github.com/nodejs/node/pull/51598 Reviewed-By: Ethan Arrowood Reviewed-By: Matthew Aitken Reviewed-By: Matteo Collina Reviewed-By: Marco Ippolito --- .../bootstrap/web/exposed-window-or-worker.js | 42 +++++++++++++ lib/internal/process/pre_execution.js | 60 +++---------------- test/parallel/test-bootstrap-modules.js | 2 +- 3 files changed, 51 insertions(+), 53 deletions(-) diff --git a/lib/internal/bootstrap/web/exposed-window-or-worker.js b/lib/internal/bootstrap/web/exposed-window-or-worker.js index 37e4518a5400b5..fe38603cdab5cc 100644 --- a/lib/internal/bootstrap/web/exposed-window-or-worker.js +++ b/lib/internal/bootstrap/web/exposed-window-or-worker.js @@ -10,6 +10,7 @@ const { globalThis, + ObjectDefineProperty, } = primordials; const { @@ -55,3 +56,44 @@ defineReplaceableLazyAttribute(globalThis, 'perf_hooks', ['performance']); // https://w3c.github.io/FileAPI/#creating-revoking const { installObjectURLMethods } = require('internal/url'); installObjectURLMethods(); + +{ + // https://fetch.spec.whatwg.org/#fetch-method + function set(value) { + ObjectDefineProperty(globalThis, 'fetch', { + __proto__: null, + writable: true, + value, + }); + } + ObjectDefineProperty(globalThis, 'fetch', { + __proto__: null, + configurable: true, + enumerable: true, + set, + get() { + function fetch(input, init = undefined) { + // Loading undici alone lead to promises which breaks lots of tests so we + // have to load it really lazily for now. + const { fetch: impl } = require('internal/deps/undici/undici'); + return impl(input, init); + } + set(fetch); + return fetch; + }, + }); +} + +// https://xhr.spec.whatwg.org/#interface-formdata +// https://fetch.spec.whatwg.org/#headers-class +// https://fetch.spec.whatwg.org/#request-class +// https://fetch.spec.whatwg.org/#response-class +exposeLazyInterfaces(globalThis, 'internal/deps/undici/undici', [ + 'FormData', 'Headers', 'Request', 'Response', +]); + +// The WebAssembly Web API which relies on Response. +// https:// webassembly.github.io/spec/web-api/#streaming-modules +internalBinding('wasm_web_api').setImplementation((streamState, source) => { + require('internal/wasm_web_api').wasmStreamingCallback(streamState, source); +}); diff --git a/lib/internal/process/pre_execution.js b/lib/internal/process/pre_execution.js index 98533b7828d3ff..037e2c87a9d5d3 100644 --- a/lib/internal/process/pre_execution.js +++ b/lib/internal/process/pre_execution.js @@ -10,7 +10,6 @@ const { DatePrototypeGetMonth, DatePrototypeGetSeconds, NumberParseInt, - ObjectDefineProperties, ObjectDefineProperty, ObjectGetOwnPropertyDescriptor, SafeMap, @@ -29,7 +28,6 @@ const { } = require('internal/options'); const { reconnectZeroFillToggle } = require('internal/buffer'); const { - defineOperation, exposeInterface, exposeLazyInterfaces, defineReplaceableLazyAttribute, @@ -301,58 +299,16 @@ function setupWarningHandler() { // https://fetch.spec.whatwg.org/ // https://websockets.spec.whatwg.org/ function setupUndici() { - if (getEmbedderOptions().noBrowserGlobals) { - return; - } - - let undici; - function lazyUndici() { - if (undici) { - return undici; - } - - undici = require('internal/deps/undici/undici'); - return undici; - } - - function lazyInterface(name) { - return { - configurable: true, - enumerable: false, - get() { - return lazyUndici()[name]; - }, - set(value) { - exposeInterface(globalThis, name, value); - }, - }; + if (getOptionValue('--no-experimental-fetch')) { + delete globalThis.fetch; + delete globalThis.FormData; + delete globalThis.Headers; + delete globalThis.Request; + delete globalThis.Response; } - if (!getOptionValue('--no-experimental-fetch')) { - // Fetch is meant to return a Promise, but not be async. - function fetch(input, init = undefined) { - return lazyUndici().fetch(input, init); - } - - defineOperation(globalThis, 'fetch', fetch); - - ObjectDefineProperties(globalThis, { - FormData: lazyInterface('FormData'), - Headers: lazyInterface('Headers'), - Request: lazyInterface('Request'), - Response: lazyInterface('Response'), - }); - - // The WebAssembly Web API: https://webassembly.github.io/spec/web-api - internalBinding('wasm_web_api').setImplementation((streamState, source) => { - require('internal/wasm_web_api').wasmStreamingCallback(streamState, source); - }); - } - - if (getOptionValue('--experimental-websocket')) { - ObjectDefineProperties(globalThis, { - WebSocket: lazyInterface('WebSocket'), - }); + if (!getEmbedderOptions().noBrowserGlobals && getOptionValue('--experimental-websocket')) { + exposeLazyInterfaces(globalThis, 'internal/deps/undici/undici', ['WebSocket']); } } diff --git a/test/parallel/test-bootstrap-modules.js b/test/parallel/test-bootstrap-modules.js index d158e489196c39..f4bfde6484f35a 100644 --- a/test/parallel/test-bootstrap-modules.js +++ b/test/parallel/test-bootstrap-modules.js @@ -98,10 +98,10 @@ expected.beforePreExec = new Set([ 'NativeModule internal/modules/package_json_reader', 'Internal Binding module_wrap', 'NativeModule internal/modules/cjs/loader', + 'Internal Binding wasm_web_api', ]); expected.atRunTime = new Set([ - 'Internal Binding wasm_web_api', 'Internal Binding worker', 'NativeModule internal/modules/run_main', 'NativeModule internal/net',