diff --git a/lib/internal/main/eval_stdin.js b/lib/internal/main/eval_stdin.js index d97dbece8f0f56..c5fa02ed3c06e8 100644 --- a/lib/internal/main/eval_stdin.js +++ b/lib/internal/main/eval_stdin.js @@ -24,7 +24,7 @@ readStdin((code) => { const print = getOptionValue('--print'); if (getOptionValue('--input-type') === 'module') - evalModule(code, print); + evalModule(code, print, 'node:stdin'); else evalScript('[stdin]', code, diff --git a/lib/internal/main/eval_string.js b/lib/internal/main/eval_string.js index 2784204f6002e9..bd76a1d1c00008 100644 --- a/lib/internal/main/eval_string.js +++ b/lib/internal/main/eval_string.js @@ -22,7 +22,7 @@ markBootstrapComplete(); const source = getOptionValue('--eval'); const print = getOptionValue('--print'); if (getOptionValue('--input-type') === 'module') - evalModule(source, print); + evalModule(source, print, 'node:execArgv'); else evalScript('[eval]', source, diff --git a/lib/internal/modules/esm/initialize_import_meta.js b/lib/internal/modules/esm/initialize_import_meta.js index f1daabbb6425aa..90f2880cad3e10 100644 --- a/lib/internal/modules/esm/initialize_import_meta.js +++ b/lib/internal/modules/esm/initialize_import_meta.js @@ -26,15 +26,13 @@ function createImportMetaResolve(defaultParentUrl) { * @param {{url: string}} context */ function initializeImportMeta(meta, context) { - let url = context.url; + const url = asyncESM.esmLoader.getBaseURL(context.url); // Alphabetical if (experimentalImportMetaResolve) { meta.resolve = createImportMetaResolve(url); } - url = asyncESM.esmLoader.getBaseURL(url); - meta.url = url; } diff --git a/lib/internal/modules/esm/loader.js b/lib/internal/modules/esm/loader.js index 16b832527f7c64..1282b8b92c3f94 100644 --- a/lib/internal/modules/esm/loader.js +++ b/lib/internal/modules/esm/loader.js @@ -16,6 +16,7 @@ const { PromiseAll, RegExpPrototypeExec, SafeArrayIterator, + SafeMap, SafeWeakMap, StringPrototypeStartsWith, globalThis, @@ -30,7 +31,7 @@ const { ERR_INVALID_RETURN_VALUE, ERR_UNKNOWN_MODULE_FORMAT } = require('internal/errors').codes; -const { pathToFileURL, isURLInstance, URL } = require('internal/url'); +const { isURLInstance, URL } = require('internal/url'); const { isAnyArrayBuffer, isArrayBufferView, @@ -92,10 +93,6 @@ class ESMLoader { */ cjsCache = new SafeWeakMap(); - /** - * The index for assigning unique URLs to anonymous module evaluation - */ - evalIndex = 0; /** * Registry of loaded modules, akin to `require.cache` @@ -207,8 +204,10 @@ class ESMLoader { async eval( source, - url = pathToFileURL(`${process.cwd()}/[eval${++this.evalIndex}]`).href + url, + baseURL ) { + this.baseURLs.set(url, baseURL); const evalInstance = (url) => { const { ModuleWrap, callbackMap } = internalBinding('module_wrap'); const module = new ModuleWrap(url, undefined, source, 0, 0); @@ -217,6 +216,9 @@ class ESMLoader { return this.import(specifier, this.getBaseURL(url), importAssertions); + }, + initializeImportMeta: (meta, { url }) => { + this.importMetaInitialize(meta, { url }); } }); @@ -232,6 +234,7 @@ class ESMLoader { }; } + baseURLs = new SafeMap(); /** * Returns the url to use for the resolution of a given cache key url * These are not guaranteed to be the same. @@ -253,6 +256,12 @@ class ESMLoader { * @returns {string} */ getBaseURL(url) { + let baseURL = this.baseURLs.get(url); + // This will only be a string if it exists in the Map otherwise, it + // doesn't have a baseURL or needs to compute the baseURL + if (typeof baseURL === 'string') { + return baseURL; + } if ( StringPrototypeStartsWith(url, 'http:') || StringPrototypeStartsWith(url, 'https:') @@ -260,13 +269,16 @@ class ESMLoader { // The request & response have already settled, so they are in // fetchModule's cache, in which case, fetchModule returns // immediately and synchronously - url = fetchModule(new URL(url), { parentURL: url }).resolvedHREF; + baseURL = fetchModule(new URL(url), { parentURL: url }).resolvedHREF; // This should only occur if the module hasn't been fetched yet - if (typeof url !== 'string') { + if (typeof baseURL !== 'string') { throw new ERR_INTERNAL_ASSERTION(`Base url for module ${url} not loaded.`); } + this.baseURLs.set(url, baseURL); + } else { + baseURL = url; } - return url; + return baseURL; } /** diff --git a/lib/internal/process/execution.js b/lib/internal/process/execution.js index 4a8e51f694f7e6..4eb92db4c67444 100644 --- a/lib/internal/process/execution.js +++ b/lib/internal/process/execution.js @@ -23,6 +23,7 @@ const { emitAfter, popAsyncContext, } = require('internal/async_hooks'); +const { pathToFileURL } = require('internal/url'); // shouldAbortOnUncaughtToggle is a typed array for faster // communication with JS. @@ -39,13 +40,21 @@ function tryGetCwd() { } } -function evalModule(source, print) { +/** + * The index for assigning unique URLs to anonymous module evaluation + */ +let evalIndex = 0; +function evalModule(source, + print, + cacheKey = pathToFileURL(`node:eval/[eval${++evalIndex}]`), + baseURL = pathToFileURL(process.cwd() + '/').href, +) { if (print) { throw new ERR_EVAL_ESM_CANNOT_PRINT(); } const { loadESM } = require('internal/process/esm_loader'); const { handleMainPromise } = require('internal/modules/run_main'); - return handleMainPromise(loadESM((loader) => loader.eval(source))); + return handleMainPromise(loadESM((loader) => loader.eval(source, cacheKey, baseURL))); } function evalScript(name, body, breakFirstLine, print) {