Skip to content
Open
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
12 changes: 12 additions & 0 deletions doc/api/process.md
Original file line number Diff line number Diff line change
Expand Up @@ -1513,6 +1513,18 @@ emitMyWarning();
// Emits nothing
```
## `process.entrypoint`
<!-- YAML
added: REPLACEME
-->
* Type: {URL | undefined}
The entry point that Node.js was started with. Worker threads inherit this
value. If Node.js was started without an entry point, such as in the REPL, the
value is {undefined}.
## `process.env`
<!-- YAML
Expand Down
6 changes: 6 additions & 0 deletions lib/internal/main/worker_thread.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const {
} = primordials;

const {
defineEntrypoint,
prepareWorkerThreadExecution,
initializeModuleLoaders,
markBootstrapComplete,
Expand Down Expand Up @@ -95,6 +96,7 @@ port.on('message', (message) => {
argv,
cwdCounter,
doEval,
entrypoint,
environmentData,
filename,
hasStdin,
Expand All @@ -103,6 +105,10 @@ port.on('message', (message) => {
mainThreadPort,
} = message;

const { URL } = require('internal/url');
defineEntrypoint(entrypoint === undefined ?
undefined : new URL(entrypoint));

if (doEval !== 'internal') {
if (argv !== undefined) {
ArrayPrototypePushApply(process.argv, argv);
Expand Down
22 changes: 22 additions & 0 deletions lib/internal/process/pre_execution.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const {
setupCoverageHooks,
emitExperimentalWarning,
deprecate,
getCWDURL,
} = require('internal/util');

const {
Expand Down Expand Up @@ -254,6 +255,16 @@ function refreshRuntimeOptions() {
refreshOptions();
}

function defineEntrypoint(entrypoint) {
ObjectDefineProperty(process, 'entrypoint', {
__proto__: null,
writable: false,
enumerable: true,
configurable: true,
value: entrypoint,
});
}

/**
* Patch the process object with legacy properties and normalizations.
* Replace `process.argv[0]` with `process.execPath`, preserving the original `argv[0]` value as `process.argv0`.
Expand Down Expand Up @@ -294,6 +305,16 @@ function patchProcessObject(expandArgv1) {
}
}

let entrypoint;
if (mainEntry !== undefined) {
const { pathToFileURL } = require('internal/url');
entrypoint = pathToFileURL(mainEntry);
} else if (getOptionValue('--entry-url') && process.argv[1]) {
const { URL } = require('internal/url');
entrypoint = new URL(process.argv[1], getCWDURL());
}
defineEntrypoint(entrypoint);

// We need to initialize the global console here again with process.stdout
// and friends for snapshot deserialization.
const globalConsole = require('internal/console/global');
Expand Down Expand Up @@ -824,6 +845,7 @@ function getHeapSnapshotFilename(diagnosticDir) {
}

module.exports = {
defineEntrypoint,
initializeModuleLoaders,
prepareMainThreadExecution,
prepareWorkerThreadExecution,
Expand Down
1 change: 1 addition & 0 deletions lib/internal/worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,7 @@ class Worker extends EventEmitter {

this[kPort].postMessage({
argv,
entrypoint: process.entrypoint?.href,
type: messageTypes.LOAD_SCRIPT,
filename,
doEval,
Expand Down
5 changes: 5 additions & 0 deletions test/fixtures/entrypoint/check-commonjs.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
'use strict';

const assert = require('node:assert');

assert.strictEqual(process.entrypoint.href, process.env.NODE_TEST_ENTRYPOINT);
4 changes: 4 additions & 0 deletions test/fixtures/entrypoint/check-module.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import assert from 'node:assert';
import { entrypoint } from 'node:process';

assert.strictEqual(entrypoint.href, process.env.NODE_TEST_ENTRYPOINT);
1 change: 1 addition & 0 deletions test/fixtures/entrypoint/commonjs.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
console.log(process.entrypoint.href);
4 changes: 4 additions & 0 deletions test/fixtures/entrypoint/loader.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import assert from 'node:assert';
import { entrypoint } from 'node:process';

assert.strictEqual(entrypoint.href, process.env.NODE_TEST_ENTRYPOINT);
1 change: 1 addition & 0 deletions test/fixtures/entrypoint/module.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
console.log(process.entrypoint.href);
9 changes: 9 additions & 0 deletions test/fixtures/entrypoint/worker.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
'use strict';

const { isMainThread, workerData, Worker } = require('node:worker_threads');

if (isMainThread || workerData === 'nested') {
new Worker(__filename, { workerData: isMainThread ? 'nested' : 'leaf' });
} else {
console.log(process.entrypoint.href);
}
118 changes: 118 additions & 0 deletions test/parallel/test-process-entrypoint.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
'use strict';

const { spawnPromisified } = require('../common');
const fixtures = require('../common/fixtures');

const assert = require('node:assert');
const { execPath } = require('node:process');
const { describe, it } = require('node:test');

const cjsFixture = fixtures.path('entrypoint', 'commonjs.cjs');
const cjsFixtureURL = fixtures.fileURL('entrypoint', 'commonjs.cjs').href;

const mjsFixture = fixtures.path('entrypoint', 'module.mjs');
const mjsFixtureURL = fixtures.fileURL('entrypoint', 'module.mjs').href;

const workerFixture = fixtures.path('entrypoint', 'worker.cjs');
const workerFixtureURL = fixtures.fileURL('entrypoint', 'worker.cjs').href;

const cjsPreload = fixtures.path('entrypoint', 'check-commonjs.cjs');
const esmPreload = fixtures.fileURL('entrypoint', 'check-module.mjs').href;
const loader = fixtures.fileURL('entrypoint', 'loader.mjs').href;

const printEntrypoint = 'console.log(process.entrypoint?.href)';

async function getEntrypoint(args, options, expected) {
const { code, signal, stderr, stdout } = await spawnPromisified(
execPath,
args,
{
...options,
env: {
...process.env,
NODE_TEST_ENTRYPOINT: expected,
},
},
);
assert.strictEqual(code, 0, stderr);
assert.strictEqual(signal, null);

return stdout.trim();
}

const testCases = [
{
name: 'is the file URL of a CommonJS entry point',
args: [cjsFixture],
expected: cjsFixtureURL,
},
{
name: 'is the file URL of an ES module entry point',
args: [mjsFixture],
expected: mjsFixtureURL,
},
{
name: 'is absolute when passed a relative path',
args: ['./commonjs.cjs'],
options: { cwd: fixtures.path('entrypoint') },
expected: cjsFixtureURL,
},
{
name: 'stays correct when using --require',
args: ['--require', cjsPreload, cjsFixture],
expected: cjsFixtureURL,
},
{
name: 'stays correct when using --import',
args: ['--import', esmPreload, cjsFixture],
expected: cjsFixtureURL,
},
{
name: 'stays correct when using --loader',
args: ['--loader', loader, cjsFixture],
expected: cjsFixtureURL,
},
{
name: 'stays correct when combining preloads and loaders',
args: [
'--require', cjsPreload,
'--import', esmPreload,
'--loader', loader,
mjsFixture,
],
expected: mjsFixtureURL,
},
{
name: 'is inherited by worker threads and their preloads and loaders',
args: [
'--require', cjsPreload,
'--import', esmPreload,
'--loader', loader,
workerFixture,
],
expected: workerFixtureURL,
},
{
name: 'supports non-file --entry-url entry points',
args: ['--entry-url', `data:text/javascript,${printEntrypoint}`],
expected: `data:text/javascript,${printEntrypoint}`,
},
{
name: 'is undefined when evaluating CommonJS without an entry point',
args: ['--eval', printEntrypoint],
expected: 'undefined',
},
{
name: 'is undefined when evaluating an ES module without an entry point',
args: ['--input-type=module', '--eval', printEntrypoint],
expected: 'undefined',
},
];

describe('process.entrypoint', { concurrency: true }, () => {
for (const { name, args, options, expected } of testCases) {
it(name, async () => {
assert.strictEqual(await getEntrypoint(args, options, expected), expected);
});
}
});
Loading