| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent e99d4a4 commit 32261fc
8 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -795,6 +795,28 @@ when `Error.stack` is accessed. If you access `Error.stack` frequently | |||
| 795 | 795 | in your application, take into account the performance implications | |
| 796 | 796 | of `--enable-source-maps`. | |
| 797 | 797 | ||
| 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 | + | ||
| 798 | 820 | ### `--env-file=config` | |
| 799 | 821 | ||
| 800 | 822 | > Stability: 1.1 - Active development | |
@@ -3024,6 +3046,7 @@ one is included in the list below. | |||
| 3024 | 3046 | * `--enable-fips` | |
| 3025 | 3047 | * `--enable-network-family-autoselection` | |
| 3026 | 3048 | * `--enable-source-maps` | |
| 3049 | + * `--entry-url` | ||
| 3027 | 3050 | * `--experimental-abortcontroller` | |
| 3028 | 3051 | * `--experimental-async-context-frame` | |
| 3029 | 3052 | * `--experimental-default-type` | |
@@ -3623,6 +3646,7 @@ node --stack-trace-limit=12 -p -e "Error.stackTraceLimit" # prints 12 | |||
| 3623 | 3646 | [`dns.lookup()`]: dns.md#dnslookuphostname-options-callback | |
| 3624 | 3647 | [`dns.setDefaultResultOrder()`]: dns.md#dnssetdefaultresultorderorder | |
| 3625 | 3648 | [`dnsPromises.lookup()`]: dns.md#dnspromiseslookuphostname-options | |
| 3649 | + [`import.meta.url`]: esm.md#importmetaurl | ||
| 3626 | 3650 | [`import` specifier]: esm.md#import-specifiers | |
| 3627 | 3651 | [`net.getDefaultAutoSelectFamilyAttemptTimeout()`]: net.md#netgetdefaultautoselectfamilyattempttimeout | |
| 3628 | 3652 | [`node:sqlite`]: sqlite.md | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -160,6 +160,9 @@ Requires Node.js to be built with | |||
| 160 | 160 | .It Fl -enable-source-maps | |
| 161 | 161 | Enable Source Map V3 support for stack traces. | |
| 162 | 162 | . | |
| 163 | + .It Fl -entry-url | ||
| 164 | + Interpret the entry point as a URL. | ||
| 165 | + . | ||
| 163 | 166 | .It Fl -experimental-default-type Ns = Ns Ar type | |
| 164 | 167 | Interpret as either ES modules or CommonJS modules input via --eval or STDIN, when --input-type is unspecified; | |
| 165 | 168 | .js or extensionless files with no sibling or parent package.json; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -9,14 +9,20 @@ const { | |||
| 9 | 9 | markBootstrapComplete, | |
| 10 | 10 | } = require('internal/process/pre_execution'); | |
| 11 | 11 | const { getOptionValue } = require('internal/options'); | |
| 12 | + const { emitExperimentalWarning } = require('internal/util'); | ||
| 12 | 13 | ||
| 13 | - const mainEntry = prepareMainThreadExecution(true); | ||
| 14 | + const isEntryURL = getOptionValue('--entry-url'); | ||
| 15 | + const mainEntry = prepareMainThreadExecution(!isEntryURL); | ||
| 14 | 16 | ||
| 15 | 17 | markBootstrapComplete(); | |
| 16 | 18 | ||
| 17 | 19 | // Necessary to reset RegExp statics before user code runs. | |
| 18 | 20 | RegExpPrototypeExec(/^/, ''); | |
| 19 | 21 | ||
| 22 | + if (isEntryURL) { | ||
| 23 | + emitExperimentalWarning('--entry-url'); | ||
| 24 | + } | ||
| 25 | + | ||
| 20 | 26 | if (getOptionValue('--experimental-default-type') === 'module') { | |
| 21 | 27 | require('internal/modules/run_main').executeUserEntryPoint(mainEntry); | |
| 22 | 28 | } else { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -8,7 +8,7 @@ const { | |||
| 8 | 8 | const { getNearestParentPackageJSONType } = internalBinding('modules'); | |
| 9 | 9 | const { getOptionValue } = require('internal/options'); | |
| 10 | 10 | const path = require('path'); | |
| 11 | - const { pathToFileURL } = require('internal/url'); | ||
| 11 | + const { pathToFileURL, URL } = require('internal/url'); | ||
| 12 | 12 | const { kEmptyObject, getCWDURL } = require('internal/util'); | |
| 13 | 13 | const { | |
| 14 | 14 | hasUncaughtExceptionCaptureCallback, | |
@@ -154,9 +154,14 @@ function runEntryPointWithESMLoader(callback) { | |||
| 154 | 154 | * @param {string} main - First positional CLI argument, such as `'entry.js'` from `node entry.js` | |
| 155 | 155 | */ | |
| 156 | 156 | 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 | + } | ||
| 160 | 165 | // Unless we know we should use the ESM loader to handle the entry point per the checks in `shouldUseESMLoader`, first | |
| 161 | 166 | // try to run the entry point via the CommonJS loader; and if that fails under certain conditions, retry as ESM. | |
| 162 | 167 | if (!useESMLoader) { | |
@@ -165,9 +170,7 @@ function executeUserEntryPoint(main = process.argv[1]) { | |||
| 165 | 170 | wrapModuleLoad(main, null, true); | |
| 166 | 171 | } else { | |
| 167 | 172 | 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); | ||
| 171 | 174 | ||
| 172 | 175 | runEntryPointWithESMLoader((cascadedLoader) => { | |
| 173 | 176 | // Note that if the graph contains unsettled TLA, this may never resolve | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -406,6 +406,10 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() { | |||
| 406 | 406 | "Source Map V3 support for stack traces", | |
| 407 | 407 | &EnvironmentOptions::enable_source_maps, | |
| 408 | 408 | kAllowedInEnvvar); | |
| 409 | + AddOption("--entry-url", | ||
| 410 | + "Treat the entrypoint as a URL", | ||
| 411 | + &EnvironmentOptions::entry_is_url, | ||
| 412 | + kAllowedInEnvvar); | ||
| 409 | 413 | AddOption("--experimental-abortcontroller", "", NoOp{}, kAllowedInEnvvar); | |
| 410 | 414 | AddOption("--experimental-eventsource", | |
| 411 | 415 | "experimental EventSource API", | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -133,6 +133,7 @@ class EnvironmentOptions : public Options { | |||
| 133 | 133 | bool experimental_import_meta_resolve = false; | |
| 134 | 134 | std::string input_type; // Value of --input-type | |
| 135 | 135 | std::string type; // Value of --experimental-default-type | |
| 136 | + bool entry_is_url = false; | ||
| 136 | 137 | bool experimental_permission = false; | |
| 137 | 138 | std::vector<std::string> allow_fs_read; | |
| 138 | 139 | std::vector<std::string> allow_fs_write; | |
| Original file line number | Diff line number | Diff 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 | + }); | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1 @@ | |||
| 1 | + console.log(import.meta.url); | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments