Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

process: refactor the bootstrap mode branching for readability #24673

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
263 changes: 151 additions & 112 deletions lib/internal/bootstrap/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,18 +104,13 @@
}

const { getOptionValue } = NativeModule.require('internal/options');
const helpOption = getOptionValue('--help');
const completionBashOption = getOptionValue('--completion-bash');
const experimentalModulesOption = getOptionValue('--experimental-modules');
const experimentalVMModulesOption =
getOptionValue('--experimental-vm-modules');
const experimentalWorkerOption = getOptionValue('--experimental-worker');
if (helpOption) {

if (getOptionValue('--help')) {
NativeModule.require('internal/print_help').print(process.stdout);
return;
}

if (completionBashOption) {
if (getOptionValue('--completion-bash')) {
NativeModule.require('internal/bash_completion').print(process.stdout);
return;
}
Expand All @@ -135,7 +130,7 @@
setupQueueMicrotask();
}

if (experimentalWorkerOption) {
if (getOptionValue('--experimental-worker')) {
setupDOMException();
}

Expand Down Expand Up @@ -167,8 +162,10 @@
'DeprecationWarning', 'DEP0062', startup, true);
}

if (experimentalModulesOption || experimentalVMModulesOption) {
if (experimentalModulesOption) {
const experimentalModules = getOptionValue('--experimental-modules');
const experimentalVMModules = getOptionValue('--experimental-vm-modules');
if (experimentalModules || experimentalVMModules) {
if (experimentalModules) {
process.emitWarning(
'The ESM module loader is experimental.',
'ExperimentalWarning', undefined);
Expand Down Expand Up @@ -228,22 +225,33 @@

setupAllowedFlags();

// There are various modes that Node can run in. The most common two
// are running from a script and running the REPL - but there are a few
// others like the debugger or running --eval arguments. Here we decide
// which mode we run in.
startExecution();
}

// There are various modes that Node can run in. The most common two
// are running from a script and running the REPL - but there are a few
// others like the debugger or running --eval arguments. Here we decide
// which mode we run in.
function startExecution() {
// This means we are in a Worker context, and any script execution
// will be directed by the worker module.
if (internalBinding('worker').getEnvMessagePort() !== undefined) {
// This means we are in a Worker context, and any script execution
// will be directed by the worker module.
NativeModule.require('internal/worker').setupChild(evalScript);
} else if (NativeModule.exists('_third_party_main')) {
// To allow people to extend Node in different ways, this hook allows
// one to drop a file lib/_third_party_main.js into the build
// directory which will be executed instead of Node's normal loading.
return;
}

// To allow people to extend Node in different ways, this hook allows
// one to drop a file lib/_third_party_main.js into the build
// directory which will be executed instead of Node's normal loading.
if (NativeModule.exists('_third_party_main')) {
process.nextTick(() => {
NativeModule.require('_third_party_main');
});
} else if (process.argv[1] === 'inspect' || process.argv[1] === 'debug') {
return;
}

// `node inspect ...` or `node debug ...`
if (process.argv[1] === 'inspect' || process.argv[1] === 'debug') {
if (process.argv[1] === 'debug') {
process.emitWarning(
'`node debug` is deprecated. Please use `node inspect` instead.',
Expand All @@ -254,95 +262,136 @@
process.nextTick(() => {
NativeModule.require('internal/deps/node-inspect/lib/_inspect').start();
});
return;
}

} else if (process.profProcess) {
// `node --prof-process`
// TODO(joyeecheung): use internal/options instead of process.profProcess
if (process.profProcess) {
NativeModule.require('internal/v8_prof_processor');
} else {
// There is user code to be run.

// If this is a worker in cluster mode, start up the communication
// channel. This needs to be done before any user code gets executed
// (including preload modules).
if (process.argv[1] && process.env.NODE_UNIQUE_ID) {
const cluster = NativeModule.require('cluster');
cluster._setupWorker();
// Make sure it's not accidentally inherited by child processes.
delete process.env.NODE_UNIQUE_ID;
return;
}

// There is user code to be run.
prepareUserCodeExecution();
executeUserCode();
}

function prepareUserCodeExecution() {
// If this is a worker in cluster mode, start up the communication
// channel. This needs to be done before any user code gets executed
// (including preload modules).
if (process.argv[1] && process.env.NODE_UNIQUE_ID) {
const cluster = NativeModule.require('cluster');
cluster._setupWorker();
// Make sure it's not accidentally inherited by child processes.
delete process.env.NODE_UNIQUE_ID;
}

// For user code, we preload modules if `-r` is passed
// TODO(joyeecheung): use internal/options instead of
// process._preload_modules
if (process._preload_modules) {
const {
_preloadModules
} = NativeModule.require('internal/modules/cjs/loader');
_preloadModules(process._preload_modules);
}
}

function executeUserCode() {
// User passed `-e` or `--eval` arguments to Node without `-i` or
// `--interactive`.
// Note that the name `forceRepl` is merely an alias of `interactive`
// in code.
// TODO(joyeecheung): use internal/options instead of
// process._eval/process._forceRepl
if (process._eval != null && !process._forceRepl) {
const {
addBuiltinLibsToObject
} = NativeModule.require('internal/modules/cjs/helpers');
addBuiltinLibsToObject(global);
evalScript('[eval]', wrapForBreakOnFirstLine(process._eval));
return;
}

// If the first argument is a file name, run it as a main script
if (process.argv[1] && process.argv[1] !== '-') {
// Expand process.argv[1] into a full path.
const path = NativeModule.require('path');
process.argv[1] = path.resolve(process.argv[1]);

const CJSModule = NativeModule.require('internal/modules/cjs/loader');

// If user passed `-c` or `--check` arguments to Node, check its syntax
// instead of actually running the file.
// TODO(joyeecheung): use internal/options instead of
// process._syntax_check_only
if (process._syntax_check_only != null) {
const fs = NativeModule.require('fs');
// Read the source.
const filename = CJSModule._resolveFilename(process.argv[1]);
const source = fs.readFileSync(filename, 'utf-8');
checkScriptSyntax(source, filename);
process.exit(0);
}

if (process._eval != null && !process._forceRepl) {
// User passed '-e' or '--eval' arguments to Node without '-i' or
// '--interactive'.
preloadModules();

const {
addBuiltinLibsToObject
} = NativeModule.require('internal/modules/cjs/helpers');
addBuiltinLibsToObject(global);
evalScript('[eval]');
} else if (process.argv[1] && process.argv[1] !== '-') {
// Make process.argv[1] into a full path.
const path = NativeModule.require('path');
process.argv[1] = path.resolve(process.argv[1]);

const CJSModule = NativeModule.require('internal/modules/cjs/loader');

preloadModules();
// Check if user passed `-c` or `--check` arguments to Node.
if (process._syntax_check_only != null) {
const fs = NativeModule.require('fs');
// Read the source.
const filename = CJSModule._resolveFilename(process.argv[1]);
const source = fs.readFileSync(filename, 'utf-8');
checkScriptSyntax(source, filename);
process.exit(0);
// Note: this actually tries to run the module as a ESM first if
// --experimental-modules is on.
// TODO(joyeecheung): can we move that logic to here? Note that this
// is an undocumented method available via `require('module').runMain`
CJSModule.runMain();
return;
}

// Create the REPL if `-i` or `--interactive` is passed, or if
// stdin is a TTY.
// Note that the name `forceRepl` is merely an alias of `interactive`
// in code.
if (process._forceRepl || NativeModule.require('tty').isatty(0)) {
const cliRepl = NativeModule.require('internal/repl');
cliRepl.createInternalRepl(process.env, (err, repl) => {
if (err) {
throw err;
}
CJSModule.runMain();
} else {
preloadModules();
// If -i or --interactive were passed, or stdin is a TTY.
if (process._forceRepl || NativeModule.require('tty').isatty(0)) {
// REPL
const cliRepl = NativeModule.require('internal/repl');
cliRepl.createInternalRepl(process.env, (err, repl) => {
if (err) {
throw err;
}
repl.on('exit', () => {
if (repl._flushing) {
repl.pause();
return repl.once('flushHistory', () => {
process.exit();
});
}
repl.on('exit', () => {
if (repl._flushing) {
repl.pause();
return repl.once('flushHistory', () => {
process.exit();
});
});

if (process._eval != null) {
// User passed '-e' or '--eval'
evalScript('[eval]');
}
} else {
// Read all of stdin - execute it.
process.stdin.setEncoding('utf8');

let code = '';
process.stdin.on('data', (d) => {
code += d;
});

process.stdin.on('end', function() {
if (process._syntax_check_only != null) {
checkScriptSyntax(code, '[stdin]');
} else {
process._eval = code;
evalScript('[stdin]');
}
});
}
process.exit();
});
});

// User passed '-e' or '--eval' along with `-i` or `--interactive`
if (process._eval != null) {
evalScript('[eval]', wrapForBreakOnFirstLine(process._eval));
}
return;
}

// Stdin is not a TTY, we will read it and execute it.
readAndExecuteStdin();
}

function readAndExecuteStdin() {
process.stdin.setEncoding('utf8');

let code = '';
process.stdin.on('data', (d) => {
code += d;
});

process.stdin.on('end', () => {
if (process._syntax_check_only != null) {
checkScriptSyntax(code, '[stdin]');
} else {
process._eval = code;
evalScript('[stdin]', wrapForBreakOnFirstLine(process._eval));
}
});
}

function setupTraceCategoryState() {
Expand Down Expand Up @@ -651,7 +700,7 @@
return `process.binding('inspector').callAndPauseOnStart(${fn}, {})`;
}

function evalScript(name, body = wrapForBreakOnFirstLine(process._eval)) {
function evalScript(name, body) {
const CJSModule = NativeModule.require('internal/modules/cjs/loader');
const path = NativeModule.require('path');
const cwd = tryGetCwd(path);
Expand All @@ -673,16 +722,6 @@
process._tickCallback();
}

// Load preload modules.
function preloadModules() {
if (process._preload_modules) {
const {
_preloadModules
} = NativeModule.require('internal/modules/cjs/loader');
_preloadModules(process._preload_modules);
}
}

function checkScriptSyntax(source, filename) {
const CJSModule = NativeModule.require('internal/modules/cjs/loader');
const vm = NativeModule.require('vm');
Expand Down
1 change: 1 addition & 0 deletions test/message/assert_throws_stack.out
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
at *
at *
at *
at *
2 changes: 1 addition & 1 deletion test/message/core_line_numbers.out
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ RangeError: Invalid input
at tryModuleLoad (internal/modules/cjs/loader.js:*:*)
at Function.Module._load (internal/modules/cjs/loader.js:*:*)
at Function.Module.runMain (internal/modules/cjs/loader.js:*:*)
at startup (internal/bootstrap/node.js:*:*)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These stack frames are truncated because we have a default Error.stackTraceLimit = 10. Makes me wonder again that we probably should implement #20505

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i can put it on the list of things to add once #23926 is complete

at executeUserCode (internal/bootstrap/node.js:*:*)
4 changes: 3 additions & 1 deletion test/message/error_exit.out
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,7 @@ AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
at tryModuleLoad (internal/modules/cjs/loader.js:*:*)
at Function.Module._load (internal/modules/cjs/loader.js:*:*)
at Function.Module.runMain (internal/modules/cjs/loader.js:*:*)
at executeUserCode (internal/bootstrap/node.js:*:*)
at startExecution (internal/bootstrap/node.js:*:*)
at startup (internal/bootstrap/node.js:*:*)
at bootstrapNodeJSCore (internal/bootstrap/node.js:*:*)

8 changes: 8 additions & 0 deletions test/message/eval_messages.out
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ SyntaxError: Strict mode code may not include a with statement
at Object.<anonymous> ([eval]-wrapper:*:*)
at Module._compile (internal/modules/cjs/loader.js:*:*)
at evalScript (internal/bootstrap/node.js:*:*)
at executeUserCode (internal/bootstrap/node.js:*:*)
at startExecution (internal/bootstrap/node.js:*:*)
at startup (internal/bootstrap/node.js:*:*)
at bootstrapNodeJSCore (internal/bootstrap/node.js:*:*)
42
Expand All @@ -24,6 +26,8 @@ Error: hello
at Object.<anonymous> ([eval]-wrapper:*:*)
at Module._compile (internal/modules/cjs/loader.js:*:*)
at evalScript (internal/bootstrap/node.js:*:*)
at executeUserCode (internal/bootstrap/node.js:*:*)
at startExecution (internal/bootstrap/node.js:*:*)
at startup (internal/bootstrap/node.js:*:*)
at bootstrapNodeJSCore (internal/bootstrap/node.js:*:*)

Expand All @@ -38,6 +42,8 @@ Error: hello
at Object.<anonymous> ([eval]-wrapper:*:*)
at Module._compile (internal/modules/cjs/loader.js:*:*)
at evalScript (internal/bootstrap/node.js:*:*)
at executeUserCode (internal/bootstrap/node.js:*:*)
at startExecution (internal/bootstrap/node.js:*:*)
at startup (internal/bootstrap/node.js:*:*)
at bootstrapNodeJSCore (internal/bootstrap/node.js:*:*)
100
Expand All @@ -52,6 +58,8 @@ ReferenceError: y is not defined
at Object.<anonymous> ([eval]-wrapper:*:*)
at Module._compile (internal/modules/cjs/loader.js:*:*)
at evalScript (internal/bootstrap/node.js:*:*)
at executeUserCode (internal/bootstrap/node.js:*:*)
at startExecution (internal/bootstrap/node.js:*:*)
at startup (internal/bootstrap/node.js:*:*)
at bootstrapNodeJSCore (internal/bootstrap/node.js:*:*)

Expand Down
Loading