'use strict'; // This list must be computed before we require any builtins to // to eliminate the noise. const list = process.moduleLoadList.slice(); const common = require('../common'); const assert = require('assert'); const { inspect } = require('util'); const preExecIndex = list.findIndex((i) => i.includes('pre_execution')); const actual = { beforePreExec: new Set(list.slice(0, preExecIndex)), atRunTime: new Set(list.slice(preExecIndex)), }; // Currently, we don't add additional builtins to worker snapshots. // So for worker snapshots we'll just concatenate the two. Once we // add more builtins to worker snapshots, we should also distinguish // the two stages for them. const expected = {}; expected.beforePreExec = new Set([ 'Internal Binding builtins', 'Internal Binding encoding_binding', 'Internal Binding modules', 'Internal Binding errors', 'Internal Binding util', 'NativeModule internal/errors', 'Internal Binding config', 'Internal Binding timers', 'Internal Binding async_context_frame', 'NativeModule internal/async_context_frame', 'Internal Binding async_wrap', 'Internal Binding task_queue', 'Internal Binding symbols', 'NativeModule internal/async_hooks', 'Internal Binding constants', 'Internal Binding types', 'NativeModule internal/util', 'NativeModule internal/util/types', 'NativeModule internal/validators', 'NativeModule internal/linkedlist', 'NativeModule internal/priority_queue', 'NativeModule internal/assert', 'NativeModule internal/util/inspect', 'NativeModule internal/util/debuglog', 'NativeModule internal/streams/utils', 'NativeModule internal/timers', 'NativeModule events', 'Internal Binding buffer', 'Internal Binding string_decoder', 'NativeModule internal/buffer', 'NativeModule buffer', 'Internal Binding messaging', 'NativeModule internal/worker/js_transferable', 'Internal Binding process_methods', 'NativeModule internal/process/per_thread', 'Internal Binding credentials', 'NativeModule internal/process/promises', 'NativeModule internal/fixed_queue', 'NativeModule async_hooks', 'NativeModule internal/process/task_queues', 'NativeModule timers', 'Internal Binding trace_events', 'NativeModule internal/constants', 'NativeModule path', 'NativeModule internal/process/execution', 'NativeModule internal/process/permission', 'NativeModule internal/process/warning', 'NativeModule internal/console/constructor', 'NativeModule internal/console/global', 'NativeModule internal/querystring', 'NativeModule querystring', 'Internal Binding url', 'Internal Binding blob', 'NativeModule internal/url', 'NativeModule util', 'NativeModule internal/webidl', 'Internal Binding performance', 'Internal Binding permission', 'NativeModule internal/perf/utils', 'NativeModule internal/event_target', 'Internal Binding mksnapshot', 'NativeModule internal/v8/startup_snapshot', 'NativeModule internal/process/signal', 'Internal Binding fs', 'NativeModule internal/encoding', 'NativeModule internal/webstreams/util', 'NativeModule internal/webstreams/queuingstrategies', 'NativeModule internal/blob', 'NativeModule internal/fs/utils', 'NativeModule fs', 'Internal Binding options', 'NativeModule internal/options', 'NativeModule internal/source_map/source_map_cache', 'Internal Binding contextify', 'NativeModule internal/vm', 'NativeModule internal/modules/helpers', 'NativeModule internal/modules/package_json_reader', 'Internal Binding module_wrap', 'NativeModule internal/modules/cjs/loader', 'NativeModule diagnostics_channel', 'Internal Binding wasm_web_api', 'NativeModule internal/events/abort_listener', 'NativeModule internal/modules/typescript', ]); expected.atRunTime = new Set([ 'Internal Binding worker', 'NativeModule internal/modules/run_main', 'NativeModule internal/net', 'NativeModule internal/dns/utils', 'NativeModule internal/process/pre_execution', 'NativeModule internal/modules/esm/utils', ]); if (common.isMainThread) { [ 'NativeModule url', ].forEach(expected.beforePreExec.add.bind(expected.beforePreExec)); } else { // Worker. [ 'NativeModule diagnostics_channel', 'NativeModule internal/abort_controller', 'NativeModule internal/error_serdes', 'NativeModule internal/perf/event_loop_utilization', 'NativeModule internal/process/worker_thread_only', 'NativeModule internal/streams/add-abort-signal', 'NativeModule internal/streams/compose', 'NativeModule internal/streams/destroy', 'NativeModule internal/streams/duplex', 'NativeModule internal/streams/duplexpair', 'NativeModule internal/streams/end-of-stream', 'NativeModule internal/streams/from', 'NativeModule internal/streams/legacy', 'NativeModule internal/streams/operators', 'NativeModule internal/streams/passthrough', 'NativeModule internal/streams/pipeline', 'NativeModule internal/streams/readable', 'NativeModule internal/streams/state', 'NativeModule internal/streams/transform', 'NativeModule internal/streams/utils', 'NativeModule internal/streams/writable', 'NativeModule internal/worker', 'NativeModule internal/worker/io', 'NativeModule internal/worker/messaging', 'NativeModule stream', 'NativeModule stream/promises', 'NativeModule string_decoder', 'NativeModule worker_threads', ].forEach(expected.atRunTime.add.bind(expected.atRunTime)); // For now we'll concatenate the two stages for workers. We prefer // atRunTime here because that's what currently happens for these. } if (common.isWindows) { // On Windows fs needs SideEffectFreeRegExpPrototypeExec which uses vm. expected.atRunTime.add('NativeModule vm'); } if (common.hasIntl) { expected.beforePreExec.add('Internal Binding icu'); } if (process.features.inspector) { expected.beforePreExec.add('Internal Binding inspector'); expected.beforePreExec.add('NativeModule internal/util/inspector'); expected.atRunTime.add('NativeModule internal/inspector_async_hook'); } // This is loaded if the test is run with NODE_V8_COVERAGE. if (process.env.NODE_V8_COVERAGE) { expected.atRunTime.add('Internal Binding profiler'); } // Accumulate all the errors and print them at the end instead of throwing // immediately which makes it harder to update the test. const errorLogs = []; function err(message) { if (typeof message === 'string') { errorLogs.push(message); } else { // Show the items in individual lines for easier copy-pasting. errorLogs.push(inspect(message, { compact: false })); } } if (common.isMainThread) { const missing = expected.beforePreExec.difference(actual.beforePreExec); const extra = actual.beforePreExec.difference(expected.beforePreExec); if (missing.size !== 0) { err('These builtins are now no longer loaded before pre-execution.'); err('If this is intentional, remove them from `expected.beforePreExec`.'); err('\n--- These could be removed from expected.beforePreExec ---'); err([...missing].sort()); err(''); } if (extra.size !== 0) { err('These builtins are now unexpectedly loaded before pre-execution.'); err('If this is intentional, add them to `expected.beforePreExec`.'); err('\n# Note: loading more builtins before pre-execution can lead to ' + 'startup performance regression or invalid snapshots.'); err('- Consider lazy loading builtins that are not used universally.'); err('- Make sure that the builtins do not access environment dependent ' + 'states e.g. command line arguments or environment variables ' + 'during loading.'); err('- When in doubt, ask @nodejs/startup.'); err('\n--- These could be added to expected.beforePreExec ---'); err([...extra].sort()); err(''); } } if (!common.isMainThread) { // For workers, just merge beforePreExec into atRunTime for now. // When we start adding modules to the worker snapshot, this branch // can be removed and we can just remove the common.isMainThread // conditions. expected.beforePreExec.forEach(expected.atRunTime.add.bind(expected.atRunTime)); actual.beforePreExec.forEach(actual.atRunTime.add.bind(actual.atRunTime)); } { const missing = expected.atRunTime.difference(actual.atRunTime); const extra = actual.atRunTime.difference(expected.atRunTime); if (missing.size !== 0) { err('These builtins are now no longer loaded at run time.'); err('If this is intentional, remove them from `expected.atRunTime`.'); err('\n--- These could be removed from expected.atRunTime ---'); err([...missing].sort()); err(''); } if (extra.size !== 0) { err('These builtins are now unexpectedly loaded at run time.'); err('If this is intentional, add them to `expected.atRunTime`.'); err('\n# Note: loading more builtins at run time can lead to ' + 'startup performance regression.'); err('- Consider lazy loading builtins that are not used universally.'); err('\n--- These could be added to expected.atRunTime ---'); err([...extra].sort()); err(''); } } assert.strictEqual(errorLogs.length, 0, errorLogs.join('\n'));