Skip to content

Commit 05a8024

Browse files
committed
bootstrap: lazy load non-essential modules
It turns out that even with startup snapshots, there is a non-trivial overhead for loading internal modules. This patch makes the loading of the non-essential modules lazy again. Caveat: we have to make some of the globals lazily-loaded too, so the WPT runner is updated to test what the state of the global scope is after the globals are accessed (and replaced with the loaded value). PR-URL: nodejs#45659 Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: Yagiz Nizipli <[email protected]> Reviewed-By: Daeyeon Jeong <[email protected]> Reviewed-By: Jacob Smith <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Rafael Gonzaga <[email protected]> Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: Minwoo Jung <[email protected]> Reviewed-By: Tierney Cyren <[email protected]>
1 parent 6d84197 commit 05a8024

26 files changed

+321
-337
lines changed

lib/buffer.js

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@ const {
7878
isInsideNodeModules,
7979
lazyDOMException,
8080
normalizeEncoding,
81-
kIsEncodingSymbol
81+
kIsEncodingSymbol,
82+
defineLazyProperties,
8283
} = require('internal/util');
8384
const {
8485
isAnyArrayBuffer,
@@ -121,15 +122,6 @@ const {
121122
createUnsafeBuffer
122123
} = require('internal/buffer');
123124

124-
const {
125-
Blob,
126-
resolveObjectURL,
127-
} = require('internal/blob');
128-
129-
const {
130-
File,
131-
} = require('internal/file');
132-
133125
FastBuffer.prototype.constructor = Buffer;
134126
Buffer.prototype = FastBuffer.prototype;
135127
addBufferPrototypeMethods(Buffer.prototype);
@@ -1323,9 +1315,6 @@ function atob(input) {
13231315
}
13241316

13251317
module.exports = {
1326-
Blob,
1327-
File,
1328-
resolveObjectURL,
13291318
Buffer,
13301319
SlowBuffer,
13311320
transcode,
@@ -1352,3 +1341,14 @@ ObjectDefineProperties(module.exports, {
13521341
set(val) { INSPECT_MAX_BYTES = val; }
13531342
}
13541343
});
1344+
1345+
defineLazyProperties(
1346+
module.exports,
1347+
'internal/blob',
1348+
['Blob', 'resolveObjectURL']
1349+
);
1350+
defineLazyProperties(
1351+
module.exports,
1352+
'internal/file',
1353+
['File']
1354+
);

lib/fs.js

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ const {
8686
custom: kCustomPromisifiedSymbol,
8787
},
8888
SideEffectFreeRegExpPrototypeExec,
89+
defineLazyProperties,
8990
} = require('internal/util');
9091
const {
9192
constants: {
@@ -122,11 +123,6 @@ const {
122123
validatePrimitiveStringAfterArrayBufferView,
123124
warnOnNonPortableTemplate
124125
} = require('internal/fs/utils');
125-
const {
126-
Dir,
127-
opendir,
128-
opendirSync
129-
} = require('internal/fs/dir');
130126
const {
131127
CHAR_FORWARD_SLASH,
132128
CHAR_BACKWARD_SLASH,
@@ -143,9 +139,6 @@ const {
143139
validateString,
144140
} = require('internal/validators');
145141

146-
const watchers = require('internal/fs/watchers');
147-
const ReadFileContext = require('internal/fs/read_file_context');
148-
149142
let truncateWarn = true;
150143
let fs;
151144

@@ -388,6 +381,7 @@ function checkAborted(signal, callback) {
388381
function readFile(path, options, callback) {
389382
callback = maybeCallback(callback || options);
390383
options = getOptions(options, { flag: 'r' });
384+
const ReadFileContext = require('internal/fs/read_file_context');
391385
const context = new ReadFileContext(callback, options.encoding);
392386
context.isUserFd = isFd(path); // File descriptor ownership
393387

@@ -2311,12 +2305,13 @@ function watch(filename, options, listener) {
23112305
if (options.recursive === undefined) options.recursive = false;
23122306
if (options.recursive && !(isOSX || isWindows))
23132307
throw new ERR_FEATURE_UNAVAILABLE_ON_PLATFORM('watch recursively');
2308+
2309+
const watchers = require('internal/fs/watchers');
23142310
const watcher = new watchers.FSWatcher();
23152311
watcher[watchers.kFSWatchStart](filename,
23162312
options.persistent,
23172313
options.recursive,
23182314
options.encoding);
2319-
23202315
if (listener) {
23212316
watcher.addListener('change', listener);
23222317
}
@@ -2374,7 +2369,7 @@ function watchFile(filename, options, listener) {
23742369
validateFunction(listener, 'listener');
23752370

23762371
stat = statWatchers.get(filename);
2377-
2372+
const watchers = require('internal/fs/watchers');
23782373
if (stat === undefined) {
23792374
stat = new watchers.StatWatcher(options.bigint);
23802375
stat[watchers.kFSStatWatcherStart](filename,
@@ -2400,7 +2395,7 @@ function unwatchFile(filename, listener) {
24002395
const stat = statWatchers.get(filename);
24012396

24022397
if (stat === undefined) return;
2403-
2398+
const watchers = require('internal/fs/watchers');
24042399
if (typeof listener === 'function') {
24052400
const beforeListenerCount = stat.listenerCount('change');
24062401
stat.removeListener('change', listener);
@@ -3004,8 +2999,6 @@ module.exports = fs = {
30042999
mkdtempSync,
30053000
open,
30063001
openSync,
3007-
opendir,
3008-
opendirSync,
30093002
readdir,
30103003
readdirSync,
30113004
read,
@@ -3043,7 +3036,6 @@ module.exports = fs = {
30433036
writeSync,
30443037
writev,
30453038
writevSync,
3046-
Dir,
30473039
Dirent,
30483040
Stats,
30493041

@@ -3089,6 +3081,12 @@ module.exports = fs = {
30893081
_toUnixTimestamp: toUnixTimestamp
30903082
};
30913083

3084+
defineLazyProperties(
3085+
fs,
3086+
'internal/fs/dir',
3087+
['Dir', 'opendir', 'opendirSync']
3088+
);
3089+
30923090
ObjectDefineProperties(fs, {
30933091
F_OK: { __proto__: null, enumerable: true, value: F_OK || 0 },
30943092
R_OK: { __proto__: null, enumerable: true, value: R_OK || 0 },

lib/internal/async_hooks.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ const {
88
Symbol,
99
} = primordials;
1010

11-
const promiseHooks = require('internal/promise_hooks');
12-
1311
const async_wrap = internalBinding('async_wrap');
1412
const { setCallbackTrampoline } = async_wrap;
1513
/* async_hook_fields is a Uint32Array wrapping the uint32_t array of
@@ -382,6 +380,7 @@ function updatePromiseHookMode() {
382380
initHook = destroyTracking;
383381
}
384382
if (stopPromiseHook) stopPromiseHook();
383+
const promiseHooks = require('internal/promise_hooks');
385384
stopPromiseHook = promiseHooks.createHook({
386385
init: initHook,
387386
before: promiseBeforeHook,

lib/internal/bootstrap/browser.js

Lines changed: 62 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ const {
99
defineOperation,
1010
exposeInterface,
1111
lazyDOMExceptionClass,
12+
defineLazyProperties,
13+
defineReplaceableLazyAttribute,
14+
exposeLazyInterfaces,
1215
} = require('internal/util');
1316
const config = internalBinding('config');
1417

@@ -28,55 +31,39 @@ exposeGetterAndSetter(globalThis,
2831
exposeInterface(globalThis, 'DOMException', value);
2932
});
3033

31-
const {
32-
TextEncoder, TextDecoder
33-
} = require('internal/encoding');
34-
// https://encoding.spec.whatwg.org/#textencoder
35-
exposeInterface(globalThis, 'TextEncoder', TextEncoder);
36-
// https://encoding.spec.whatwg.org/#textdecoder
37-
exposeInterface(globalThis, 'TextDecoder', TextDecoder);
38-
39-
const {
40-
AbortController,
41-
AbortSignal,
42-
} = require('internal/abort_controller');
43-
exposeInterface(globalThis, 'AbortController', AbortController);
44-
exposeInterface(globalThis, 'AbortSignal', AbortSignal);
45-
46-
const {
47-
EventTarget,
48-
Event,
49-
} = require('internal/event_target');
50-
exposeInterface(globalThis, 'EventTarget', EventTarget);
51-
exposeInterface(globalThis, 'Event', Event);
52-
const {
53-
MessageChannel,
54-
MessagePort,
55-
MessageEvent,
56-
} = require('internal/worker/io');
57-
exposeInterface(globalThis, 'MessageChannel', MessageChannel);
58-
exposeInterface(globalThis, 'MessagePort', MessagePort);
59-
exposeInterface(globalThis, 'MessageEvent', MessageEvent);
60-
6134
// https://html.spec.whatwg.org/multipage/webappapis.html#windoworworkerglobalscope
6235
const timers = require('timers');
6336
defineOperation(globalThis, 'clearInterval', timers.clearInterval);
6437
defineOperation(globalThis, 'clearTimeout', timers.clearTimeout);
6538
defineOperation(globalThis, 'setInterval', timers.setInterval);
6639
defineOperation(globalThis, 'setTimeout', timers.setTimeout);
6740

68-
const buffer = require('buffer');
69-
defineOperation(globalThis, 'atob', buffer.atob);
70-
defineOperation(globalThis, 'btoa', buffer.btoa);
71-
41+
// Lazy ones.
42+
exposeLazyInterfaces(globalThis, 'internal/abort_controller', [
43+
'AbortController', 'AbortSignal',
44+
]);
45+
exposeLazyInterfaces(globalThis, 'internal/event_target', [
46+
'EventTarget', 'Event',
47+
]);
48+
exposeLazyInterfaces(globalThis, 'internal/worker/io', [
49+
'MessageChannel', 'MessagePort', 'MessageEvent',
50+
]);
51+
defineLazyProperties(globalThis, 'buffer', ['atob', 'btoa']);
7252
// https://www.w3.org/TR/FileAPI/#dfn-Blob
73-
exposeInterface(globalThis, 'Blob', buffer.Blob);
74-
53+
exposeLazyInterfaces(globalThis, 'internal/blob', ['Blob']);
7554
// https://www.w3.org/TR/hr-time-2/#the-performance-attribute
76-
const perf_hooks = require('perf_hooks');
77-
exposeInterface(globalThis, 'Performance', perf_hooks.Performance);
78-
defineReplacableAttribute(globalThis, 'performance',
79-
perf_hooks.performance);
55+
56+
exposeLazyInterfaces(globalThis, 'perf_hooks', [
57+
'Performance'
58+
]);
59+
60+
defineReplaceableLazyAttribute(globalThis, 'perf_hooks', ['performance']);
61+
62+
// https://encoding.spec.whatwg.org/#textencoder
63+
// https://encoding.spec.whatwg.org/#textdecoder
64+
exposeLazyInterfaces(globalThis,
65+
'internal/encoding',
66+
['TextEncoder', 'TextDecoder']);
8067

8168
function createGlobalConsole() {
8269
const consoleFromNode =
@@ -114,67 +101,43 @@ function exposeGetterAndSetter(target, name, getter, setter = undefined) {
114101
});
115102
}
116103

117-
// https://heycam.github.io/webidl/#Replaceable
118-
function defineReplacableAttribute(target, name, value) {
119-
ObjectDefineProperty(target, name, {
120-
__proto__: null,
121-
writable: true,
122-
enumerable: true,
123-
configurable: true,
124-
value,
125-
});
126-
}
127-
128104
// Web Streams API
129-
const {
130-
TransformStream,
131-
TransformStreamDefaultController,
132-
} = require('internal/webstreams/transformstream');
133-
134-
const {
135-
WritableStream,
136-
WritableStreamDefaultController,
137-
WritableStreamDefaultWriter,
138-
} = require('internal/webstreams/writablestream');
105+
exposeLazyInterfaces(
106+
globalThis,
107+
'internal/webstreams/transformstream',
108+
['TransformStream', 'TransformStreamDefaultController']);
139109

140-
const {
141-
ReadableStream,
142-
ReadableStreamDefaultReader,
143-
ReadableStreamBYOBReader,
144-
ReadableStreamBYOBRequest,
145-
ReadableByteStreamController,
146-
ReadableStreamDefaultController,
147-
} = require('internal/webstreams/readablestream');
110+
exposeLazyInterfaces(
111+
globalThis,
112+
'internal/webstreams/writablestream',
113+
['WritableStream', 'WritableStreamDefaultController', 'WritableStreamDefaultWriter']);
148114

149-
const {
150-
ByteLengthQueuingStrategy,
151-
CountQueuingStrategy,
152-
} = require('internal/webstreams/queuingstrategies');
115+
exposeLazyInterfaces(
116+
globalThis,
117+
'internal/webstreams/readablestream',
118+
[
119+
'ReadableStream', 'ReadableStreamDefaultReader',
120+
'ReadableStreamBYOBReader', 'ReadableStreamBYOBRequest',
121+
'ReadableByteStreamController', 'ReadableStreamDefaultController',
122+
]);
123+
124+
exposeLazyInterfaces(
125+
globalThis,
126+
'internal/webstreams/queuingstrategies',
127+
[
128+
'ByteLengthQueuingStrategy', 'CountQueuingStrategy',
129+
]);
153130

154-
const {
155-
TextEncoderStream,
156-
TextDecoderStream,
157-
} = require('internal/webstreams/encoding');
131+
exposeLazyInterfaces(
132+
globalThis,
133+
'internal/webstreams/encoding',
134+
[
135+
'TextEncoderStream', 'TextDecoderStream',
136+
]);
158137

159-
const {
160-
CompressionStream,
161-
DecompressionStream,
162-
} = require('internal/webstreams/compression');
163-
164-
exposeInterface(globalThis, 'ReadableStream', ReadableStream);
165-
exposeInterface(globalThis, 'ReadableStreamDefaultReader', ReadableStreamDefaultReader);
166-
exposeInterface(globalThis, 'ReadableStreamBYOBReader', ReadableStreamBYOBReader);
167-
exposeInterface(globalThis, 'ReadableStreamBYOBRequest', ReadableStreamBYOBRequest);
168-
exposeInterface(globalThis, 'ReadableByteStreamController', ReadableByteStreamController);
169-
exposeInterface(globalThis, 'ReadableStreamDefaultController', ReadableStreamDefaultController);
170-
exposeInterface(globalThis, 'TransformStream', TransformStream);
171-
exposeInterface(globalThis, 'TransformStreamDefaultController', TransformStreamDefaultController);
172-
exposeInterface(globalThis, 'WritableStream', WritableStream);
173-
exposeInterface(globalThis, 'WritableStreamDefaultWriter', WritableStreamDefaultWriter);
174-
exposeInterface(globalThis, 'WritableStreamDefaultController', WritableStreamDefaultController);
175-
exposeInterface(globalThis, 'ByteLengthQueuingStrategy', ByteLengthQueuingStrategy);
176-
exposeInterface(globalThis, 'CountQueuingStrategy', CountQueuingStrategy);
177-
exposeInterface(globalThis, 'TextEncoderStream', TextEncoderStream);
178-
exposeInterface(globalThis, 'TextDecoderStream', TextDecoderStream);
179-
exposeInterface(globalThis, 'CompressionStream', CompressionStream);
180-
exposeInterface(globalThis, 'DecompressionStream', DecompressionStream);
138+
exposeLazyInterfaces(
139+
globalThis,
140+
'internal/webstreams/compression',
141+
[
142+
'CompressionStream', 'DecompressionStream',
143+
]);

0 commit comments

Comments
 (0)