summaryrefslogtreecommitdiff
path: root/ext/node
diff options
context:
space:
mode:
Diffstat (limited to 'ext/node')
-rw-r--r--ext/node/polyfills/02_init.js67
-rw-r--r--ext/node/polyfills/_process/streams.mjs16
-rw-r--r--ext/node/polyfills/process.ts120
3 files changed, 120 insertions, 83 deletions
diff --git a/ext/node/polyfills/02_init.js b/ext/node/polyfills/02_init.js
index 85f924493..752f518bf 100644
--- a/ext/node/polyfills/02_init.js
+++ b/ext/node/polyfills/02_init.js
@@ -16,38 +16,32 @@ function initialize(
runningOnMainThread,
workerId,
maybeWorkerMetadata,
+ warmup = false,
) {
- if (initialized) {
- throw Error("Node runtime already initialized");
- }
- initialized = true;
- if (usesLocalNodeModulesDir) {
- requireImpl.setUsesLocalNodeModulesDir();
- }
- const nativeModuleExports = requireImpl.nativeModuleExports;
- nodeGlobals.Buffer = nativeModuleExports["buffer"].Buffer;
- nodeGlobals.clearImmediate = nativeModuleExports["timers"].clearImmediate;
- nodeGlobals.clearInterval = nativeModuleExports["timers"].clearInterval;
- nodeGlobals.clearTimeout = nativeModuleExports["timers"].clearTimeout;
- nodeGlobals.console = nativeModuleExports["console"];
- nodeGlobals.global = globalThis;
- nodeGlobals.process = nativeModuleExports["process"];
- nodeGlobals.setImmediate = nativeModuleExports["timers"].setImmediate;
- nodeGlobals.setInterval = nativeModuleExports["timers"].setInterval;
- nodeGlobals.setTimeout = nativeModuleExports["timers"].setTimeout;
- nodeGlobals.performance = nativeModuleExports["perf_hooks"].performance;
+ if (!warmup) {
+ if (initialized) {
+ throw Error("Node runtime already initialized");
+ }
+ initialized = true;
+ if (usesLocalNodeModulesDir) {
+ requireImpl.setUsesLocalNodeModulesDir();
+ }
- // FIXME(bartlomieju): not nice to depend on `Deno` namespace here
- // but it's the only way to get `args` and `version` and this point.
- internals.__bootstrapNodeProcess(argv0, Deno.args, Deno.version);
- internals.__initWorkerThreads(
- runningOnMainThread,
- workerId,
- maybeWorkerMetadata,
- );
- internals.__setupChildProcessIpcChannel();
- // `Deno[Deno.internal].requireImpl` will be unreachable after this line.
- delete internals.requireImpl;
+ // FIXME(bartlomieju): not nice to depend on `Deno` namespace here
+ // but it's the only way to get `args` and `version` and this point.
+ internals.__bootstrapNodeProcess(argv0, Deno.args, Deno.version);
+ internals.__initWorkerThreads(
+ runningOnMainThread,
+ workerId,
+ maybeWorkerMetadata,
+ );
+ internals.__setupChildProcessIpcChannel();
+ // `Deno[Deno.internal].requireImpl` will be unreachable after this line.
+ delete internals.requireImpl;
+ } else {
+ // Warm up the process module
+ internals.__bootstrapNodeProcess(undefined, undefined, undefined, true);
+ }
}
function loadCjsModule(moduleName, isMain, inspectBrk) {
@@ -63,3 +57,16 @@ internals.node = {
initialize,
loadCjsModule,
};
+
+const nativeModuleExports = requireImpl.nativeModuleExports;
+nodeGlobals.Buffer = nativeModuleExports["buffer"].Buffer;
+nodeGlobals.clearImmediate = nativeModuleExports["timers"].clearImmediate;
+nodeGlobals.clearInterval = nativeModuleExports["timers"].clearInterval;
+nodeGlobals.clearTimeout = nativeModuleExports["timers"].clearTimeout;
+nodeGlobals.console = nativeModuleExports["console"];
+nodeGlobals.global = globalThis;
+nodeGlobals.process = nativeModuleExports["process"];
+nodeGlobals.setImmediate = nativeModuleExports["timers"].setImmediate;
+nodeGlobals.setInterval = nativeModuleExports["timers"].setInterval;
+nodeGlobals.setTimeout = nativeModuleExports["timers"].setTimeout;
+nodeGlobals.performance = nativeModuleExports["perf_hooks"].performance;
diff --git a/ext/node/polyfills/_process/streams.mjs b/ext/node/polyfills/_process/streams.mjs
index 09c53eb9a..f50e20588 100644
--- a/ext/node/polyfills/_process/streams.mjs
+++ b/ext/node/polyfills/_process/streams.mjs
@@ -16,7 +16,7 @@ import * as io from "ext:deno_io/12_io.js";
import { guessHandleType } from "ext:deno_node/internal_binding/util.ts";
// https://github.com/nodejs/node/blob/00738314828074243c9a52a228ab4c68b04259ef/lib/internal/bootstrap/switches/is_main_thread.js#L41
-export function createWritableStdioStream(writer, name) {
+export function createWritableStdioStream(writer, name, warmup = false) {
const stream = new Writable({
emitClose: false,
write(buf, enc, cb) {
@@ -73,7 +73,9 @@ export function createWritableStdioStream(writer, name) {
},
});
- if (writer?.isTerminal()) {
+ // If we're warming up, create a stdout/stderr stream that assumes a terminal (the most likely case).
+ // If we're wrong at boot time, we'll recreate it.
+ if (warmup || writer?.isTerminal()) {
// These belong on tty.WriteStream(), but the TTY streams currently have
// following problems:
// 1. Using them here introduces a circular dependency.
@@ -123,10 +125,11 @@ export function setReadStream(s) {
/** https://nodejs.org/api/process.html#process_process_stdin */
// https://github.com/nodejs/node/blob/v18.12.1/lib/internal/bootstrap/switches/is_main_thread.js#L189
/** Create process.stdin */
-export const initStdin = () => {
+export const initStdin = (warmup = false) => {
const fd = io.stdin ? io.STDIN_RID : undefined;
let stdin;
- const stdinType = _guessStdinType(fd);
+ // Warmup assumes a TTY for all stdio
+ const stdinType = warmup ? "TTY" : _guessStdinType(fd);
switch (stdinType) {
case "FILE": {
@@ -142,6 +145,11 @@ export const initStdin = () => {
break;
}
case "TTY": {
+ // If it's a TTY, we know that the stdin we created during warmup is the correct one and
+ // just return null to re-use it.
+ if (!warmup) {
+ return null;
+ }
stdin = new readStream(fd);
break;
}
diff --git a/ext/node/polyfills/process.ts b/ext/node/polyfills/process.ts
index 44207e2f4..70c516c96 100644
--- a/ext/node/polyfills/process.ts
+++ b/ext/node/polyfills/process.ts
@@ -68,7 +68,7 @@ const notImplementedEvents = [
"worker",
];
-export const argv: string[] = [];
+export const argv: string[] = ["", ""];
let globalProcessExitCode: number | undefined = undefined;
/** https://nodejs.org/api/process.html#process_process_exit_code */
@@ -868,69 +868,91 @@ function synchronizeListeners() {
}
}
+// Overwrites the 1st and 2nd items with getters.
+Object.defineProperty(argv, "0", { get: () => argv0 });
+Object.defineProperty(argv, "1", {
+ get: () => {
+ if (Deno.mainModule?.startsWith("file:")) {
+ return pathFromURL(new URL(Deno.mainModule));
+ } else {
+ return join(Deno.cwd(), "$deno$node.js");
+ }
+ },
+});
+
// Should be called only once, in `runtime/js/99_main.js` when the runtime is
// bootstrapped.
internals.__bootstrapNodeProcess = function (
argv0Val: string | undefined,
args: string[],
denoVersions: Record<string, string>,
+ warmup = false,
) {
- // Overwrites the 1st item with getter.
- if (typeof argv0Val === "string") {
- argv0 = argv0Val;
- Object.defineProperty(argv, "0", {
- get: () => {
- return argv0Val;
- },
- });
- } else {
- Object.defineProperty(argv, "0", { get: () => argv0 });
- }
+ if (!warmup) {
+ argv0 = argv0Val || "";
+ // Manually concatenate these arrays to avoid triggering the getter
+ for (let i = 0; i < args.length; i++) {
+ argv[i + 2] = args[i];
+ }
- // Overwrites the 2st item with getter.
- Object.defineProperty(argv, "1", {
- get: () => {
- if (Deno.mainModule?.startsWith("file:")) {
- return pathFromURL(new URL(Deno.mainModule));
- } else {
- return join(Deno.cwd(), "$deno$node.js");
- }
- },
- });
- for (let i = 0; i < args.length; i++) {
- argv[i + 2] = args[i];
- }
+ for (const [key, value] of Object.entries(denoVersions)) {
+ versions[key] = value;
+ }
- for (const [key, value] of Object.entries(denoVersions)) {
- versions[key] = value;
- }
+ core.setNextTickCallback(processTicksAndRejections);
+ core.setMacrotaskCallback(runNextTicks);
+ enableNextTick();
- core.setNextTickCallback(processTicksAndRejections);
- core.setMacrotaskCallback(runNextTicks);
- enableNextTick();
+ // Replace stdin if it is not a terminal
+ const newStdin = initStdin();
+ if (newStdin) {
+ stdin = process.stdin = newStdin;
+ }
- stdin = process.stdin = initStdin();
- /** https://nodejs.org/api/process.html#process_process_stdout */
- stdout = process.stdout = createWritableStdioStream(
- io.stdout,
- "stdout",
- );
+ // Replace stdout/stderr if they are not terminals
+ if (!io.stdout.isTerminal()) {
+ /** https://nodejs.org/api/process.html#process_process_stdout */
+ stdout = process.stdout = createWritableStdioStream(
+ io.stdout,
+ "stdout",
+ );
+ }
- /** https://nodejs.org/api/process.html#process_process_stderr */
- stderr = process.stderr = createWritableStdioStream(
- io.stderr,
- "stderr",
- );
+ if (!io.stderr.isTerminal()) {
+ /** https://nodejs.org/api/process.html#process_process_stderr */
+ stderr = process.stderr = createWritableStdioStream(
+ io.stderr,
+ "stderr",
+ );
+ }
- process.setStartTime(Date.now());
+ process.setStartTime(Date.now());
- arch = arch_();
- platform = isWindows ? "win32" : Deno.build.os;
- pid = Deno.pid;
+ arch = arch_();
+ platform = isWindows ? "win32" : Deno.build.os;
+ pid = Deno.pid;
- // @ts-ignore Remove setStartTime and #startTime is not modifiable
- delete process.setStartTime;
- delete internals.__bootstrapNodeProcess;
+ // @ts-ignore Remove setStartTime and #startTime is not modifiable
+ delete process.setStartTime;
+ delete internals.__bootstrapNodeProcess;
+ } else {
+ // Warmup, assuming stdin/stdout/stderr are all terminals
+ stdin = process.stdin = initStdin(true);
+
+ /** https://nodejs.org/api/process.html#process_process_stdout */
+ stdout = process.stdout = createWritableStdioStream(
+ io.stdout,
+ "stdout",
+ true,
+ );
+
+ /** https://nodejs.org/api/process.html#process_process_stderr */
+ stderr = process.stderr = createWritableStdioStream(
+ io.stderr,
+ "stderr",
+ true,
+ );
+ }
};
export default process;