Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 32261fc

Browse filesBrowse files
avivkelleraduh95
authored andcommitted
module: support loading entrypoint as url
Co-Authored-By: Antoine du Hamel <duhamelantoine1995@gmail.com> PR-URL: #54933 Refs: #49975 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: LiviaMedeiros <livia@cirno.name> Reviewed-By: Stephen Belanger <admin@stephenbelanger.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
1 parent e99d4a4 commit 32261fc
Copy full SHA for 32261fc

File tree

Expand file treeCollapse file tree

8 files changed

+147
-8
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

8 files changed

+147
-8
lines changed
Open diff view settings
Collapse file

‎doc/api/cli.md‎

Copy file name to clipboardExpand all lines: doc/api/cli.md
+24Lines changed: 24 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -795,6 +795,28 @@ when `Error.stack` is accessed. If you access `Error.stack` frequently
795795
in your application, take into account the performance implications
796796
of `--enable-source-maps`.
797797

798+
### `--entry-url`
799+
800+
<!-- YAML
801+
added:
802+
- REPLACEME
803+
-->
804+
805+
> Stability: 1 - Experimental
806+
807+
When present, Node.js will interpret the entry point as a URL, rather than a
808+
path.
809+
810+
Follows [ECMAScript module][] resolution rules.
811+
812+
Any query parameter or hash in the URL will be accessible via [`import.meta.url`][].
813+
814+
```bash
815+
node --entry-url 'file:///path/to/file.js?queryparams=work#and-hashes-too'
816+
node --entry-url --experimental-strip-types 'file.ts?query#hash'
817+
node --entry-url 'data:text/javascript,console.log("Hello")'
818+
```
819+
798820
### `--env-file=config`
799821

800822
> Stability: 1.1 - Active development
@@ -3024,6 +3046,7 @@ one is included in the list below.
30243046
* `--enable-fips`
30253047
* `--enable-network-family-autoselection`
30263048
* `--enable-source-maps`
3049+
* `--entry-url`
30273050
* `--experimental-abortcontroller`
30283051
* `--experimental-async-context-frame`
30293052
* `--experimental-default-type`
@@ -3623,6 +3646,7 @@ node --stack-trace-limit=12 -p -e "Error.stackTraceLimit" # prints 12
36233646
[`dns.lookup()`]: dns.md#dnslookuphostname-options-callback
36243647
[`dns.setDefaultResultOrder()`]: dns.md#dnssetdefaultresultorderorder
36253648
[`dnsPromises.lookup()`]: dns.md#dnspromiseslookuphostname-options
3649+
[`import.meta.url`]: esm.md#importmetaurl
36263650
[`import` specifier]: esm.md#import-specifiers
36273651
[`net.getDefaultAutoSelectFamilyAttemptTimeout()`]: net.md#netgetdefaultautoselectfamilyattempttimeout
36283652
[`node:sqlite`]: sqlite.md
Collapse file

‎doc/node.1‎

Copy file name to clipboardExpand all lines: doc/node.1
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,9 @@ Requires Node.js to be built with
160160
.It Fl -enable-source-maps
161161
Enable Source Map V3 support for stack traces.
162162
.
163+
.It Fl -entry-url
164+
Interpret the entry point as a URL.
165+
.
163166
.It Fl -experimental-default-type Ns = Ns Ar type
164167
Interpret as either ES modules or CommonJS modules input via --eval or STDIN, when --input-type is unspecified;
165168
.js or extensionless files with no sibling or parent package.json;
Collapse file

‎lib/internal/main/run_main_module.js‎

Copy file name to clipboardExpand all lines: lib/internal/main/run_main_module.js
+7-1Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,20 @@ const {
99
markBootstrapComplete,
1010
} = require('internal/process/pre_execution');
1111
const { getOptionValue } = require('internal/options');
12+
const { emitExperimentalWarning } = require('internal/util');
1213

13-
const mainEntry = prepareMainThreadExecution(true);
14+
const isEntryURL = getOptionValue('--entry-url');
15+
const mainEntry = prepareMainThreadExecution(!isEntryURL);
1416

1517
markBootstrapComplete();
1618

1719
// Necessary to reset RegExp statics before user code runs.
1820
RegExpPrototypeExec(/^/, '');
1921

