Commit e8e2abc

Browse files
codebytereaduh95
authored andcommitted
lib: load fewer builtins when bootstrapping without a snapshot
Contexts that are not deserialized from the built-in snapshot -- worker threads, and the main context of embedders that create their own isolate or of `node --no-node-snapshot` -- compile (with the code cache at best) every builtin the bootstrap touches, so each eagerly required builtin is startup time (~0.15-0.4 ms apiece). A number of them are only required eagerly so that they end up in the snapshot, or for features the bootstrap path never uses. Load lazily what those paths do not need: - is_main_thread.js: preload util, url, the ESM loader (translators, resolver, module_job/map, source maps, node:module, vm modules, mime, data_url, the TypeScript stripper), internal/blob and internal/dns/utils only while building a snapshot; they load on first use otherwise. - fs: internal/blob (+ internal/encoding and its tables) is only used by fs.openAsBlob(). - internal/url: internal/data_url (+ internal/mime) is only used by the Buffer-returning file URL helpers. - internal/process/execution, the CommonJS loader, esm/translators and esm/load: the TypeScript stripper and data: URL helpers are only needed for TypeScript sources / data: URLs. - pre_execution: internal/dns/utils (+ internal/net) is only needed up front to validate an explicit --dns-result-order or to register the resolver's snapshot serializer; the default order becomes the variable's initializer. - internal/worker: event_loop_utilization and error_serdes are only needed once a sub-worker's ELU is read or it reports an error. - worker_threads: `locks` is defined lazily, like util's lazy exports. Main-thread startup with the snapshot is unchanged (the same modules are preloaded into it; the bootstrap-modules test lists are adjusted). A bare worker compiles 95 -> 83 builtins (cold start -5%); without the snapshot an empty CommonJS entry point compiles 76 -> 59 builtins and an empty ES module entry point 76 -> 69. Signed-off-by: Shelley Vohr <shelley.vohr@gmail.com> PR-URL: #65329 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Chengzhong Wu <legendecas@gmail.com> Reviewed-By: Aviv Keller <me@aviv.sh>
1 parent a457631 commit e8e2abc

12 files changed

Lines changed: 78 additions & 46 deletions

File tree

β€Žlib/fs.jsβ€Ž

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,6 @@ const { isArrayBufferView } = require('internal/util/types');
6464

6565
constbinding=internalBinding('fs');
6666

67-
const{ createBlobFromFilePath }=require('internal/blob');
68-
6967
const{ Buffer }=require('buffer');
7068
const{isBuffer: BufferIsBuffer}=Buffer;
7169
constBufferToString=uncurryThis(Buffer.prototype.toString);
@@ -784,6 +782,7 @@ function openAsBlob(path, options = kEmptyObject) {
784782
// To give ourselves flexibility to maybe return the Blob asynchronously,
785783
// this API returns a Promise.
786784
path=getValidatedPath(path);
785+
const{ createBlobFromFilePath }=require('internal/blob');
787786
returnPromiseResolve(createBlobFromFilePath(path,{ type }));
788787
}
789788