22+
if (isEntryURL) {
23+
emitExperimentalWarning('--entry-url');
24+
}
25+
2026
if (getOptionValue('--experimental-default-type') === 'module') {
2127
require('internal/modules/run_main').executeUserEntryPoint(mainEntry);
2228
} else {
Collapse file

‎lib/internal/modules/run_main.js‎

Copy file name to clipboardExpand all lines: lib/internal/modules/run_main.js
+10-7Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const {
88
const { getNearestParentPackageJSONType } = internalBinding('modules');
99
const { getOptionValue } = require('internal/options');
1010
const path = require('path');
11-
const { pathToFileURL } = require('internal/url');
11+
const { pathToFileURL, URL } = require('internal/url');
1212
const { kEmptyObject, getCWDURL } = require('internal/util');
1313
const {
1414
hasUncaughtExceptionCaptureCallback,
@@ -154,9 +154,14 @@ function runEntryPointWithESMLoader(callback) {
154154
* @param {string} main - First positional CLI argument, such as `'entry.js'` from `node entry.js`
155155
*/
156156
function executeUserEntryPoint(main = process.argv[1]) {
157-
const resolvedMain = resolveMainPath(main);
158-
const useESMLoader = shouldUseESMLoader(resolvedMain);
159-
let mainURL;
157+
let useESMLoader;
158+
let resolvedMain;
159+
if (getOptionValue('--entry-url')) {
160+
useESMLoader = true;
161+
} else {
162+
resolvedMain = resolveMainPath(main);
163+
useESMLoader = shouldUseESMLoader(resolvedMain);
164+
}
160165
// Unless we know we should use the ESM loader to handle the entry point per the checks in `shouldUseESMLoader`, first
161166
// try to run the entry point via the CommonJS loader; and if that fails under certain conditions, retry as ESM.
162167
if (!useESMLoader) {
@@ -165,9 +170,7 @@ function executeUserEntryPoint(main = process.argv[1]) {
165170
wrapModuleLoad(main, null, true);
166171
} else {
167172
const mainPath = resolvedMain || main;
168-
if (mainURL === undefined) {
169-
mainURL = pathToFileURL(mainPath).href;
170-
}
173+
const mainURL = getOptionValue('--entry-url') ? new URL(mainPath, getCWDURL()) : pathToFileURL(mainPath);
171174

172175
runEntryPointWithESMLoader((cascadedLoader) => {
173176
// Note that if the graph contains unsettled TLA, this may never resolve
Collapse file

‎src/node_options.cc‎

Copy file name to clipboardExpand all lines: src/node_options.cc
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,10 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() {
406406
"Source Map V3 support for stack traces",
407407
&EnvironmentOptions::enable_source_maps,
408408
kAllowedInEnvvar);
409+
AddOption("--entry-url",
410+
"Treat the entrypoint as a URL",
411+
&EnvironmentOptions::entry_is_url,
412+
kAllowedInEnvvar);
409413
AddOption("--experimental-abortcontroller", "", NoOp{}, kAllowedInEnvvar);
410414
AddOption("--experimental-eventsource",
411415
"experimental EventSource API",
Collapse file

‎src/node_options.h‎

Copy file name to clipboardExpand all lines: src/node_options.h
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ class EnvironmentOptions : public Options {
133133
bool experimental_import_meta_resolve = false;
134134
std::string input_type; // Value of --input-type
135135
std::string type; // Value of --experimental-default-type
136+
bool entry_is_url = false;
136137
bool experimental_permission = false;
137138
std::vector<std::string> allow_fs_read;
138139
std::vector<std::string> allow_fs_write;
Collapse file
+97Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import { spawnPromisified } from '../common/index.mjs';
2+
import * as fixtures from '../common/fixtures.mjs';
3+
import assert from 'node:assert';
4+
import { execPath } from 'node:process';
5+
import { describe, it } from 'node:test';
6+
7+
// Helper function to assert the spawned process
8+
async function assertSpawnedProcess(args, options = {}, expected = {}) {
9+
const { code, signal, stderr, stdout } = await spawnPromisified(execPath, args, options);
10+
11+
if (expected.stderr) {
12+
assert.match(stderr, expected.stderr);
13+
}
14+
15+
if (expected.stdout) {
16+
assert.match(stdout, expected.stdout);
17+
}
18+
19+
assert.strictEqual(code, expected.code ?? 0);
20+
assert.strictEqual(signal, expected.signal ?? null);
21+
}
22+
23+
// Common expectation for experimental feature warning in stderr
24+
const experimentalFeatureWarning = { stderr: /--entry-url is an experimental feature/ };
25+
26+
describe('--entry-url', { concurrency: true }, () => {
27+
it('should reject loading a path that contains %', async () => {
28+
await assertSpawnedProcess(
29+
['--entry-url', './test-esm-double-encoding-native%20.mjs'],
30+
{ cwd: fixtures.fileURL('es-modules') },
31+
{
32+
code: 1,
33+
stderr: /ERR_MODULE_NOT_FOUND/,
34+
}
35+
);
36+
});
37+
38+
it('should support loading properly encoded Unix path', async () => {
39+
await assertSpawnedProcess(
40+
['--entry-url', fixtures.fileURL('es-modules/test-esm-double-encoding-native%20.mjs').pathname],
41+
{},
42+
experimentalFeatureWarning
43+
);
44+
});
45+
46+
it('should support loading absolute URLs', async () => {
47+
await assertSpawnedProcess(
48+
['--entry-url', fixtures.fileURL('printA.js')],
49+
{},
50+
{
51+
...experimentalFeatureWarning,
52+
stdout: /^A\r?\n$/,
53+
}
54+
);
55+
});
56+
57+
it('should support loading relative URLs', async () => {
58+
await assertSpawnedProcess(
59+
['--entry-url', 'es-modules/print-entrypoint.mjs?key=value#hash'],
60+
{ cwd: fixtures.fileURL('./') },
61+
{
62+
...experimentalFeatureWarning,
63+
stdout: /print-entrypoint\.mjs\?key=value#hash\r?\n$/,
64+
}
65+
);
66+
});
67+
68+
it('should support loading `data:` URLs', async () => {
69+
await assertSpawnedProcess(
70+
['--entry-url', 'data:text/javascript,console.log(import.meta.url)'],
71+
{},
72+
{
73+
...experimentalFeatureWarning,
74+
stdout: /^data:text\/javascript,console\.log\(import\.meta\.url\)\r?\n$/,
75+
}
76+
);
77+
});
78+
79+
it('should support loading TypeScript URLs', async () => {
80+
const typescriptUrls = [
81+
'typescript/cts/test-require-ts-file.cts',
82+
'typescript/mts/test-import-ts-file.mts',
83+
];
84+
85+
for (const url of typescriptUrls) {
86+
await assertSpawnedProcess(
87+
['--entry-url', '--experimental-strip-types', fixtures.fileURL(url)],
88+
{},
89+
{
90+
...experimentalFeatureWarning,
91+
stdout: /Hello, TypeScript!/,
92+
}
93+
);
94+
}
95+
});
96+
97+
});
Collapse file
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
console.log(import.meta.url);

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.