β€Žlib/internal/bootstrap/switches/is_main_thread.jsβ€Ž

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -292,12 +292,27 @@ rawMethods.resetStdioForTesting = function() {
292292

293293
// Needed by the module loader and generally needed everywhere.
294294
require('fs');
295-
require('util');
296-
require('url');// eslint-disable-line no-restricted-modules
297295
internalBinding('module_wrap');
298296
require('internal/modules/cjs/loader');
299-
require('internal/modules/esm/loader');
300297
require('internal/modules/esm/utils');
298+
if(isBuildingSnapshot()){
299+
// Preloaded so that they are part of the snapshot, where they cost nothing
300+
// at startup. When bootstrapping WITHOUT a snapshot (worker threads,
301+
// embedders that create their own isolate, --no-node-snapshot) they are
302+
// loaded on first use instead: the ESM loader (with its translators,
303+
// resolver and their dependencies) by run_main/import(), the public util
304+
// and url modules by whoever requires them, data: URL and TypeScript
305+
// support by the module loaders, internal/blob by fs.openAsBlob(), and the
306+
// DNS helpers by node:dns or an explicit --dns-result-order (see
307+
// pre_execution).
308+
require('util');
309+
require('url');// eslint-disable-line no-restricted-modules
310+
require('internal/modules/esm/loader');
311+
require('internal/data_url');
312+
require('internal/modules/typescript');
313+
require('internal/blob');
314+
require('internal/dns/utils');
315+
}
301316

302317
// Needed to refresh the time origin.
303318
require('internal/perf/utils');
@@ -311,8 +326,6 @@ internalBinding('wasm_web_api');
311326
internalBinding('worker');
312327
// Needed by most execution modes.
313328
require('internal/modules/run_main');
314-
// Needed to refresh DNS configurations.
315-
require('internal/dns/utils');
316329
// Needed by almost all execution modes. It's fine to
317330
// load them into the snapshot as long as we don't run
318331
// any of the initialization.

β€Žlib/internal/dns/utils.jsβ€Ž

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -214,15 +214,15 @@ class ResolverBase {
214214
}
215215

216216
letdefaultResolver;
217-
letdnsOrder;
217+
// May already hold a value chosen by the snapshotted application; a
218+
// --dns-result-order flag given at runtime overrides it in initializeDns().
219+
letdnsOrder='verbatim';
218220
constvalidDnsOrders=['verbatim','ipv4first','ipv6first'];
219221
constvalidFamilies=[0,4,6];
220222

221223
functioninitializeDns(){
222224
constorderFromCLI=getOptionValue('--dns-result-order');
223-
if(!orderFromCLI){
224-
dnsOrder??='verbatim';
225-
}else{
225+
if(orderFromCLI){
226226
// Allow the deserialized application to override order from CLI.
227227
validateOneOf(orderFromCLI,'--dns-result-order',validDnsOrders);
228228
dnsOrder=orderFromCLI;

β€Žlib/internal/modules/cjs/loader.jsβ€Ž

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ const {
180180
resolveWithHooks,
181181
validateLoadStrict,
182182
}=require('internal/modules/customization_hooks');
183-
const{ stripTypeScriptModuleTypes }=require('internal/modules/typescript');
183+
constlazyTypeScript=getLazy(()=>require('internal/modules/typescript'));
184184
constpackageJsonReader=require('internal/modules/package_json_reader');
185185
const{ getOptionValue, getEmbedderOptions }=require('internal/options');
186186
constshouldReportRequiredModules=getLazy(()=>process.env.WATCH_REPORT_DEPENDENCIES);
@@ -1885,7 +1885,7 @@ function wrapSafe(filename, content, cjsModuleInstance, format) {
18851885
Module.prototype._compile=function(content,filename,format){
18861886
if(format==='commonjs-typescript'||format==='module-typescript'||format==='typescript'){
18871887
this[kURL]??=convertCJSFilenameToURL(filename);
1888-
content=stripTypeScriptModuleTypes(content,filename,this[kURL]);
1888+
content=lazyTypeScript().stripTypeScriptModuleTypes(content,filename,this[kURL]);
18891889
switch(format){
18901890
case'commonjs-typescript': {
18911891
format='commonjs';

β€Žlib/internal/modules/esm/load.jsβ€Ž

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,6 @@ const {
2020
ERR_UNSUPPORTED_ESM_URL_SCHEME,
2121
}=require('internal/errors').codes;
2222

23-
const{
24-
dataURLProcessor,
25-
}=require('internal/data_url');
2623

2724
/**
2825
* @param {URL} url URL to the module
@@ -40,6 +37,7 @@ function getSourceSync(url, context) {
4037
// Prefer module.registerHooks() or other more formal fs hooks released in the future.
4138
source=fs.readFileSync(url);
4239
}elseif(protocol==='data:'){
40+
const{ dataURLProcessor }=require('internal/data_url');// Only for data: URLs.
4341
constresult=dataURLProcessor(url);
4442
if(result==='failure'){
4543
thrownewERR_INVALID_URL(responseURL);

β€Žlib/internal/modules/esm/translators.jsβ€Ž

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@ const {
3030
stripBOM,
3131
urlToFilename,
3232
}=require('internal/modules/helpers');
33-
const{ stripTypeScriptModuleTypes }=require('internal/modules/typescript');
33+
functionstripTypeScriptModuleTypes(source,url){
34+
// Only needed for TypeScript sources; keep it out of the loader's startup path.
35+
returnrequire('internal/modules/typescript').stripTypeScriptModuleTypes(source,url);
36+
}
3437
const{
3538
kIsCachedByESMLoader,
3639
Module: CJSModule,

β€Žlib/internal/process/execution.jsβ€Ž

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ const {
2525
kSourcePhase,
2626
kEvaluationPhase,
2727
}=internalBinding('module_wrap');
28-
const{ stripTypeScriptModuleTypes }=require('internal/modules/typescript');
28+
functionstripTypeScriptModuleTypes(source,filename){
29+
returnrequire('internal/modules/typescript').stripTypeScriptModuleTypes(source,filename);
30+
}
2931

3032
const{
3133
executionAsyncId,

β€Žlib/internal/process/pre_execution.jsβ€Ž

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,12 @@ function prepareExecution(options) {
137137

138138
initializeConfigFileSupport();
139139

140-
require('internal/dns/utils').initializeDns();
140+
// internal/dns/utils (and internal/net behind it) is only needed up front
141+
// to validate an explicit --dns-result-order or to register the resolver's
142+
// snapshot serialization; otherwise it is loaded with node:dns.
143+
if(getOptionValue('--dns-result-order')||isBuildingSnapshot()){
144+
require('internal/dns/utils').initializeDns();
145+
}
141146

142147
if(isMainThread){
143148
assert(internalBinding('worker').isMainThread);

β€Žlib/internal/url.jsβ€Ž

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,11 @@ const {
9393
kValidateObjectAllowObjects,
9494
}=require('internal/validators');
9595

96-
const{ percentDecode }=require('internal/data_url');
96+
letpercentDecode;
97+
functionlazyPercentDecode(input){
98+
percentDecode??=require('internal/data_url').percentDecode;
99+
returnpercentDecode(input);
100+
}
97101

98102
constquerystring=require('querystring');
99103

@@ -1560,7 +1564,7 @@ function getPathBufferFromURLWin32(url) {
15601564
// percent encoded characters and we take the string as is. Any invalid
15611565
// percent encodings, e.g. `%ZZ` are ignored and are passed through
15621566
// literally.
1563-
constdecodedu8=percentDecode(Buffer.from(pathname,'utf8'));
1567+
constdecodedu8=lazyPercentDecode(Buffer.from(pathname,'utf8'));
15641568
constdecodedPathname=Buffer.from(TypedArrayPrototypeGetBuffer(decodedu8),
15651569
TypedArrayPrototypeGetByteOffset(decodedu8),
15661570
TypedArrayPrototypeGetByteLength(decodedu8));
@@ -1635,7 +1639,7 @@ function getPathBufferFromURLPosix(url) {
16351639
// won't scan for the slashes at all, and instead will decode the bytes
16361640
// literally into the returned Buffer. We're going to do the best we can and
16371641
// just interpret the input url as a sequence of bytes.
1638-
constu8=percentDecode(Buffer.from(pathname,'utf8'));
1642+
constu8=lazyPercentDecode(Buffer.from(pathname,'utf8'));
16391643
returnBuffer.from(TypedArrayPrototypeGetBuffer(u8),
16401644
TypedArrayPrototypeGetByteOffset(u8),
16411645
TypedArrayPrototypeGetByteLength(u8));

β€Žlib/internal/worker.jsβ€Ž

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,6 @@ const {
3030
constEventEmitter=require('events');
3131
constassert=require('internal/assert');
3232
constpath=require('path');
33-
const{
34-
internalEventLoopUtilization,
35-
}=require('internal/perf/event_loop_utilization');
36-
3733
consterrorCodes=require('internal/errors').codes;
3834
const{
3935
ERR_WORKER_NOT_RUNNING,
@@ -60,7 +56,6 @@ const {
6056
WritableWorkerStdio,
6157
}=workerIo;
6258
const{ createMainThreadPort, destroyMainThreadPort }=require('internal/worker/messaging');
63-
const{ deserializeError }=require('internal/error_serdes');
6459
const{ fileURLToPath, isURL, pathToFileURL }=require('internal/url');
6560
const{
6661
constructSharedArrayBuffer,
@@ -415,6 +410,7 @@ class Worker extends EventEmitter {
415410

416411
[kOnErrorMessage](serialized){
417412
// This is what is called for uncaught exceptions.
413+
const{ deserializeError }=require('internal/error_serdes');
418414
consterror=deserializeError(serialized);
419415
this.emit('error',error);
420416
}
@@ -697,6 +693,7 @@ function makeResourceLimits(float64arr) {
697693
}
698694

699695
functioneventLoopUtilization(util1,util2){
696+
const{ internalEventLoopUtilization }=require('internal/perf/event_loop_utilization');
700697
// TODO(trevnorris): Works to solve the thread-safe read/write issue of
701698
// loopTime, but has the drawback that it can't be set until the event loop
702699
// has had a chance to turn. So it will be impossible to read the ELU of

0 commit comments

Comments
Β (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Commit e8e2abc

Browse files
codebytereaduh95
authored andcommitted
lib: load fewer builtins when bootstrapping without a snapshot
Contexts that are not deserialized from the built-in snapshot -- worker threads, and the main context of embedders that create their own isolate or of `node --no-node-snapshot` -- compile (with the code cache at best) every builtin the bootstrap touches, so each eagerly required builtin is startup time (~0.15-0.4 ms apiece). A number of them are only required eagerly so that they end up in the snapshot, or for features the bootstrap path never uses. Load lazily what those paths do not need: - is_main_thread.js: preload util, url, the ESM loader (translators, resolver, module_job/map, source maps, node:module, vm modules, mime, data_url, the TypeScript stripper), internal/blob and internal/dns/utils only while building a snapshot; they load on first use otherwise. - fs: internal/blob (+ internal/encoding and its tables) is only used by fs.openAsBlob(). - internal/url: internal/data_url (+ internal/mime) is only used by the Buffer-returning file URL helpers. - internal/process/execution, the CommonJS loader, esm/translators and esm/load: the TypeScript stripper and data: URL helpers are only needed for TypeScript sources / data: URLs. - pre_execution: internal/dns/utils (+ internal/net) is only needed up front to validate an explicit --dns-result-order or to register the resolver's snapshot serializer; the default order becomes the variable's initializer. - internal/worker: event_loop_utilization and error_serdes are only needed once a sub-worker's ELU is read or it reports an error. - worker_threads: `locks` is defined lazily, like util's lazy exports. Main-thread startup with the snapshot is unchanged (the same modules are preloaded into it; the bootstrap-modules test lists are adjusted). A bare worker compiles 95 -> 83 builtins (cold start -5%); without the snapshot an empty CommonJS entry point compiles 76 -> 59 builtins and an empty ES module entry point 76 -> 69. Signed-off-by: Shelley Vohr <shelley.vohr@gmail.com> PR-URL: #65329 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Chengzhong Wu <legendecas@gmail.com> Reviewed-By: Aviv Keller <me@aviv.sh>
1 parent a457631 commit e8e2abc

12 files changed

Lines changed: 78 additions & 46 deletions

File tree

β€Žlib/fs.jsβ€Ž

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,6 @@ const { isArrayBufferView } = require('internal/util/types');
6464

6565
constbinding=internalBinding('fs');
6666

67-
const{ createBlobFromFilePath }=require('internal/blob');
68-
6967
const{ Buffer }=require('buffer');
7068
const{isBuffer: BufferIsBuffer}=Buffer;
7169
constBufferToString=uncurryThis(Buffer.prototype.toString);
@@ -784,6 +782,7 @@ function openAsBlob(path, options = kEmptyObject) {
784782
// To give ourselves flexibility to maybe return the Blob asynchronously,
785783
// this API returns a Promise.
786784
path=getValidatedPath(path);
785+
const{ createBlobFromFilePath }=require('internal/blob');
787786
returnPromiseResolve(createBlobFromFilePath(path,{ type }));
788787
}
789788

β€Žlib/internal/bootstrap/switches/is_main_thread.jsβ€Ž

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -292,12 +292,27 @@ rawMethods.resetStdioForTesting = function() {
292292

293293
// Needed by the module loader and generally needed everywhere.
294294
require('fs');
295-
require('util');
296-
require('url');// eslint-disable-line no-restricted-modules
297295
internalBinding('module_wrap');
298296
require('internal/modules/cjs/loader');
299-
require('internal/modules/esm/loader');
300297
require('internal/modules/esm/utils');
298+
if(isBuildingSnapshot()){
299+
// Preloaded so that they are part of the snapshot, where they cost nothing
300+
// at startup. When bootstrapping WITHOUT a snapshot (worker threads,
301+
// embedders that create their own isolate, --no-node-snapshot) they are
302+
// loaded on first use instead: the ESM loader (with its translators,
303+
// resolver and their dependencies) by run_main/import(), the public util
304+
// and url modules by whoever requires them, data: URL and TypeScript
305+
// support by the module loaders, internal/blob by fs.openAsBlob(), and the
306+
// DNS helpers by node:dns or an explicit --dns-result-order (see
307+
// pre_execution).
308+
require('util');
309+
require('url');// eslint-disable-line no-restricted-modules
310+
require('internal/modules/esm/loader');
311+
require('internal/data_url');
312+
require('internal/modules/typescript');
313+
require('internal/blob');
314+
require('internal/dns/utils');
315+
}
301316

302317
// Needed to refresh the time origin.
303318
require('internal/perf/utils');
@@ -311,8 +326,6 @@ internalBinding('wasm_web_api');
311326
internalBinding('worker');
312327
// Needed by most execution modes.
313328
require('internal/modules/run_main');
314-
// Needed to refresh DNS configurations.
315-
require('internal/dns/utils');
316329
// Needed by almost all execution modes. It's fine to
317330
// load them into the snapshot as long as we don't run
318331
// any of the initialization.

β€Žlib/internal/dns/utils.jsβ€Ž

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -214,15 +214,15 @@ class ResolverBase {
214214
}
215215

216216
letdefaultResolver;
217-
letdnsOrder;
217+
// May already hold a value chosen by the snapshotted application; a
218+
// --dns-result-order flag given at runtime overrides it in initializeDns().
219+
letdnsOrder='verbatim';
218220
constvalidDnsOrders=['verbatim','ipv4first','ipv6first'];
219221
constvalidFamilies=[0,4,6];
220222

221223
functioninitializeDns(){
222224
constorderFromCLI=getOptionValue('--dns-result-order');
223-
if(!orderFromCLI){
224-
dnsOrder??='verbatim';
225-
}else{
225+
if(orderFromCLI){
226226
// Allow the deserialized application to override order from CLI.
227227
validateOneOf(orderFromCLI,'--dns-result-order',validDnsOrders);
228228
dnsOrder=orderFromCLI;

β€Žlib/internal/modules/cjs/loader.jsβ€Ž

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ const {
180180
resolveWithHooks,
181181
validateLoadStrict,
182182
}=require('internal/modules/customization_hooks');
183-
const{ stripTypeScriptModuleTypes }=require('internal/modules/typescript');
183+
constlazyTypeScript=getLazy(()=>require('internal/modules/typescript'));
184184
constpackageJsonReader=require('internal/modules/package_json_reader');
185185
const{ getOptionValue, getEmbedderOptions }=require('internal/options');
186186
constshouldReportRequiredModules=getLazy(()=>process.env.WATCH_REPORT_DEPENDENCIES);
@@ -1885,7 +1885,7 @@ function wrapSafe(filename, content, cjsModuleInstance, format) {
18851885
Module.prototype._compile=function(content,filename,format){
18861886
if(format==='commonjs-typescript'||format==='module-typescript'||format==='typescript'){
18871887
this[kURL]??=convertCJSFilenameToURL(filename);
1888-
content=stripTypeScriptModuleTypes(content,filename,this[kURL]);
1888+
content=lazyTypeScript().stripTypeScriptModuleTypes(content,filename,this[kURL]);
18891889
switch(format){
18901890
case'commonjs-typescript': {
18911891
format='commonjs';

β€Žlib/internal/modules/esm/load.jsβ€Ž

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,6 @@ const {
2020
ERR_UNSUPPORTED_ESM_URL_SCHEME,
2121
}=require('internal/errors').codes;
2222

23-
const{
24-
dataURLProcessor,
25-
}=require('internal/data_url');
2623

2724
/**
2825
* @param {URL} url URL to the module
@@ -40,6 +37,7 @@ function getSourceSync(url, context) {
4037
// Prefer module.registerHooks() or other more formal fs hooks released in the future.
4138
source=fs.readFileSync(url);
4239
}elseif(protocol==='data:'){
40+
const{ dataURLProcessor }=require('internal/data_url');// Only for data: URLs.
4341
constresult=dataURLProcessor(url);
4442
if(result==='failure'){
4543
thrownewERR_INVALID_URL(responseURL);

β€Žlib/internal/modules/esm/translators.jsβ€Ž

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@ const {
3030
stripBOM,
3131
urlToFilename,
3232
}=require('internal/modules/helpers');
33-
const{ stripTypeScriptModuleTypes }=require('internal/modules/typescript');
33+
functionstripTypeScriptModuleTypes(source,url){
34+
// Only needed for TypeScript sources; keep it out of the loader's startup path.
35+
returnrequire('internal/modules/typescript').stripTypeScriptModuleTypes(source,url);
36+
}
3437
const{
3538
kIsCachedByESMLoader,
3639
Module: CJSModule,

β€Žlib/internal/process/execution.jsβ€Ž

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ const {
2525
kSourcePhase,
2626
kEvaluationPhase,
2727
}=internalBinding('module_wrap');
28-
const{ stripTypeScriptModuleTypes }=require('internal/modules/typescript');
28+
functionstripTypeScriptModuleTypes(source,filename){
29+
returnrequire('internal/modules/typescript').stripTypeScriptModuleTypes(source,filename);
30+
}
2931

3032
const{
3133
executionAsyncId,

β€Žlib/internal/process/pre_execution.jsβ€Ž

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,12 @@ function prepareExecution(options) {
137137

138138
initializeConfigFileSupport();
139139

140-
require('internal/dns/utils').initializeDns();
140+
// internal/dns/utils (and internal/net behind it) is only needed up front
141+
// to validate an explicit --dns-result-order or to register the resolver's
142+
// snapshot serialization; otherwise it is loaded with node:dns.
143+
if(getOptionValue('--dns-result-order')||isBuildingSnapshot()){
144+
require('internal/dns/utils').initializeDns();
145+
}
141146

142147
if(isMainThread){
143148
assert(internalBinding('worker').isMainThread);

β€Žlib/internal/url.jsβ€Ž

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,11 @@ const {
9393
kValidateObjectAllowObjects,
9494
}=require('internal/validators');
9595

96-
const{ percentDecode }=require('internal/data_url');
96+
letpercentDecode;
97+
functionlazyPercentDecode(input){
98+
percentDecode??=require('internal/data_url').percentDecode;
99+
returnpercentDecode(input);
100+
}
97101

98102
constquerystring=require('querystring');
99103

@@ -1560,7 +1564,7 @@ function getPathBufferFromURLWin32(url) {
15601564
// percent encoded characters and we take the string as is. Any invalid
15611565
// percent encodings, e.g. `%ZZ` are ignored and are passed through
15621566
// literally.
1563-
constdecodedu8=percentDecode(Buffer.from(pathname,'utf8'));
1567+
constdecodedu8=lazyPercentDecode(Buffer.from(pathname,'utf8'));
15641568
constdecodedPathname=Buffer.from(TypedArrayPrototypeGetBuffer(decodedu8),
15651569
TypedArrayPrototypeGetByteOffset(decodedu8),
15661570
TypedArrayPrototypeGetByteLength(decodedu8));
@@ -1635,7 +1639,7 @@ function getPathBufferFromURLPosix(url) {
16351639
// won't scan for the slashes at all, and instead will decode the bytes
16361640
// literally into the returned Buffer. We're going to do the best we can and
16371641
// just interpret the input url as a sequence of bytes.
1638-
constu8=percentDecode(Buffer.from(pathname,'utf8'));
1642+
constu8=lazyPercentDecode(Buffer.from(pathname,'utf8'));
16391643
returnBuffer.from(TypedArrayPrototypeGetBuffer(u8),
16401644
TypedArrayPrototypeGetByteOffset(u8),
16411645
TypedArrayPrototypeGetByteLength(u8));

β€Žlib/internal/worker.jsβ€Ž

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,6 @@ const {
3030
constEventEmitter=require('events');
3131
constassert=require('internal/assert');
3232
constpath=require('path');
33-
const{
34-
internalEventLoopUtilization,
35-
}=require('internal/perf/event_loop_utilization');
36-
3733
consterrorCodes=require('internal/errors').codes;
3834
const{
3935
ERR_WORKER_NOT_RUNNING,
@@ -60,7 +56,6 @@ const {
6056
WritableWorkerStdio,
6157
}=workerIo;
6258
const{ createMainThreadPort, destroyMainThreadPort }=require('internal/worker/messaging');
63-
const{ deserializeError }=require('internal/error_serdes');
6459
const{ fileURLToPath, isURL, pathToFileURL }=require('internal/url');
6560
const{
6661
constructSharedArrayBuffer,
@@ -415,6 +410,7 @@ class Worker extends EventEmitter {
415410

416411
[kOnErrorMessage](serialized){
417412
// This is what is called for uncaught exceptions.
413+
const{ deserializeError }=require('internal/error_serdes');
418414
consterror=deserializeError(serialized);
419415
this.emit('error',error);
420416
}
@@ -697,6 +693,7 @@ function makeResourceLimits(float64arr) {
697693
}
698694

699695
functioneventLoopUtilization(util1,util2){
696+
const{ internalEventLoopUtilization }=require('internal/perf/event_loop_utilization');
700697
// TODO(trevnorris): Works to solve the thread-safe read/write issue of
701698
// loopTime, but has the drawback that it can't be set until the event loop
702699
// has had a chance to turn. So it will be impossible to read the ELU of

0 commit comments

Comments
Β (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Commit e8e2abc

Browse files
codebytereaduh95
authored andcommitted
lib: load fewer builtins when bootstrapping without a snapshot
Contexts that are not deserialized from the built-in snapshot -- worker threads, and the main context of embedders that create their own isolate or of `node --no-node-snapshot` -- compile (with the code cache at best) every builtin the bootstrap touches, so each eagerly required builtin is startup time (~0.15-0.4 ms apiece). A number of them are only required eagerly so that they end up in the snapshot, or for features the bootstrap path never uses. Load lazily what those paths do not need: - is_main_thread.js: preload util, url, the ESM loader (translators, resolver, module_job/map, source maps, node:module, vm modules, mime, data_url, the TypeScript stripper), internal/blob and internal/dns/utils only while building a snapshot; they load on first use otherwise. - fs: internal/blob (+ internal/encoding and its tables) is only used by fs.openAsBlob(). - internal/url: internal/data_url (+ internal/mime) is only used by the Buffer-returning file URL helpers. - internal/process/execution, the CommonJS loader, esm/translators and esm/load: the TypeScript stripper and data: URL helpers are only needed for TypeScript sources / data: URLs. - pre_execution: internal/dns/utils (+ internal/net) is only needed up front to validate an explicit --dns-result-order or to register the resolver's snapshot serializer; the default order becomes the variable's initializer. - internal/worker: event_loop_utilization and error_serdes are only needed once a sub-worker's ELU is read or it reports an error. - worker_threads: `locks` is defined lazily, like util's lazy exports. Main-thread startup with the snapshot is unchanged (the same modules are preloaded into it; the bootstrap-modules test lists are adjusted). A bare worker compiles 95 -> 83 builtins (cold start -5%); without the snapshot an empty CommonJS entry point compiles 76 -> 59 builtins and an empty ES module entry point 76 -> 69. Signed-off-by: Shelley Vohr <shelley.vohr@gmail.com> PR-URL: #65329 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Chengzhong Wu <legendecas@gmail.com> Reviewed-By: Aviv Keller <me@aviv.sh>
1 parent a457631 commit e8e2abc

12 files changed

Lines changed: 78 additions & 46 deletions

File tree

β€Žlib/fs.jsβ€Ž

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,6 @@ const { isArrayBufferView } = require('internal/util/types');
6464

6565
constbinding=internalBinding('fs');
6666

67-
const{ createBlobFromFilePath }=require('internal/blob');
68-
6967
const{ Buffer }=require('buffer');
7068
const{isBuffer: BufferIsBuffer}=Buffer;
7169
constBufferToString=uncurryThis(Buffer.prototype.toString);
@@ -784,6 +782,7 @@ function openAsBlob(path, options = kEmptyObject) {
784782
// To give ourselves flexibility to maybe return the Blob asynchronously,
785783
// this API returns a Promise.
786784
path=getValidatedPath(path);
785+
const{ createBlobFromFilePath }=require('internal/blob');
787786
returnPromiseResolve(createBlobFromFilePath(path,{ type }));
788787
}
789788

β€Žlib/internal/bootstrap/switches/is_main_thread.jsβ€Ž

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -292,12 +292,27 @@ rawMethods.resetStdioForTesting = function() {
292292

293293
// Needed by the module loader and generally needed everywhere.
294294
require('fs');
295-
require('util');
296-
require('url');// eslint-disable-line no-restricted-modules
297295
internalBinding('module_wrap');
298296
require('internal/modules/cjs/loader');
299-
require('internal/modules/esm/loader');
300297
require('internal/modules/esm/utils');
298+
if(isBuildingSnapshot()){
299+
// Preloaded so that they are part of the snapshot, where they cost nothing
300+
// at startup. When bootstrapping WITHOUT a snapshot (worker threads,
301+
// embedders that create their own isolate, --no-node-snapshot) they are
302+
// loaded on first use instead: the ESM loader (with its translators,
303+
// resolver and their dependencies) by run_main/import(), the public util
304+
// and url modules by whoever requires them, data: URL and TypeScript
305+
// support by the module loaders, internal/blob by fs.openAsBlob(), and the
306+
// DNS helpers by node:dns or an explicit --dns-result-order (see
307+
// pre_execution).
308+
require('util');
309+
require('url');// eslint-disable-line no-restricted-modules
310+
require('internal/modules/esm/loader');
311+
require('internal/data_url');
312+
require('internal/modules/typescript');
313+
require('internal/blob');
314+
require('internal/dns/utils');
315+
}
301316

302317
// Needed to refresh the time origin.
303318
require('internal/perf/utils');
@@ -311,8 +326,6 @@ internalBinding('wasm_web_api');
311326
internalBinding('worker');
312327
// Needed by most execution modes.
313328
require('internal/modules/run_main');
314-
// Needed to refresh DNS configurations.
315-
require('internal/dns/utils');
316329
// Needed by almost all execution modes. It's fine to
317330
// load them into the snapshot as long as we don't run
318331
// any of the initialization.

β€Žlib/internal/dns/utils.jsβ€Ž

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -214,15 +214,15 @@ class ResolverBase {
214214
}
215215

216216
letdefaultResolver;
217-
letdnsOrder;
217+
// May already hold a value chosen by the snapshotted application; a
218+
// --dns-result-order flag given at runtime overrides it in initializeDns().
219+
letdnsOrder='verbatim';
218220
constvalidDnsOrders=['verbatim','ipv4first','ipv6first'];
219221
constvalidFamilies=[0,4,6];
220222

221223
functioninitializeDns(){
222224
constorderFromCLI=getOptionValue('--dns-result-order');
223-
if(!orderFromCLI){
224-
dnsOrder??='verbatim';
225-
}else{
225+
if(orderFromCLI){
226226
// Allow the deserialized application to override order from CLI.
227227
validateOneOf(orderFromCLI,'--dns-result-order',validDnsOrders);
228228
dnsOrder=orderFromCLI;

β€Žlib/internal/modules/cjs/loader.jsβ€Ž

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ const {
180180
resolveWithHooks,
181181
validateLoadStrict,
182182
}=require('internal/modules/customization_hooks');
183-
const{ stripTypeScriptModuleTypes }=require('internal/modules/typescript');
183+
constlazyTypeScript=getLazy(()=>require('internal/modules/typescript'));
184184
constpackageJsonReader=require('internal/modules/package_json_reader');
185185
const{ getOptionValue, getEmbedderOptions }=require('internal/options');
186186
constshouldReportRequiredModules=getLazy(()=>process.env.WATCH_REPORT_DEPENDENCIES);
@@ -1885,7 +1885,7 @@ function wrapSafe(filename, content, cjsModuleInstance, format) {
18851885
Module.prototype._compile=function(content,filename,format){
18861886
if(format==='commonjs-typescript'||format==='module-typescript'||format==='typescript'){
18871887
this[kURL]??=convertCJSFilenameToURL(filename);
1888-
content=stripTypeScriptModuleTypes(content,filename,this[kURL]);
1888+
content=lazyTypeScript().stripTypeScriptModuleTypes(content,filename,this[kURL]);
18891889
switch(format){
18901890
case'commonjs-typescript': {
18911891
format='commonjs';

β€Žlib/internal/modules/esm/load.jsβ€Ž

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,6 @@ const {
2020
ERR_UNSUPPORTED_ESM_URL_SCHEME,
2121
}=require('internal/errors').codes;
2222

23-
const{
24-
dataURLProcessor,
25-
}=require('internal/data_url');
2623

2724
/**
2825
* @param {URL} url URL to the module
@@ -40,6 +37,7 @@ function getSourceSync(url, context) {
4037
// Prefer module.registerHooks() or other more formal fs hooks released in the future.
4138
source=fs.readFileSync(url);
4239
}elseif(protocol==='data:'){
40+
const{ dataURLProcessor }=require('internal/data_url');// Only for data: URLs.
4341
constresult=dataURLProcessor(url);
4442
if(result==='failure'){
4543
thrownewERR_INVALID_URL(responseURL);

β€Žlib/internal/modules/esm/translators.jsβ€Ž

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@ const {
3030
stripBOM,
3131
urlToFilename,
3232
}=require('internal/modules/helpers');
33-
const{ stripTypeScriptModuleTypes }=require('internal/modules/typescript');
33+
functionstripTypeScriptModuleTypes(source,url){
34+
// Only needed for TypeScript sources; keep it out of the loader's startup path.
35+
returnrequire('internal/modules/typescript').stripTypeScriptModuleTypes(source,url);
36+
}
3437
const{
3538
kIsCachedByESMLoader,
3639
Module: CJSModule,

β€Žlib/internal/process/execution.jsβ€Ž

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ const {
2525
kSourcePhase,
2626
kEvaluationPhase,
2727
}=internalBinding('module_wrap');
28-
const{ stripTypeScriptModuleTypes }=require('internal/modules/typescript');
28+
functionstripTypeScriptModuleTypes(source,filename){
29+
returnrequire('internal/modules/typescript').stripTypeScriptModuleTypes(source,filename);
30+
}
2931

3032
const{
3133
executionAsyncId,

β€Žlib/internal/process/pre_execution.jsβ€Ž

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,12 @@ function prepareExecution(options) {
137137

138138
initializeConfigFileSupport();
139139

140-
require('internal/dns/utils').initializeDns();
140+
// internal/dns/utils (and internal/net behind it) is only needed up front
141+
// to validate an explicit --dns-result-order or to register the resolver's
142+
// snapshot serialization; otherwise it is loaded with node:dns.
143+
if(getOptionValue('--dns-result-order')||isBuildingSnapshot()){
144+
require('internal/dns/utils').initializeDns();
145+
}
141146

142147
if(isMainThread){
143148
assert(internalBinding('worker').isMainThread);

β€Žlib/internal/url.jsβ€Ž

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,11 @@ const {
9393
kValidateObjectAllowObjects,
9494
}=require('internal/validators');
9595

96-
const{ percentDecode }=require('internal/data_url');
96+
letpercentDecode;
97+
functionlazyPercentDecode(input){
98+
percentDecode??=require('internal/data_url').percentDecode;
99+
returnpercentDecode(input);
100+
}
97101

98102
constquerystring=require('querystring');
99103

@@ -1560,7 +1564,7 @@ function getPathBufferFromURLWin32(url) {
15601564
// percent encoded characters and we take the string as is. Any invalid
15611565
// percent encodings, e.g. `%ZZ` are ignored and are passed through
15621566
// literally.
1563-
constdecodedu8=percentDecode(Buffer.from(pathname,'utf8'));
1567+
constdecodedu8=lazyPercentDecode(Buffer.from(pathname,'utf8'));
15641568
constdecodedPathname=Buffer.from(TypedArrayPrototypeGetBuffer(decodedu8),
15651569
TypedArrayPrototypeGetByteOffset(decodedu8),
15661570
TypedArrayPrototypeGetByteLength(decodedu8));
@@ -1635,7 +1639,7 @@ function getPathBufferFromURLPosix(url) {
16351639
// won't scan for the slashes at all, and instead will decode the bytes
16361640
// literally into the returned Buffer. We're going to do the best we can and
16371641
// just interpret the input url as a sequence of bytes.
1638-
constu8=percentDecode(Buffer.from(pathname,'utf8'));
1642+
constu8=lazyPercentDecode(Buffer.from(pathname,'utf8'));
16391643
returnBuffer.from(TypedArrayPrototypeGetBuffer(u8),
16401644
TypedArrayPrototypeGetByteOffset(u8),
16411645
TypedArrayPrototypeGetByteLength(u8));

β€Žlib/internal/worker.jsβ€Ž

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,6 @@ const {
3030
constEventEmitter=require('events');
3131
constassert=require('internal/assert');
3232
constpath=require('path');
33-
const{
34-
internalEventLoopUtilization,
35-
}=require('internal/perf/event_loop_utilization');
36-
3733
consterrorCodes=require('internal/errors').codes;
3834
const{
3935
ERR_WORKER_NOT_RUNNING,
@@ -60,7 +56,6 @@ const {
6056
WritableWorkerStdio,
6157
}=workerIo;
6258
const{ createMainThreadPort, destroyMainThreadPort }=require('internal/worker/messaging');
63-
const{ deserializeError }=require('internal/error_serdes');
6459
const{ fileURLToPath, isURL, pathToFileURL }=require('internal/url');
6560
const{
6661
constructSharedArrayBuffer,
@@ -415,6 +410,7 @@ class Worker extends EventEmitter {
415410

416411
[kOnErrorMessage](serialized){
417412
// This is what is called for uncaught exceptions.
413+
const{ deserializeError }=require('internal/error_serdes');
418414
consterror=deserializeError(serialized);
419415
this.emit('error',error);
420416
}
@@ -697,6 +693,7 @@ function makeResourceLimits(float64arr) {
697693
}
698694

699695
functioneventLoopUtilization(util1,util2){
696+
const{ internalEventLoopUtilization }=require('internal/perf/event_loop_utilization');
700697
// TODO(trevnorris): Works to solve the thread-safe read/write issue of
701698
// loopTime, but has the drawback that it can't be set until the event loop
702699
// has had a chance to turn. So it will be impossible to read the ELU of

0 commit comments

Comments
Β (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Commit e8e2abc

Browse files
codebytereaduh95
authored andcommitted
lib: load fewer builtins when bootstrapping without a snapshot
Contexts that are not deserialized from the built-in snapshot -- worker threads, and the main context of embedders that create their own isolate or of `node --no-node-snapshot` -- compile (with the code cache at best) every builtin the bootstrap touches, so each eagerly required builtin is startup time (~0.15-0.4 ms apiece). A number of them are only required eagerly so that they end up in the snapshot, or for features the bootstrap path never uses. Load lazily what those paths do not need: - is_main_thread.js: preload util, url, the ESM loader (translators, resolver, module_job/map, source maps, node:module, vm modules, mime, data_url, the TypeScript stripper), internal/blob and internal/dns/utils only while building a snapshot; they load on first use otherwise. - fs: internal/blob (+ internal/encoding and its tables) is only used by fs.openAsBlob(). - internal/url: internal/data_url (+ internal/mime) is only used by the Buffer-returning file URL helpers. - internal/process/execution, the CommonJS loader, esm/translators and esm/load: the TypeScript stripper and data: URL helpers are only needed for TypeScript sources / data: URLs. - pre_execution: internal/dns/utils (+ internal/net) is only needed up front to validate an explicit --dns-result-order or to register the resolver's snapshot serializer; the default order becomes the variable's initializer. - internal/worker: event_loop_utilization and error_serdes are only needed once a sub-worker's ELU is read or it reports an error. - worker_threads: `locks` is defined lazily, like util's lazy exports. Main-thread startup with the snapshot is unchanged (the same modules are preloaded into it; the bootstrap-modules test lists are adjusted). A bare worker compiles 95 -> 83 builtins (cold start -5%); without the snapshot an empty CommonJS entry point compiles 76 -> 59 builtins and an empty ES module entry point 76 -> 69. Signed-off-by: Shelley Vohr <shelley.vohr@gmail.com> PR-URL: #65329 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Chengzhong Wu <legendecas@gmail.com> Reviewed-By: Aviv Keller <me@aviv.sh>
1 parent a457631 commit e8e2abc

12 files changed

Lines changed: 78 additions & 46 deletions

File tree

β€Žlib/fs.jsβ€Ž

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,6 @@ const { isArrayBufferView } = require('internal/util/types');
6464

6565
constbinding=internalBinding('fs');
6666

67-
const{ createBlobFromFilePath }=require('internal/blob');
68-
6967
const{ Buffer }=require('buffer');
7068
const{isBuffer: BufferIsBuffer}=Buffer;
7169
constBufferToString=uncurryThis(Buffer.prototype.toString);
@@ -784,6 +782,7 @@ function openAsBlob(path, options = kEmptyObject) {
784782
// To give ourselves flexibility to maybe return the Blob asynchronously,
785783
// this API returns a Promise.
786784
path=getValidatedPath(path);
785+
const{ createBlobFromFilePath }=require('internal/blob');
787786
returnPromiseResolve(createBlobFromFilePath(path,{ type }));
788787
}
789788

β€Žlib/internal/bootstrap/switches/is_main_thread.jsβ€Ž

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -292,12 +292,27 @@ rawMethods.resetStdioForTesting = function() {
292292

293293
// Needed by the module loader and generally needed everywhere.
294294
require('fs');
295-
require('util');
296-
require('url');// eslint-disable-line no-restricted-modules
297295
internalBinding('module_wrap');
298296
require('internal/modules/cjs/loader');
299-
require('internal/modules/esm/loader');
300297
require('internal/modules/esm/utils');
298+
if(isBuildingSnapshot()){
299+
// Preloaded so that they are part of the snapshot, where they cost nothing
300+
// at startup. When bootstrapping WITHOUT a snapshot (worker threads,
301+
// embedders that create their own isolate, --no-node-snapshot) they are
302+
// loaded on first use instead: the ESM loader (with its translators,
303+
// resolver and their dependencies) by run_main/import(), the public util
304+
// and url modules by whoever requires them, data: URL and TypeScript
305+
// support by the module loaders, internal/blob by fs.openAsBlob(), and the
306+
// DNS helpers by node:dns or an explicit --dns-result-order (see
307+
// pre_execution).
308+
require('util');
309+
require('url');// eslint-disable-line no-restricted-modules
310+
require('internal/modules/esm/loader');
311+
require('internal/data_url');
312+
require('internal/modules/typescript');
313+
require('internal/blob');
314+
require('internal/dns/utils');
315+
}
301316

302317
// Needed to refresh the time origin.
303318
require('internal/perf/utils');
@@ -311,8 +326,6 @@ internalBinding('wasm_web_api');
311326
internalBinding('worker');
312327
// Needed by most execution modes.
313328
require('internal/modules/run_main');
314-
// Needed to refresh DNS configurations.
315-
require('internal/dns/utils');
316329
// Needed by almost all execution modes. It's fine to
317330
// load them into the snapshot as long as we don't run
318331
// any of the initialization.

β€Žlib/internal/dns/utils.jsβ€Ž

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -214,15 +214,15 @@ class ResolverBase {
214214
}
215215

216216
letdefaultResolver;
217-
letdnsOrder;
217+
// May already hold a value chosen by the snapshotted application; a
218+
// --dns-result-order flag given at runtime overrides it in initializeDns().
219+
letdnsOrder='verbatim';
218220
constvalidDnsOrders=['verbatim','ipv4first','ipv6first'];
219221
constvalidFamilies=[0,4,6];
220222

221223
functioninitializeDns(){
222224
constorderFromCLI=getOptionValue('--dns-result-order');
223-
if(!orderFromCLI){
224-
dnsOrder??='verbatim';
225-
}else{
225+
if(orderFromCLI){
226226
// Allow the deserialized application to override order from CLI.
227227
validateOneOf(orderFromCLI,'--dns-result-order',validDnsOrders);
228228
dnsOrder=orderFromCLI;

β€Žlib/internal/modules/cjs/loader.jsβ€Ž

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ const {
180180
resolveWithHooks,
181181
validateLoadStrict,
182182
}=require('internal/modules/customization_hooks');
183-
const{ stripTypeScriptModuleTypes }=require('internal/modules/typescript');
183+
constlazyTypeScript=getLazy(()=>require('internal/modules/typescript'));
184184
constpackageJsonReader=require('internal/modules/package_json_reader');
185185
const{ getOptionValue, getEmbedderOptions }=require('internal/options');
186186
constshouldReportRequiredModules=getLazy(()=>process.env.WATCH_REPORT_DEPENDENCIES);
@@ -1885,7 +1885,7 @@ function wrapSafe(filename, content, cjsModuleInstance, format) {
18851885
Module.prototype._compile=function(content,filename,format){
18861886
if(format==='commonjs-typescript'||format==='module-typescript'||format==='typescript'){
18871887
this[kURL]??=convertCJSFilenameToURL(filename);
1888-
content=stripTypeScriptModuleTypes(content,filename,this[kURL]);
1888+
content=lazyTypeScript().stripTypeScriptModuleTypes(content,filename,this[kURL]);
18891889
switch(format){
18901890
case'commonjs-typescript': {
18911891
format='commonjs';

β€Žlib/internal/modules/esm/load.jsβ€Ž

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,6 @@ const {
2020
ERR_UNSUPPORTED_ESM_URL_SCHEME,
2121
}=require('internal/errors').codes;
2222

23-
const{
24-
dataURLProcessor,
25-
}=require('internal/data_url');
2623

2724
/**
2825
* @param {URL} url URL to the module
@@ -40,6 +37,7 @@ function getSourceSync(url, context) {
4037
// Prefer module.registerHooks() or other more formal fs hooks released in the future.
4138
source=fs.readFileSync(url);
4239
}elseif(protocol==='data:'){
40+
const{ dataURLProcessor }=require('internal/data_url');// Only for data: URLs.
4341
constresult=dataURLProcessor(url);
4442
if(result==='failure'){
4543
thrownewERR_INVALID_URL(responseURL);

β€Žlib/internal/modules/esm/translators.jsβ€Ž

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@ const {
3030
stripBOM,
3131
urlToFilename,
3232
}=require('internal/modules/helpers');
33-
const{ stripTypeScriptModuleTypes }=require('internal/modules/typescript');
33+
functionstripTypeScriptModuleTypes(source,url){
34+
// Only needed for TypeScript sources; keep it out of the loader's startup path.
35+
returnrequire('internal/modules/typescript').stripTypeScriptModuleTypes(source,url);
36+
}
3437
const{
3538
kIsCachedByESMLoader,
3639
Module: CJSModule,

β€Žlib/internal/process/execution.jsβ€Ž

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ const {
2525
kSourcePhase,
2626
kEvaluationPhase,
2727
}=internalBinding('module_wrap');
28-
const{ stripTypeScriptModuleTypes }=require('internal/modules/typescript');
28+
functionstripTypeScriptModuleTypes(source,filename){
29+
returnrequire('internal/modules/typescript').stripTypeScriptModuleTypes(source,filename);
30+
}
2931

3032
const{
3133
executionAsyncId,

β€Žlib/internal/process/pre_execution.jsβ€Ž

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,12 @@ function prepareExecution(options) {
137137

138138
initializeConfigFileSupport();
139139

140-
require('internal/dns/utils').initializeDns();
140+
// internal/dns/utils (and internal/net behind it) is only needed up front
141+
// to validate an explicit --dns-result-order or to register the resolver's
142+
// snapshot serialization; otherwise it is loaded with node:dns.
143+
if(getOptionValue('--dns-result-order')||isBuildingSnapshot()){
144+
require('internal/dns/utils').initializeDns();
145+
}
141146

142147
if(isMainThread){
143148
assert(internalBinding('worker').isMainThread);

β€Žlib/internal/url.jsβ€Ž

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,11 @@ const {
9393
kValidateObjectAllowObjects,
9494
}=require('internal/validators');
9595

96-
const{ percentDecode }=require('internal/data_url');
96+
letpercentDecode;
97+
functionlazyPercentDecode(input){
98+
percentDecode??=require('internal/data_url').percentDecode;
99+
returnpercentDecode(input);
100+
}
97101

98102
constquerystring=require('querystring');
99103

@@ -1560,7 +1564,7 @@ function getPathBufferFromURLWin32(url) {
15601564
// percent encoded characters and we take the string as is. Any invalid
15611565
// percent encodings, e.g. `%ZZ` are ignored and are passed through
15621566
// literally.
1563-
constdecodedu8=percentDecode(Buffer.from(pathname,'utf8'));
1567+
constdecodedu8=lazyPercentDecode(Buffer.from(pathname,'utf8'));
15641568
constdecodedPathname=Buffer.from(TypedArrayPrototypeGetBuffer(decodedu8),
15651569
TypedArrayPrototypeGetByteOffset(decodedu8),
15661570
TypedArrayPrototypeGetByteLength(decodedu8));
@@ -1635,7 +1639,7 @@ function getPathBufferFromURLPosix(url) {
16351639
// won't scan for the slashes at all, and instead will decode the bytes
16361640
// literally into the returned Buffer. We're going to do the best we can and
16371641
// just interpret the input url as a sequence of bytes.
1638-
constu8=percentDecode(Buffer.from(pathname,'utf8'));
1642+
constu8=lazyPercentDecode(Buffer.from(pathname,'utf8'));
16391643
returnBuffer.from(TypedArrayPrototypeGetBuffer(u8),
16401644
TypedArrayPrototypeGetByteOffset(u8),
16411645
TypedArrayPrototypeGetByteLength(u8));

β€Žlib/internal/worker.jsβ€Ž

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,6 @@ const {
3030
constEventEmitter=require('events');
3131
constassert=require('internal/assert');
3232
constpath=require('path');
33-
const{
34-
internalEventLoopUtilization,
35-
}=require('internal/perf/event_loop_utilization');
36-
3733
consterrorCodes=require('internal/errors').codes;
3834
const{
3935
ERR_WORKER_NOT_RUNNING,
@@ -60,7 +56,6 @@ const {
6056
WritableWorkerStdio,
6157
}=workerIo;
6258
const{ createMainThreadPort, destroyMainThreadPort }=require('internal/worker/messaging');
63-
const{ deserializeError }=require('internal/error_serdes');
6459
const{ fileURLToPath, isURL, pathToFileURL }=require('internal/url');
6560
const{
6661
constructSharedArrayBuffer,
@@ -415,6 +410,7 @@ class Worker extends EventEmitter {
415410

416411
[kOnErrorMessage](serialized){
417412
// This is what is called for uncaught exceptions.
413+
const{ deserializeError }=require('internal/error_serdes');
418414
consterror=deserializeError(serialized);
419415
this.emit('error',error);
420416
}
@@ -697,6 +693,7 @@ function makeResourceLimits(float64arr) {
697693
}
698694

699695
functioneventLoopUtilization(util1,util2){
696+
const{ internalEventLoopUtilization }=require('internal/perf/event_loop_utilization');
700697
// TODO(trevnorris): Works to solve the thread-safe read/write issue of
701698
// loopTime, but has the drawback that it can't be set until the event loop
702699
// has had a chance to turn. So it will be impossible to read the ELU of

0 commit comments

Comments
Β (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Commit e8e2abc

Browse files
codebytereaduh95
authored andcommitted
lib: load fewer builtins when bootstrapping without a snapshot
Contexts that are not deserialized from the built-in snapshot -- worker threads, and the main context of embedders that create their own isolate or of `node --no-node-snapshot` -- compile (with the code cache at best) every builtin the bootstrap touches, so each eagerly required builtin is startup time (~0.15-0.4 ms apiece). A number of them are only required eagerly so that they end up in the snapshot, or for features the bootstrap path never uses. Load lazily what those paths do not need: - is_main_thread.js: preload util, url, the ESM loader (translators, resolver, module_job/map, source maps, node:module, vm modules, mime, data_url, the TypeScript stripper), internal/blob and internal/dns/utils only while building a snapshot; they load on first use otherwise. - fs: internal/blob (+ internal/encoding and its tables) is only used by fs.openAsBlob(). - internal/url: internal/data_url (+ internal/mime) is only used by the Buffer-returning file URL helpers. - internal/process/execution, the CommonJS loader, esm/translators and esm/load: the TypeScript stripper and data: URL helpers are only needed for TypeScript sources / data: URLs. - pre_execution: internal/dns/utils (+ internal/net) is only needed up front to validate an explicit --dns-result-order or to register the resolver's snapshot serializer; the default order becomes the variable's initializer. - internal/worker: event_loop_utilization and error_serdes are only needed once a sub-worker's ELU is read or it reports an error. - worker_threads: `locks` is defined lazily, like util's lazy exports. Main-thread startup with the snapshot is unchanged (the same modules are preloaded into it; the bootstrap-modules test lists are adjusted). A bare worker compiles 95 -> 83 builtins (cold start -5%); without the snapshot an empty CommonJS entry point compiles 76 -> 59 builtins and an empty ES module entry point 76 -> 69. Signed-off-by: Shelley Vohr <shelley.vohr@gmail.com> PR-URL: #65329 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Chengzhong Wu <legendecas@gmail.com> Reviewed-By: Aviv Keller <me@aviv.sh>
1 parent a457631 commit e8e2abc

12 files changed

Lines changed: 78 additions & 46 deletions

File tree

β€Žlib/fs.jsβ€Ž

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,6 @@ const { isArrayBufferView } = require('internal/util/types');
6464

6565
constbinding=internalBinding('fs');
6666

67-
const{ createBlobFromFilePath }=require('internal/blob');
68-
6967
const{ Buffer }=require('buffer');
7068
const{isBuffer: BufferIsBuffer}=Buffer;
7169
constBufferToString=uncurryThis(Buffer.prototype.toString);
@@ -784,6 +782,7 @@ function openAsBlob(path, options = kEmptyObject) {
784782
// To give ourselves flexibility to maybe return the Blob asynchronously,
785783
// this API returns a Promise.
786784
path=getValidatedPath(path);
785+
const{ createBlobFromFilePath }=require('internal/blob');
787786
returnPromiseResolve(createBlobFromFilePath(path,{ type }));
788787
}
789788

β€Žlib/internal/bootstrap/switches/is_main_thread.jsβ€Ž

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -292,12 +292,27 @@ rawMethods.resetStdioForTesting = function() {
292292

293293
// Needed by the module loader and generally needed everywhere.
294294
require('fs');
295-
require('util');
296-
require('url');// eslint-disable-line no-restricted-modules
297295
internalBinding('module_wrap');
298296
require('internal/modules/cjs/loader');
299-
require('internal/modules/esm/loader');
300297
require('internal/modules/esm/utils');
298+
if(isBuildingSnapshot()){
299+
// Preloaded so that they are part of the snapshot, where they cost nothing
300+
// at startup. When bootstrapping WITHOUT a snapshot (worker threads,
301+
// embedders that create their own isolate, --no-node-snapshot) they are
302+
// loaded on first use instead: the ESM loader (with its translators,
303+
// resolver and their dependencies) by run_main/import(), the public util
304+
// and url modules by whoever requires them, data: URL and TypeScript
305+
// support by the module loaders, internal/blob by fs.openAsBlob(), and the
306+
// DNS helpers by node:dns or an explicit --dns-result-order (see
307+
// pre_execution).
308+
require('util');
309+
require('url');// eslint-disable-line no-restricted-modules
310+
require('internal/modules/esm/loader');
311+
require('internal/data_url');
312+
require('internal/modules/typescript');
313+
require('internal/blob');
314+
require('internal/dns/utils');
315+
}
301316

302317
// Needed to refresh the time origin.
303318
require('internal/perf/utils');
@@ -311,8 +326,6 @@ internalBinding('wasm_web_api');
311326
internalBinding('worker');
312327
// Needed by most execution modes.
313328
require('internal/modules/run_main');
314-
// Needed to refresh DNS configurations.
315-
require('internal/dns/utils');
316329
// Needed by almost all execution modes. It's fine to
317330
// load them into the snapshot as long as we don't run
318331
// any of the initialization.

β€Žlib/internal/dns/utils.jsβ€Ž

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -214,15 +214,15 @@ class ResolverBase {
214214
}
215215

216216
letdefaultResolver;
217-
letdnsOrder;
217+
// May already hold a value chosen by the snapshotted application; a
218+
// --dns-result-order flag given at runtime overrides it in initializeDns().
219+
letdnsOrder='verbatim';
218220
constvalidDnsOrders=['verbatim','ipv4first','ipv6first'];
219221
constvalidFamilies=[0,4,6];
220222

221223
functioninitializeDns(){
222224
constorderFromCLI=getOptionValue('--dns-result-order');
223-
if(!orderFromCLI){
224-
dnsOrder??='verbatim';
225-
}else{
225+
if(orderFromCLI){
226226
// Allow the deserialized application to override order from CLI.
227227
validateOneOf(orderFromCLI,'--dns-result-order',validDnsOrders);
228228
dnsOrder=orderFromCLI;

β€Žlib/internal/modules/cjs/loader.jsβ€Ž

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ const {
180180
resolveWithHooks,
181181
validateLoadStrict,
182182
}=require('internal/modules/customization_hooks');
183-
const{ stripTypeScriptModuleTypes }=require('internal/modules/typescript');
183+
constlazyTypeScript=getLazy(()=>require('internal/modules/typescript'));
184184
constpackageJsonReader=require('internal/modules/package_json_reader');
185185
const{ getOptionValue, getEmbedderOptions }=require('internal/options');
186186
constshouldReportRequiredModules=getLazy(()=>process.env.WATCH_REPORT_DEPENDENCIES);
@@ -1885,7 +1885,7 @@ function wrapSafe(filename, content, cjsModuleInstance, format) {
18851885
Module.prototype._compile=function(content,filename,format){
18861886
if(format==='commonjs-typescript'||format==='module-typescript'||format==='typescript'){
18871887
this[kURL]??=convertCJSFilenameToURL(filename);
1888-
content=stripTypeScriptModuleTypes(content,filename,this[kURL]);
1888+
content=lazyTypeScript().stripTypeScriptModuleTypes(content,filename,this[kURL]);
18891889
switch(format){
18901890
case'commonjs-typescript': {
18911891
format='commonjs';

β€Žlib/internal/modules/esm/load.jsβ€Ž

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,6 @@ const {
2020
ERR_UNSUPPORTED_ESM_URL_SCHEME,
2121
}=require('internal/errors').codes;
2222

23-
const{
24-
dataURLProcessor,
25-
}=require('internal/data_url');
2623

2724
/**
2825
* @param {URL} url URL to the module
@@ -40,6 +37,7 @@ function getSourceSync(url, context) {
4037
// Prefer module.registerHooks() or other more formal fs hooks released in the future.
4138
source=fs.readFileSync(url);
4239
}elseif(protocol==='data:'){
40+
const{ dataURLProcessor }=require('internal/data_url');// Only for data: URLs.
4341
constresult=dataURLProcessor(url);
4442
if(result==='failure'){
4543
thrownewERR_INVALID_URL(responseURL);

β€Žlib/internal/modules/esm/translators.jsβ€Ž

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@ const {
3030
stripBOM,
3131
urlToFilename,
3232
}=require('internal/modules/helpers');
33-
const{ stripTypeScriptModuleTypes }=require('internal/modules/typescript');
33+
functionstripTypeScriptModuleTypes(source,url){
34+
// Only needed for TypeScript sources; keep it out of the loader's startup path.
35+
returnrequire('internal/modules/typescript').stripTypeScriptModuleTypes(source,url);
36+
}
3437
const{
3538
kIsCachedByESMLoader,
3639
Module: CJSModule,

β€Žlib/internal/process/execution.jsβ€Ž

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ const {
2525
kSourcePhase,
2626
kEvaluationPhase,
2727
}=internalBinding('module_wrap');
28-
const{ stripTypeScriptModuleTypes }=require('internal/modules/typescript');
28+
functionstripTypeScriptModuleTypes(source,filename){
29+
returnrequire('internal/modules/typescript').stripTypeScriptModuleTypes(source,filename);
30+
}
2931

3032
const{
3133
executionAsyncId,

β€Žlib/internal/process/pre_execution.jsβ€Ž

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,12 @@ function prepareExecution(options) {
137137

138138
initializeConfigFileSupport();
139139

140-
require('internal/dns/utils').initializeDns();
140+
// internal/dns/utils (and internal/net behind it) is only needed up front
141+
// to validate an explicit --dns-result-order or to register the resolver's
142+
// snapshot serialization; otherwise it is loaded with node:dns.
143+
if(getOptionValue('--dns-result-order')||isBuildingSnapshot()){
144+
require('internal/dns/utils').initializeDns();
145+
}
141146

142147
if(isMainThread){
143148
assert(internalBinding('worker').isMainThread);

β€Žlib/internal/url.jsβ€Ž

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,11 @@ const {
9393
kValidateObjectAllowObjects,
9494
}=require('internal/validators');
9595

96-
const{ percentDecode }=require('internal/data_url');
96+
letpercentDecode;
97+
functionlazyPercentDecode(input){
98+
percentDecode??=require('internal/data_url').percentDecode;
99+
returnpercentDecode(input);
100+
}
97101

98102
constquerystring=require('querystring');
99103

@@ -1560,7 +1564,7 @@ function getPathBufferFromURLWin32(url) {
15601564
// percent encoded characters and we take the string as is. Any invalid
15611565
// percent encodings, e.g. `%ZZ` are ignored and are passed through
15621566
// literally.
1563-
constdecodedu8=percentDecode(Buffer.from(pathname,'utf8'));
1567+
constdecodedu8=lazyPercentDecode(Buffer.from(pathname,'utf8'));
15641568
constdecodedPathname=Buffer.from(TypedArrayPrototypeGetBuffer(decodedu8),
15651569
TypedArrayPrototypeGetByteOffset(decodedu8),
15661570
TypedArrayPrototypeGetByteLength(decodedu8));
@@ -1635,7 +1639,7 @@ function getPathBufferFromURLPosix(url) {
16351639
// won't scan for the slashes at all, and instead will decode the bytes
16361640
// literally into the returned Buffer. We're going to do the best we can and
16371641
// just interpret the input url as a sequence of bytes.
1638-
constu8=percentDecode(Buffer.from(pathname,'utf8'));
1642+
constu8=lazyPercentDecode(Buffer.from(pathname,'utf8'));
16391643
returnBuffer.from(TypedArrayPrototypeGetBuffer(u8),
16401644
TypedArrayPrototypeGetByteOffset(u8),
16411645
TypedArrayPrototypeGetByteLength(u8));

β€Žlib/internal/worker.jsβ€Ž

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,6 @@ const {
3030
constEventEmitter=require('events');
3131
constassert=require('internal/assert');
3232
constpath=require('path');
33-
const{
34-
internalEventLoopUtilization,
35-
}=require('internal/perf/event_loop_utilization');
36-
3733
consterrorCodes=require('internal/errors').codes;
3834
const{
3935
ERR_WORKER_NOT_RUNNING,
@@ -60,7 +56,6 @@ const {
6056
WritableWorkerStdio,
6157
}=workerIo;
6258
const{ createMainThreadPort, destroyMainThreadPort }=require('internal/worker/messaging');
63-
const{ deserializeError }=require('internal/error_serdes');
6459
const{ fileURLToPath, isURL, pathToFileURL }=require('internal/url');
6560
const{
6661
constructSharedArrayBuffer,
@@ -415,6 +410,7 @@ class Worker extends EventEmitter {
415410

416411
[kOnErrorMessage](serialized){
417412
// This is what is called for uncaught exceptions.
413+
const{ deserializeError }=require('internal/error_serdes');
418414
consterror=deserializeError(serialized);
419415
this.emit('error',error);
420416
}
@@ -697,6 +693,7 @@ function makeResourceLimits(float64arr) {
697693
}
698694

699695
functioneventLoopUtilization(util1,util2){
696+
const{ internalEventLoopUtilization }=require('internal/perf/event_loop_utilization');
700697
// TODO(trevnorris): Works to solve the thread-safe read/write issue of
701698
// loopTime, but has the drawback that it can't be set until the event loop
702699
// has had a chance to turn. So it will be impossible to read the ELU of

0 commit comments

Comments
Β (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Commit e8e2abc

Browse files
codebytereaduh95
authored andcommitted
lib: load fewer builtins when bootstrapping without a snapshot
Contexts that are not deserialized from the built-in snapshot -- worker threads, and the main context of embedders that create their own isolate or of `node --no-node-snapshot` -- compile (with the code cache at best) every builtin the bootstrap touches, so each eagerly required builtin is startup time (~0.15-0.4 ms apiece). A number of them are only required eagerly so that they end up in the snapshot, or for features the bootstrap path never uses. Load lazily what those paths do not need: - is_main_thread.js: preload util, url, the ESM loader (translators, resolver, module_job/map, source maps, node:module, vm modules, mime, data_url, the TypeScript stripper), internal/blob and internal/dns/utils only while building a snapshot; they load on first use otherwise. - fs: internal/blob (+ internal/encoding and its tables) is only used by fs.openAsBlob(). - internal/url: internal/data_url (+ internal/mime) is only used by the Buffer-returning file URL helpers. - internal/process/execution, the CommonJS loader, esm/translators and esm/load: the TypeScript stripper and data: URL helpers are only needed for TypeScript sources / data: URLs. - pre_execution: internal/dns/utils (+ internal/net) is only needed up front to validate an explicit --dns-result-order or to register the resolver's snapshot serializer; the default order becomes the variable's initializer. - internal/worker: event_loop_utilization and error_serdes are only needed once a sub-worker's ELU is read or it reports an error. - worker_threads: `locks` is defined lazily, like util's lazy exports. Main-thread startup with the snapshot is unchanged (the same modules are preloaded into it; the bootstrap-modules test lists are adjusted). A bare worker compiles 95 -> 83 builtins (cold start -5%); without the snapshot an empty CommonJS entry point compiles 76 -> 59 builtins and an empty ES module entry point 76 -> 69. Signed-off-by: Shelley Vohr <shelley.vohr@gmail.com> PR-URL: #65329 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Chengzhong Wu <legendecas@gmail.com> Reviewed-By: Aviv Keller <me@aviv.sh>
1 parent a457631 commit e8e2abc

12 files changed

Lines changed: 78 additions & 46 deletions

File tree

β€Žlib/fs.jsβ€Ž

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,6 @@ const { isArrayBufferView } = require('internal/util/types');
6464

6565
constbinding=internalBinding('fs');
6666

67-
const{ createBlobFromFilePath }=require('internal/blob');
68-
6967
const{ Buffer }=require('buffer');
7068
const{isBuffer: BufferIsBuffer}=Buffer;
7169
constBufferToString=uncurryThis(Buffer.prototype.toString);
@@ -784,6 +782,7 @@ function openAsBlob(path, options = kEmptyObject) {
784782
// To give ourselves flexibility to maybe return the Blob asynchronously,
785783
// this API returns a Promise.
786784
path=getValidatedPath(path);
785+
const{ createBlobFromFilePath }=require('internal/blob');
787786
returnPromiseResolve(createBlobFromFilePath(path,{ type }));
788787
}
789788

β€Žlib/internal/bootstrap/switches/is_main_thread.jsβ€Ž

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -292,12 +292,27 @@ rawMethods.resetStdioForTesting = function() {
292292

293293
// Needed by the module loader and generally needed everywhere.
294294
require('fs');
295-
require('util');
296-
require('url');// eslint-disable-line no-restricted-modules
297295
internalBinding('module_wrap');
298296
require('internal/modules/cjs/loader');
299-
require('internal/modules/esm/loader');
300297
require('internal/modules/esm/utils');
298+
if(isBuildingSnapshot()){
299+
// Preloaded so that they are part of the snapshot, where they cost nothing
300+
// at startup. When bootstrapping WITHOUT a snapshot (worker threads,
301+
// embedders that create their own isolate, --no-node-snapshot) they are
302+
// loaded on first use instead: the ESM loader (with its translators,
303+
// resolver and their dependencies) by run_main/import(), the public util
304+
// and url modules by whoever requires them, data: URL and TypeScript
305+
// support by the module loaders, internal/blob by fs.openAsBlob(), and the
306+
// DNS helpers by node:dns or an explicit --dns-result-order (see
307+
// pre_execution).
308+
require('util');
309+
require('url');// eslint-disable-line no-restricted-modules
310+
require('internal/modules/esm/loader');
311+
require('internal/data_url');
312+
require('internal/modules/typescript');
313+
require('internal/blob');
314+
require('internal/dns/utils');
315+
}
301316

302317
// Needed to refresh the time origin.
303318
require('internal/perf/utils');
@@ -311,8 +326,6 @@ internalBinding('wasm_web_api');
311326
internalBinding('worker');
312327
// Needed by most execution modes.
313328
require('internal/modules/run_main');
314-
// Needed to refresh DNS configurations.
315-
require('internal/dns/utils');
316329
// Needed by almost all execution modes. It's fine to
317330
// load them into the snapshot as long as we don't run
318331
// any of the initialization.

β€Žlib/internal/dns/utils.jsβ€Ž

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -214,15 +214,15 @@ class ResolverBase {
214214
}
215215

216216
letdefaultResolver;
217-
letdnsOrder;
217+
// May already hold a value chosen by the snapshotted application; a
218+
// --dns-result-order flag given at runtime overrides it in initializeDns().
219+
letdnsOrder='verbatim';
218220
constvalidDnsOrders=['verbatim','ipv4first','ipv6first'];
219221
constvalidFamilies=[0,4,6];
220222

221223
functioninitializeDns(){
222224
constorderFromCLI=getOptionValue('--dns-result-order');
223-
if(!orderFromCLI){
224-
dnsOrder??='verbatim';
225-
}else{
225+
if(orderFromCLI){
226226
// Allow the deserialized application to override order from CLI.
227227
validateOneOf(orderFromCLI,'--dns-result-order',validDnsOrders);
228228
dnsOrder=orderFromCLI;

β€Žlib/internal/modules/cjs/loader.jsβ€Ž

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ const {
180180
resolveWithHooks,
181181
validateLoadStrict,
182182
}=require('internal/modules/customization_hooks');
183-
const{ stripTypeScriptModuleTypes }=require('internal/modules/typescript');
183+
constlazyTypeScript=getLazy(()=>require('internal/modules/typescript'));
184184
constpackageJsonReader=require('internal/modules/package_json_reader');
185185
const{ getOptionValue, getEmbedderOptions }=require('internal/options');
186186
constshouldReportRequiredModules=getLazy(()=>process.env.WATCH_REPORT_DEPENDENCIES);
@@ -1885,7 +1885,7 @@ function wrapSafe(filename, content, cjsModuleInstance, format) {
18851885
Module.prototype._compile=function(content,filename,format){
18861886
if(format==='commonjs-typescript'||format==='module-typescript'||format==='typescript'){
18871887
this[kURL]??=convertCJSFilenameToURL(filename);
1888-
content=stripTypeScriptModuleTypes(content,filename,this[kURL]);
1888+
content=lazyTypeScript().stripTypeScriptModuleTypes(content,filename,this[kURL]);
18891889
switch(format){
18901890
case'commonjs-typescript': {
18911891
format='commonjs';

β€Žlib/internal/modules/esm/load.jsβ€Ž

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,6 @@ const {
2020
ERR_UNSUPPORTED_ESM_URL_SCHEME,
2121
}=require('internal/errors').codes;
2222

23-
const{
24-
dataURLProcessor,
25-
}=require('internal/data_url');
2623

2724
/**
2825
* @param {URL} url URL to the module
@@ -40,6 +37,7 @@ function getSourceSync(url, context) {
4037
// Prefer module.registerHooks() or other more formal fs hooks released in the future.
4138
source=fs.readFileSync(url);
4239
}elseif(protocol==='data:'){
40+
const{ dataURLProcessor }=require('internal/data_url');// Only for data: URLs.
4341
constresult=dataURLProcessor(url);
4442
if(result==='failure'){
4543
thrownewERR_INVALID_URL(responseURL);

β€Žlib/internal/modules/esm/translators.jsβ€Ž

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@ const {
3030
stripBOM,
3131
urlToFilename,
3232
}=require('internal/modules/helpers');
33-
const{ stripTypeScriptModuleTypes }=require('internal/modules/typescript');
33+
functionstripTypeScriptModuleTypes(source,url){
34+
// Only needed for TypeScript sources; keep it out of the loader's startup path.
35+
returnrequire('internal/modules/typescript').stripTypeScriptModuleTypes(source,url);
36+
}
3437
const{
3538
kIsCachedByESMLoader,
3639
Module: CJSModule,

β€Žlib/internal/process/execution.jsβ€Ž

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ const {
2525
kSourcePhase,
2626
kEvaluationPhase,
2727
}=internalBinding('module_wrap');
28-
const{ stripTypeScriptModuleTypes }=require('internal/modules/typescript');
28+
functionstripTypeScriptModuleTypes(source,filename){
29+
returnrequire('internal/modules/typescript').stripTypeScriptModuleTypes(source,filename);
30+
}
2931

3032
const{
3133
executionAsyncId,

β€Žlib/internal/process/pre_execution.jsβ€Ž

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,12 @@ function prepareExecution(options) {
137137

138138
initializeConfigFileSupport();
139139

140-
require('internal/dns/utils').initializeDns();
140+
// internal/dns/utils (and internal/net behind it) is only needed up front
141+
// to validate an explicit --dns-result-order or to register the resolver's
142+
// snapshot serialization; otherwise it is loaded with node:dns.
143+
if(getOptionValue('--dns-result-order')||isBuildingSnapshot()){
144+
require('internal/dns/utils').initializeDns();
145+
}
141146

142147
if(isMainThread){
143148
assert(internalBinding('worker').isMainThread);

β€Žlib/internal/url.jsβ€Ž

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,11 @@ const {
9393
kValidateObjectAllowObjects,
9494
}=require('internal/validators');
9595

96-
const{ percentDecode }=require('internal/data_url');
96+
letpercentDecode;
97+
functionlazyPercentDecode(input){
98+
percentDecode??=require('internal/data_url').percentDecode;
99+
returnpercentDecode(input);
100+
}
97101

98102
constquerystring=require('querystring');
99103

@@ -1560,7 +1564,7 @@ function getPathBufferFromURLWin32(url) {
15601564
// percent encoded characters and we take the string as is. Any invalid
15611565
// percent encodings, e.g. `%ZZ` are ignored and are passed through
15621566
// literally.
1563-
constdecodedu8=percentDecode(Buffer.from(pathname,'utf8'));
1567+
constdecodedu8=lazyPercentDecode(Buffer.from(pathname,'utf8'));
15641568
constdecodedPathname=Buffer.from(TypedArrayPrototypeGetBuffer(decodedu8),
15651569
TypedArrayPrototypeGetByteOffset(decodedu8),
15661570
TypedArrayPrototypeGetByteLength(decodedu8));
@@ -1635,7 +1639,7 @@ function getPathBufferFromURLPosix(url) {
16351639
// won't scan for the slashes at all, and instead will decode the bytes
16361640
// literally into the returned Buffer. We're going to do the best we can and
16371641
// just interpret the input url as a sequence of bytes.
1638-
constu8=percentDecode(Buffer.from(pathname,'utf8'));
1642+
constu8=lazyPercentDecode(Buffer.from(pathname,'utf8'));
16391643
returnBuffer.from(TypedArrayPrototypeGetBuffer(u8),
16401644
TypedArrayPrototypeGetByteOffset(u8),
16411645
TypedArrayPrototypeGetByteLength(u8));

β€Žlib/internal/worker.jsβ€Ž

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,6 @@ const {
3030
constEventEmitter=require('events');
3131
constassert=require('internal/assert');
3232
constpath=require('path');
33-
const{
34-
internalEventLoopUtilization,
35-
}=require('internal/perf/event_loop_utilization');
36-
3733
consterrorCodes=require('internal/errors').codes;
3834
const{
3935
ERR_WORKER_NOT_RUNNING,
@@ -60,7 +56,6 @@ const {
6056
WritableWorkerStdio,
6157
}=workerIo;
6258
const{ createMainThreadPort, destroyMainThreadPort }=require('internal/worker/messaging');
63-
const{ deserializeError }=require('internal/error_serdes');
6459
const{ fileURLToPath, isURL, pathToFileURL }=require('internal/url');
6560
const{
6661
constructSharedArrayBuffer,
@@ -415,6 +410,7 @@ class Worker extends EventEmitter {
415410

416411
[kOnErrorMessage](serialized){
417412
// This is what is called for uncaught exceptions.
413+
const{ deserializeError }=require('internal/error_serdes');
418414
consterror=deserializeError(serialized);
419415
this.emit('error',error);
420416
}
@@ -697,6 +693,7 @@ function makeResourceLimits(float64arr) {
697693
}
698694

699695
functioneventLoopUtilization(util1,util2){
696+
const{ internalEventLoopUtilization }=require('internal/perf/event_loop_utilization');
700697
// TODO(trevnorris): Works to solve the thread-safe read/write issue of
701698
// loopTime, but has the drawback that it can't be set until the event loop
702699
// has had a chance to turn. So it will be impossible to read the ELU of

0 commit comments

Comments
Β (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Commit e8e2abc

Browse files
codebytereaduh95
authored andcommitted
lib: load fewer builtins when bootstrapping without a snapshot
Contexts that are not deserialized from the built-in snapshot -- worker threads, and the main context of embedders that create their own isolate or of `node --no-node-snapshot` -- compile (with the code cache at best) every builtin the bootstrap touches, so each eagerly required builtin is startup time (~0.15-0.4 ms apiece). A number of them are only required eagerly so that they end up in the snapshot, or for features the bootstrap path never uses. Load lazily what those paths do not need: - is_main_thread.js: preload util, url, the ESM loader (translators, resolver, module_job/map, source maps, node:module, vm modules, mime, data_url, the TypeScript stripper), internal/blob and internal/dns/utils only while building a snapshot; they load on first use otherwise. - fs: internal/blob (+ internal/encoding and its tables) is only used by fs.openAsBlob(). - internal/url: internal/data_url (+ internal/mime) is only used by the Buffer-returning file URL helpers. - internal/process/execution, the CommonJS loader, esm/translators and esm/load: the TypeScript stripper and data: URL helpers are only needed for TypeScript sources / data: URLs. - pre_execution: internal/dns/utils (+ internal/net) is only needed up front to validate an explicit --dns-result-order or to register the resolver's snapshot serializer; the default order becomes the variable's initializer. - internal/worker: event_loop_utilization and error_serdes are only needed once a sub-worker's ELU is read or it reports an error. - worker_threads: `locks` is defined lazily, like util's lazy exports. Main-thread startup with the snapshot is unchanged (the same modules are preloaded into it; the bootstrap-modules test lists are adjusted). A bare worker compiles 95 -> 83 builtins (cold start -5%); without the snapshot an empty CommonJS entry point compiles 76 -> 59 builtins and an empty ES module entry point 76 -> 69. Signed-off-by: Shelley Vohr <shelley.vohr@gmail.com> PR-URL: #65329 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Chengzhong Wu <legendecas@gmail.com> Reviewed-By: Aviv Keller <me@aviv.sh>
1 parent a457631 commit e8e2abc

12 files changed

Lines changed: 78 additions & 46 deletions

File tree

β€Žlib/fs.jsβ€Ž

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,6 @@ const { isArrayBufferView } = require('internal/util/types');
6464

6565
constbinding=internalBinding('fs');
6666

67-
const{ createBlobFromFilePath }=require('internal/blob');
68-
6967
const{ Buffer }=require('buffer');
7068
const{isBuffer: BufferIsBuffer}=Buffer;
7169
constBufferToString=uncurryThis(Buffer.prototype.toString);
@@ -784,6 +782,7 @@ function openAsBlob(path, options = kEmptyObject) {
784782
// To give ourselves flexibility to maybe return the Blob asynchronously,
785783
// this API returns a Promise.
786784
path=getValidatedPath(path);
785+
const{ createBlobFromFilePath }=require('internal/blob');
787786
returnPromiseResolve(createBlobFromFilePath(path,{ type }));
788787
}
789788

β€Žlib/internal/bootstrap/switches/is_main_thread.jsβ€Ž

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -292,12 +292,27 @@ rawMethods.resetStdioForTesting = function() {
292292

293293
// Needed by the module loader and generally needed everywhere.
294294
require('fs');
295-
require('util');
296-
require('url');// eslint-disable-line no-restricted-modules
297295
internalBinding('module_wrap');
298296
require('internal/modules/cjs/loader');
299-
require('internal/modules/esm/loader');
300297
require('internal/modules/esm/utils');
298+
if(isBuildingSnapshot()){
299+
// Preloaded so that they are part of the snapshot, where they cost nothing
300+
// at startup. When bootstrapping WITHOUT a snapshot (worker threads,
301+
// embedders that create their own isolate, --no-node-snapshot) they are
302+
// loaded on first use instead: the ESM loader (with its translators,
303+
// resolver and their dependencies) by run_main/import(), the public util
304+
// and url modules by whoever requires them, data: URL and TypeScript
305+
// support by the module loaders, internal/blob by fs.openAsBlob(), and the
306+
// DNS helpers by node:dns or an explicit --dns-result-order (see
307+
// pre_execution).
308+
require('util');
309+
require('url');// eslint-disable-line no-restricted-modules
310+
require('internal/modules/esm/loader');
311+
require('internal/data_url');
312+
require('internal/modules/typescript');
313+
require('internal/blob');
314+
require('internal/dns/utils');
315+
}
301316

302317
// Needed to refresh the time origin.
303318
require('internal/perf/utils');
@@ -311,8 +326,6 @@ internalBinding('wasm_web_api');
311326
internalBinding('worker');
312327
// Needed by most execution modes.
313328
require('internal/modules/run_main');
314-
// Needed to refresh DNS configurations.
315-
require('internal/dns/utils');
316329
// Needed by almost all execution modes. It's fine to
317330
// load them into the snapshot as long as we don't run
318331
// any of the initialization.

β€Žlib/internal/dns/utils.jsβ€Ž

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -214,15 +214,15 @@ class ResolverBase {
214214
}
215215

216216
letdefaultResolver;
217-
letdnsOrder;
217+
// May already hold a value chosen by the snapshotted application; a
218+
// --dns-result-order flag given at runtime overrides it in initializeDns().
219+
letdnsOrder='verbatim';
218220
constvalidDnsOrders=['verbatim','ipv4first','ipv6first'];
219221
constvalidFamilies=[0,4,6];
220222

221223
functioninitializeDns(){
222224
constorderFromCLI=getOptionValue('--dns-result-order');
223-
if(!orderFromCLI){
224-
dnsOrder??='verbatim';
225-
}else{
225+
if(orderFromCLI){
226226
// Allow the deserialized application to override order from CLI.
227227
validateOneOf(orderFromCLI,'--dns-result-order',validDnsOrders);
228228
dnsOrder=orderFromCLI;

β€Žlib/internal/modules/cjs/loader.jsβ€Ž

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ const {
180180
resolveWithHooks,
181181
validateLoadStrict,
182182
}=require('internal/modules/customization_hooks');
183-
const{ stripTypeScriptModuleTypes }=require('internal/modules/typescript');
183+
constlazyTypeScript=getLazy(()=>require('internal/modules/typescript'));
184184
constpackageJsonReader=require('internal/modules/package_json_reader');
185185
const{ getOptionValue, getEmbedderOptions }=require('internal/options');
186186
constshouldReportRequiredModules=getLazy(()=>process.env.WATCH_REPORT_DEPENDENCIES);
@@ -1885,7 +1885,7 @@ function wrapSafe(filename, content, cjsModuleInstance, format) {
18851885
Module.prototype._compile=function(content,filename,format){
18861886
if(format==='commonjs-typescript'||format==='module-typescript'||format==='typescript'){
18871887
this[kURL]??=convertCJSFilenameToURL(filename);
1888-
content=stripTypeScriptModuleTypes(content,filename,this[kURL]);
1888+
content=lazyTypeScript().stripTypeScriptModuleTypes(content,filename,this[kURL]);
18891889
switch(format){
18901890
case'commonjs-typescript': {
18911891
format='commonjs';

β€Žlib/internal/modules/esm/load.jsβ€Ž

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,6 @@ const {
2020
ERR_UNSUPPORTED_ESM_URL_SCHEME,
2121
}=require('internal/errors').codes;
2222

23-
const{
24-
dataURLProcessor,
25-
}=require('internal/data_url');
2623

2724
/**
2825
* @param {URL} url URL to the module
@@ -40,6 +37,7 @@ function getSourceSync(url, context) {
4037
// Prefer module.registerHooks() or other more formal fs hooks released in the future.
4138
source=fs.readFileSync(url);
4239
}elseif(protocol==='data:'){
40+
const{ dataURLProcessor }=require('internal/data_url');// Only for data: URLs.
4341
constresult=dataURLProcessor(url);
4442
if(result==='failure'){
4543
thrownewERR_INVALID_URL(responseURL);

β€Žlib/internal/modules/esm/translators.jsβ€Ž

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@ const {
3030
stripBOM,
3131
urlToFilename,
3232
}=require('internal/modules/helpers');
33-
const{ stripTypeScriptModuleTypes }=require('internal/modules/typescript');
33+
functionstripTypeScriptModuleTypes(source,url){
34+
// Only needed for TypeScript sources; keep it out of the loader's startup path.
35+
returnrequire('internal/modules/typescript').stripTypeScriptModuleTypes(source,url);
36+
}
3437
const{
3538
kIsCachedByESMLoader,
3639
Module: CJSModule,

β€Žlib/internal/process/execution.jsβ€Ž

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ const {
2525
kSourcePhase,
2626
kEvaluationPhase,
2727
}=internalBinding('module_wrap');
28-
const{ stripTypeScriptModuleTypes }=require('internal/modules/typescript');
28+
functionstripTypeScriptModuleTypes(source,filename){
29+
returnrequire('internal/modules/typescript').stripTypeScriptModuleTypes(source,filename);
30+
}
2931

3032
const{
3133
executionAsyncId,

β€Žlib/internal/process/pre_execution.jsβ€Ž

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,12 @@ function prepareExecution(options) {
137137

138138
initializeConfigFileSupport();
139139

140-
require('internal/dns/utils').initializeDns();
140+
// internal/dns/utils (and internal/net behind it) is only needed up front
141+
// to validate an explicit --dns-result-order or to register the resolver's
142+
// snapshot serialization; otherwise it is loaded with node:dns.
143+
if(getOptionValue('--dns-result-order')||isBuildingSnapshot()){
144+
require('internal/dns/utils').initializeDns();
145+
}
141146

142147
if(isMainThread){
143148
assert(internalBinding('worker').isMainThread);

β€Žlib/internal/url.jsβ€Ž

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,11 @@ const {
9393
kValidateObjectAllowObjects,
9494
}=require('internal/validators');
9595

96-
const{ percentDecode }=require('internal/data_url');
96+
letpercentDecode;
97+
functionlazyPercentDecode(input){
98+
percentDecode??=require('internal/data_url').percentDecode;
99+
returnpercentDecode(input);
100+
}
97101

98102
constquerystring=require('querystring');
99103

@@ -1560,7 +1564,7 @@ function getPathBufferFromURLWin32(url) {
15601564
// percent encoded characters and we take the string as is. Any invalid
15611565
// percent encodings, e.g. `%ZZ` are ignored and are passed through
15621566
// literally.
1563-
constdecodedu8=percentDecode(Buffer.from(pathname,'utf8'));
1567+
constdecodedu8=lazyPercentDecode(Buffer.from(pathname,'utf8'));
15641568
constdecodedPathname=Buffer.from(TypedArrayPrototypeGetBuffer(decodedu8),
15651569
TypedArrayPrototypeGetByteOffset(decodedu8),
15661570
TypedArrayPrototypeGetByteLength(decodedu8));
@@ -1635,7 +1639,7 @@ function getPathBufferFromURLPosix(url) {
16351639
// won't scan for the slashes at all, and instead will decode the bytes
16361640
// literally into the returned Buffer. We're going to do the best we can and
16371641
// just interpret the input url as a sequence of bytes.
1638-
constu8=percentDecode(Buffer.from(pathname,'utf8'));
1642+
constu8=lazyPercentDecode(Buffer.from(pathname,'utf8'));
16391643
returnBuffer.from(TypedArrayPrototypeGetBuffer(u8),
16401644
TypedArrayPrototypeGetByteOffset(u8),
16411645
TypedArrayPrototypeGetByteLength(u8));

β€Žlib/internal/worker.jsβ€Ž

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,6 @@ const {
3030
constEventEmitter=require('events');
3131
constassert=require('internal/assert');
3232
constpath=require('path');
33-
const{
34-
internalEventLoopUtilization,
35-
}=require('internal/perf/event_loop_utilization');
36-
3733
consterrorCodes=require('internal/errors').codes;
3834
const{
3935
ERR_WORKER_NOT_RUNNING,
@@ -60,7 +56,6 @@ const {
6056
WritableWorkerStdio,
6157
}=workerIo;
6258
const{ createMainThreadPort, destroyMainThreadPort }=require('internal/worker/messaging');
63-
const{ deserializeError }=require('internal/error_serdes');
6459
const{ fileURLToPath, isURL, pathToFileURL }=require('internal/url');
6560
const{
6661
constructSharedArrayBuffer,
@@ -415,6 +410,7 @@ class Worker extends EventEmitter {
415410

416411
[kOnErrorMessage](serialized){
417412
// This is what is called for uncaught exceptions.
413+
const{ deserializeError }=require('internal/error_serdes');
418414
consterror=deserializeError(serialized);
419415
this.emit('error',error);
420416
}
@@ -697,6 +693,7 @@ function makeResourceLimits(float64arr) {
697693
}
698694

699695
functioneventLoopUtilization(util1,util2){
696+
const{ internalEventLoopUtilization }=require('internal/perf/event_loop_utilization');
700697
// TODO(trevnorris): Works to solve the thread-safe read/write issue of
701698
// loopTime, but has the drawback that it can't be set until the event loop
702699
// has had a chance to turn. So it will be impossible to read the ELU of

0 commit comments

Comments
Β (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Commit e8e2abc

Browse files
codebytereaduh95
authored andcommitted
lib: load fewer builtins when bootstrapping without a snapshot
Contexts that are not deserialized from the built-in snapshot -- worker threads, and the main context of embedders that create their own isolate or of `node --no-node-snapshot` -- compile (with the code cache at best) every builtin the bootstrap touches, so each eagerly required builtin is startup time (~0.15-0.4 ms apiece). A number of them are only required eagerly so that they end up in the snapshot, or for features the bootstrap path never uses. Load lazily what those paths do not need: - is_main_thread.js: preload util, url, the ESM loader (translators, resolver, module_job/map, source maps, node:module, vm modules, mime, data_url, the TypeScript stripper), internal/blob and internal/dns/utils only while building a snapshot; they load on first use otherwise. - fs: internal/blob (+ internal/encoding and its tables) is only used by fs.openAsBlob(). - internal/url: internal/data_url (+ internal/mime) is only used by the Buffer-returning file URL helpers. - internal/process/execution, the CommonJS loader, esm/translators and esm/load: the TypeScript stripper and data: URL helpers are only needed for TypeScript sources / data: URLs. - pre_execution: internal/dns/utils (+ internal/net) is only needed up front to validate an explicit --dns-result-order or to register the resolver's snapshot serializer; the default order becomes the variable's initializer. - internal/worker: event_loop_utilization and error_serdes are only needed once a sub-worker's ELU is read or it reports an error. - worker_threads: `locks` is defined lazily, like util's lazy exports. Main-thread startup with the snapshot is unchanged (the same modules are preloaded into it; the bootstrap-modules test lists are adjusted). A bare worker compiles 95 -> 83 builtins (cold start -5%); without the snapshot an empty CommonJS entry point compiles 76 -> 59 builtins and an empty ES module entry point 76 -> 69. Signed-off-by: Shelley Vohr <shelley.vohr@gmail.com> PR-URL: #65329 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Chengzhong Wu <legendecas@gmail.com> Reviewed-By: Aviv Keller <me@aviv.sh>
1 parent a457631 commit e8e2abc

12 files changed

Lines changed: 78 additions & 46 deletions

File tree

β€Žlib/fs.jsβ€Ž

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,6 @@ const { isArrayBufferView } = require('internal/util/types');
6464

6565
constbinding=internalBinding('fs');
6666

67-
const{ createBlobFromFilePath }=require('internal/blob');
68-
6967
const{ Buffer }=require('buffer');
7068
const{isBuffer: BufferIsBuffer}=Buffer;
7169
constBufferToString=uncurryThis(Buffer.prototype.toString);
@@ -784,6 +782,7 @@ function openAsBlob(path, options = kEmptyObject) {
784782
// To give ourselves flexibility to maybe return the Blob asynchronously,
785783
// this API returns a Promise.
786784
path=getValidatedPath(path);
785+
const{ createBlobFromFilePath }=require('internal/blob');
787786
returnPromiseResolve(createBlobFromFilePath(path,{ type }));
788787
}
789788

β€Žlib/internal/bootstrap/switches/is_main_thread.jsβ€Ž

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -292,12 +292,27 @@ rawMethods.resetStdioForTesting = function() {
292292

293293
// Needed by the module loader and generally needed everywhere.
294294
require('fs');
295-
require('util');
296-
require('url');// eslint-disable-line no-restricted-modules
297295
internalBinding('module_wrap');
298296
require('internal/modules/cjs/loader');
299-
require('internal/modules/esm/loader');
300297
require('internal/modules/esm/utils');
298+
if(isBuildingSnapshot()){
299+
// Preloaded so that they are part of the snapshot, where they cost nothing
300+
// at startup. When bootstrapping WITHOUT a snapshot (worker threads,
301+
// embedders that create their own isolate, --no-node-snapshot) they are
302+
// loaded on first use instead: the ESM loader (with its translators,
303+
// resolver and their dependencies) by run_main/import(), the public util
304+
// and url modules by whoever requires them, data: URL and TypeScript
305+
// support by the module loaders, internal/blob by fs.openAsBlob(), and the
306+
// DNS helpers by node:dns or an explicit --dns-result-order (see
307+
// pre_execution).
308+
require('util');
309+
require('url');// eslint-disable-line no-restricted-modules
310+
require('internal/modules/esm/loader');
311+
require('internal/data_url');
312+
require('internal/modules/typescript');
313+
require('internal/blob');
314+
require('internal/dns/utils');
315+
}
301316

302317
// Needed to refresh the time origin.
303318
require('internal/perf/utils');
@@ -311,8 +326,6 @@ internalBinding('wasm_web_api');
311326
internalBinding('worker');
312327
// Needed by most execution modes.
313328
require('internal/modules/run_main');
314-
// Needed to refresh DNS configurations.
315-
require('internal/dns/utils');
316329
// Needed by almost all execution modes. It's fine to
317330
// load them into the snapshot as long as we don't run
318331
// any of the initialization.

β€Žlib/internal/dns/utils.jsβ€Ž

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -214,15 +214,15 @@ class ResolverBase {
214214
}
215215

216216
letdefaultResolver;
217-
letdnsOrder;
217+
// May already hold a value chosen by the snapshotted application; a
218+
// --dns-result-order flag given at runtime overrides it in initializeDns().
219+
letdnsOrder='verbatim';
218220
constvalidDnsOrders=['verbatim','ipv4first','ipv6first'];
219221
constvalidFamilies=[0,4,6];
220222

221223
functioninitializeDns(){
222224
constorderFromCLI=getOptionValue('--dns-result-order');
223-
if(!orderFromCLI){
224-
dnsOrder??='verbatim';
225-
}else{
225+
if(orderFromCLI){
226226
// Allow the deserialized application to override order from CLI.
227227
validateOneOf(orderFromCLI,'--dns-result-order',validDnsOrders);
228228
dnsOrder=orderFromCLI;

β€Žlib/internal/modules/cjs/loader.jsβ€Ž

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ const {
180180
resolveWithHooks,
181181
validateLoadStrict,
182182
}=require('internal/modules/customization_hooks');
183-
const{ stripTypeScriptModuleTypes }=require('internal/modules/typescript');
183+
constlazyTypeScript=getLazy(()=>require('internal/modules/typescript'));
184184
constpackageJsonReader=require('internal/modules/package_json_reader');
185185
const{ getOptionValue, getEmbedderOptions }=require('internal/options');
186186
constshouldReportRequiredModules=getLazy(()=>process.env.WATCH_REPORT_DEPENDENCIES);
@@ -1885,7 +1885,7 @@ function wrapSafe(filename, content, cjsModuleInstance, format) {
18851885
Module.prototype._compile=function(content,filename,format){
18861886
if(format==='commonjs-typescript'||format==='module-typescript'||format==='typescript'){
18871887
this[kURL]??=convertCJSFilenameToURL(filename);
1888-
content=stripTypeScriptModuleTypes(content,filename,this[kURL]);
1888+
content=lazyTypeScript().stripTypeScriptModuleTypes(content,filename,this[kURL]);
18891889
switch(format){
18901890
case'commonjs-typescript': {
18911891
format='commonjs';

β€Žlib/internal/modules/esm/load.jsβ€Ž

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,6 @@ const {
2020
ERR_UNSUPPORTED_ESM_URL_SCHEME,
2121
}=require('internal/errors').codes;
2222

23-
const{
24-
dataURLProcessor,
25-
}=require('internal/data_url');
2623

2724
/**
2825
* @param {URL} url URL to the module
@@ -40,6 +37,7 @@ function getSourceSync(url, context) {
4037
// Prefer module.registerHooks() or other more formal fs hooks released in the future.
4138
source=fs.readFileSync(url);
4239
}elseif(protocol==='data:'){
40+
const{ dataURLProcessor }=require('internal/data_url');// Only for data: URLs.
4341
constresult=dataURLProcessor(url);
4442
if(result==='failure'){
4543
thrownewERR_INVALID_URL(responseURL);

β€Žlib/internal/modules/esm/translators.jsβ€Ž

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@ const {
3030
stripBOM,
3131
urlToFilename,
3232
}=require('internal/modules/helpers');
33-
const{ stripTypeScriptModuleTypes }=require('internal/modules/typescript');
33+
functionstripTypeScriptModuleTypes(source,url){
34+
// Only needed for TypeScript sources; keep it out of the loader's startup path.
35+
returnrequire('internal/modules/typescript').stripTypeScriptModuleTypes(source,url);
36+
}
3437
const{
3538
kIsCachedByESMLoader,
3639
Module: CJSModule,

β€Žlib/internal/process/execution.jsβ€Ž

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ const {
2525
kSourcePhase,
2626
kEvaluationPhase,
2727
}=internalBinding('module_wrap');
28-
const{ stripTypeScriptModuleTypes }=require('internal/modules/typescript');
28+
functionstripTypeScriptModuleTypes(source,filename){
29+
returnrequire('internal/modules/typescript').stripTypeScriptModuleTypes(source,filename);
30+
}
2931

3032
const{
3133
executionAsyncId,

β€Žlib/internal/process/pre_execution.jsβ€Ž

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,12 @@ function prepareExecution(options) {
137137

138138
initializeConfigFileSupport();
139139

140-
require('internal/dns/utils').initializeDns();
140+
// internal/dns/utils (and internal/net behind it) is only needed up front
141+
// to validate an explicit --dns-result-order or to register the resolver's
142+
// snapshot serialization; otherwise it is loaded with node:dns.
143+
if(getOptionValue('--dns-result-order')||isBuildingSnapshot()){
144+
require('internal/dns/utils').initializeDns();
145+
}
141146

142147
if(isMainThread){
143148
assert(internalBinding('worker').isMainThread);

β€Žlib/internal/url.jsβ€Ž

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,11 @@ const {
9393
kValidateObjectAllowObjects,
9494
}=require('internal/validators');
9595

96-
const{ percentDecode }=require('internal/data_url');
96+
letpercentDecode;
97+
functionlazyPercentDecode(input){
98+
percentDecode??=require('internal/data_url').percentDecode;
99+
returnpercentDecode(input);
100+
}
97101

98102
constquerystring=require('querystring');
99103

@@ -1560,7 +1564,7 @@ function getPathBufferFromURLWin32(url) {
15601564
// percent encoded characters and we take the string as is. Any invalid
15611565
// percent encodings, e.g. `%ZZ` are ignored and are passed through
15621566
// literally.
1563-
constdecodedu8=percentDecode(Buffer.from(pathname,'utf8'));
1567+
constdecodedu8=lazyPercentDecode(Buffer.from(pathname,'utf8'));
15641568
constdecodedPathname=Buffer.from(TypedArrayPrototypeGetBuffer(decodedu8),
15651569
TypedArrayPrototypeGetByteOffset(decodedu8),
15661570
TypedArrayPrototypeGetByteLength(decodedu8));
@@ -1635,7 +1639,7 @@ function getPathBufferFromURLPosix(url) {
16351639
// won't scan for the slashes at all, and instead will decode the bytes
16361640
// literally into the returned Buffer. We're going to do the best we can and
16371641
// just interpret the input url as a sequence of bytes.
1638-
constu8=percentDecode(Buffer.from(pathname,'utf8'));
1642+
constu8=lazyPercentDecode(Buffer.from(pathname,'utf8'));
16391643
returnBuffer.from(TypedArrayPrototypeGetBuffer(u8),
16401644
TypedArrayPrototypeGetByteOffset(u8),
16411645
TypedArrayPrototypeGetByteLength(u8));

β€Žlib/internal/worker.jsβ€Ž

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,6 @@ const {
3030
constEventEmitter=require('events');
3131
constassert=require('internal/assert');
3232
constpath=require('path');
33-
const{
34-
internalEventLoopUtilization,
35-
}=require('internal/perf/event_loop_utilization');
36-
3733
consterrorCodes=require('internal/errors').codes;
3834
const{
3935
ERR_WORKER_NOT_RUNNING,
@@ -60,7 +56,6 @@ const {
6056
WritableWorkerStdio,
6157
}=workerIo;
6258
const{ createMainThreadPort, destroyMainThreadPort }=require('internal/worker/messaging');
63-
const{ deserializeError }=require('internal/error_serdes');
6459
const{ fileURLToPath, isURL, pathToFileURL }=require('internal/url');
6560
const{
6661
constructSharedArrayBuffer,
@@ -415,6 +410,7 @@ class Worker extends EventEmitter {
415410

416411
[kOnErrorMessage](serialized){
417412
// This is what is called for uncaught exceptions.
413+
const{ deserializeError }=require('internal/error_serdes');
418414
consterror=deserializeError(serialized);
419415
this.emit('error',error);
420416
}
@@ -697,6 +693,7 @@ function makeResourceLimits(float64arr) {
697693
}
698694

699695
functioneventLoopUtilization(util1,util2){
696+
const{ internalEventLoopUtilization }=require('internal/perf/event_loop_utilization');
700697
// TODO(trevnorris): Works to solve the thread-safe read/write issue of
701698
// loopTime, but has the drawback that it can't be set until the event loop
702699
// has had a chance to turn. So it will be impossible to read the ELU of

0 commit comments

Comments
Β (0)