Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork32.2k
module: make CJS load from ESM loader#47999
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Changes fromall commits
3deeccf
c1b346c
df14ab8
f5fdea1
598d789
afd882a
9958f1f
6d57350
ad7a8ed
d0e4abf
39219be
739dc9e
297a63b
32bf878
74c93d1
0a63101
a6f01a3
3b39ba3
dd2af79
f692715
850831b
c7edb23
2a5521e
507cd21
ec6d178
279e19d
454985b
2c499bc
2c5fcfb
8291086
624d933
5d9cdd0
File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading.Please reload this page.
Jump to
Uh oh!
There was an error while loading.Please reload this page.
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -10,6 +10,7 @@ const { kEmptyObject } = require('internal/util'); | ||||||||||||||||||||||||||||||||||||
const { defaultGetFormat } = require('internal/modules/esm/get_format'); | ||||||||||||||||||||||||||||||||||||
const { validateAssertions } = require('internal/modules/esm/assert'); | ||||||||||||||||||||||||||||||||||||
const { getOptionValue } = require('internal/options'); | ||||||||||||||||||||||||||||||||||||
const { readFileSync } = require('fs'); | ||||||||||||||||||||||||||||||||||||
// Do not eagerly grab .manifest, it may be in TDZ | ||||||||||||||||||||||||||||||||||||
const policy = getOptionValue('--experimental-policy') ? | ||||||||||||||||||||||||||||||||||||
@@ -69,12 +70,35 @@ async function getSource(url, context) { | ||||||||||||||||||||||||||||||||||||
return { __proto__: null, responseURL, source }; | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
function getSourceSync(url, context) { | ||||||||||||||||||||||||||||||||||||
const parsed = new URL(url); | ||||||||||||||||||||||||||||||||||||
const responseURL = url; | ||||||||||||||||||||||||||||||||||||
let source; | ||||||||||||||||||||||||||||||||||||
if (parsed.protocol === 'file:') { | ||||||||||||||||||||||||||||||||||||
source = readFileSync(parsed); | ||||||||||||||||||||||||||||||||||||
} else if (parsed.protocol === 'data:') { | ||||||||||||||||||||||||||||||||||||
JakobJingleheimer marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||||||||||||||||||||||||||||||||||||
const match = RegExpPrototypeExec(DATA_URL_PATTERN, parsed.pathname); | ||||||||||||||||||||||||||||||||||||
GeoffreyBooth marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||||||||||||||||||||||||||||||||||||
if (!match) { | ||||||||||||||||||||||||||||||||||||
throw new ERR_INVALID_URL(url); | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
const { 1: base64, 2: body } = match; | ||||||||||||||||||||||||||||||||||||
source = BufferFrom(decodeURIComponent(body), base64 ? 'base64' : 'utf8'); | ||||||||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||||||||
const supportedSchemes = ['file', 'data']; | ||||||||||||||||||||||||||||||||||||
aduh95 marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||||||||||||||||||||||||||||||||||||
throw new ERR_UNSUPPORTED_ESM_URL_SCHEME(parsed, supportedSchemes); | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
if (policy?.manifest) { | ||||||||||||||||||||||||||||||||||||
policy.manifest.assertIntegrity(parsed, source); | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
Comment on lines +90 to +92 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. Suggested change
(possibly might need another ContributorAuthor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. I copied that from | ||||||||||||||||||||||||||||||||||||
return { __proto__: null, responseURL, source }; | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||
* Node.js default load hook. | ||||||||||||||||||||||||||||||||||||
* @param {string} url | ||||||||||||||||||||||||||||||||||||
* @param {LoadContext} context | ||||||||||||||||||||||||||||||||||||
* @returns {LoadReturn} | ||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||
async function defaultLoad(url, context = kEmptyObject) { | ||||||||||||||||||||||||||||||||||||
let responseURL = url; | ||||||||||||||||||||||||||||||||||||
@@ -108,6 +132,51 @@ async function defaultLoad(url, context = kEmptyObject) { | ||||||||||||||||||||||||||||||||||||
source, | ||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||
* @typedef LoadContext | ||||||||||||||||||||||||||||||||||||
* @property {string} [format] A hint (possibly returned from `resolve`) | ||||||||||||||||||||||||||||||||||||
* @property {string | Buffer | ArrayBuffer} [source] source | ||||||||||||||||||||||||||||||||||||
* @property {Record<string, string>} [importAssertions] import attributes | ||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||
* @typedef LoadReturn | ||||||||||||||||||||||||||||||||||||
* @property {string} format format | ||||||||||||||||||||||||||||||||||||
* @property {URL['href']} responseURL The module's fully resolved URL | ||||||||||||||||||||||||||||||||||||
* @property {Buffer} source source | ||||||||||||||||||||||||||||||||||||
JakobJingleheimer marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||
* @param {URL['href']} url | ||||||||||||||||||||||||||||||||||||
* @param {LoadContext} [context] | ||||||||||||||||||||||||||||||||||||
* @returns {LoadReturn} | ||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||
function defaultLoadSync(url, context = kEmptyObject) { | ||||||||||||||||||||||||||||||||||||
let responseURL = url; | ||||||||||||||||||||||||||||||||||||
const { importAssertions } = context; | ||||||||||||||||||||||||||||||||||||
let { | ||||||||||||||||||||||||||||||||||||
format, | ||||||||||||||||||||||||||||||||||||
source, | ||||||||||||||||||||||||||||||||||||
} = context; | ||||||||||||||||||||||||||||||||||||
format ??= defaultGetFormat(new URL(url), context); | ||||||||||||||||||||||||||||||||||||
Comment on lines +156 to +162 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. Format does not / should not change, it just needs a default value, so I think it would be better to keep it a constant with a default: Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. What if There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. Ah, we have a bug in the node/lib/internal/modules/esm/hooks.js Lines 336 to 339 ind150316
Let's fix them together (we can't fix this part without creating a second bug). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. I'm pretty sure we've always accepted nullish values indifferently in the hook APIs. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. Even for enums? Why? | ||||||||||||||||||||||||||||||||||||
validateAssertions(url, format, importAssertions); | ||||||||||||||||||||||||||||||||||||
if (format === 'builtin') { | ||||||||||||||||||||||||||||||||||||
source = null; | ||||||||||||||||||||||||||||||||||||
} else if (source == null) { | ||||||||||||||||||||||||||||||||||||
({ responseURL, source } = getSourceSync(url, context)); | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
return { | ||||||||||||||||||||||||||||||||||||
__proto__: null, | ||||||||||||||||||||||||||||||||||||
format, | ||||||||||||||||||||||||||||||||||||
responseURL, | ||||||||||||||||||||||||||||||||||||
source, | ||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||
* throws an error if the protocol is not one of the protocols | ||||||||||||||||||||||||||||||||||||
@@ -160,5 +229,6 @@ function throwUnknownModuleFormat(url, format) { | ||||||||||||||||||||||||||||||||||||
module.exports = { | ||||||||||||||||||||||||||||||||||||
defaultLoad, | ||||||||||||||||||||||||||||||||||||
defaultLoadSync, | ||||||||||||||||||||||||||||||||||||
throwUnknownModuleFormat, | ||||||||||||||||||||||||||||||||||||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -10,6 +10,7 @@ const { | ||
} = primordials; | ||
const { | ||
ERR_REQUIRE_ESM, | ||
ERR_UNKNOWN_MODULE_FORMAT, | ||
} = require('internal/errors').codes; | ||
const { getOptionValue } = require('internal/options'); | ||
@@ -18,7 +19,7 @@ const { emitExperimentalWarning } = require('internal/util'); | ||
const { | ||
getDefaultConditions, | ||
} = require('internal/modules/esm/utils'); | ||
let defaultResolve, defaultLoad,defaultLoadSync,importMetaInitializer; | ||
function newResolveCache() { | ||
const { ResolveCache } = require('internal/modules/esm/module_map'); | ||
@@ -220,7 +221,12 @@ class ModuleLoader { | ||
return this.getJobFromResolveResult(resolveResult, parentURL, importAssertions); | ||
} | ||
getModuleJobSync(specifier, parentURL, importAssertions) { | ||
const resolveResult = this.resolveSync(specifier, parentURL, importAssertions); | ||
return this.getJobFromResolveResult(resolveResult, parentURL, importAssertions, true); | ||
} | ||
getJobFromResolveResult(resolveResult, parentURL, importAssertions, sync) { | ||
const { url, format } = resolveResult; | ||
const resolvedImportAssertions = resolveResult.importAssertions ?? importAssertions; | ||
let job = this.loadCache.get(url, resolvedImportAssertions.type); | ||
@@ -231,7 +237,7 @@ class ModuleLoader { | ||
} | ||
if (job === undefined) { | ||
job = this.#createModuleJob(url, resolvedImportAssertions, parentURL, format, sync); | ||
} | ||
aduh95 marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
return job; | ||
@@ -248,17 +254,8 @@ class ModuleLoader { | ||
* `resolve` hook | ||
* @returns {Promise<ModuleJob>} The (possibly pending) module job | ||
*/ | ||
#createModuleJob(url, importAssertions, parentURL, format, sync) { | ||
const callTranslator = ({ format: finalFormat, responseURL, source }, isMain) => { | ||
const translator = getTranslators().get(finalFormat); | ||
if (!translator) { | ||
@@ -267,6 +264,10 @@ class ModuleLoader { | ||
return FunctionPrototypeCall(translator, this, responseURL, source, isMain); | ||
}; | ||
const context = { format, importAssertions }; | ||
const moduleProvider = sync ? | ||
(url, isMain) => callTranslator(this.loadSync(url, context), isMain) : | ||
async (url, isMain) => callTranslator(await this.load(url, context), isMain); | ||
const inspectBrk = ( | ||
parentURL === undefined && | ||
@@ -285,6 +286,7 @@ class ModuleLoader { | ||
moduleProvider, | ||
parentURL === undefined, | ||
inspectBrk, | ||
sync, | ||
); | ||
this.loadCache.set(url, importAssertions.type, job); | ||
@@ -388,6 +390,24 @@ class ModuleLoader { | ||
return result; | ||
} | ||
loadSync(url, context) { | ||
defaultLoadSync ??= require('internal/modules/esm/load').defaultLoadSync; | ||
let result = this.#customizations ? | ||
this.#customizations.loadSync(url, context) : | ||
defaultLoadSync(url, context); | ||
let format = result?.format; | ||
if (format === 'module') { | ||
throw new ERR_REQUIRE_ESM(url, true); | ||
} | ||
if (format === 'commonjs') { | ||
format = 'require-commonjs'; | ||
aduh95 marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
result = { __proto__: result, format }; | ||
} | ||
this.validateLoadResult(url, format); | ||
return result; | ||
} | ||
validateLoadResult(url, format) { | ||
if (format == null) { | ||
require('internal/modules/esm/load').throwUnknownModuleFormat(url, format); | ||
@@ -465,6 +485,9 @@ class CustomizedModuleLoader { | ||
load(url, context) { | ||
return hooksProxy.makeAsyncRequest('load', undefined, url, context); | ||
} | ||
loadSync(url, context) { | ||
return hooksProxy.makeSyncRequest('load', undefined, url, context); | ||
} | ||
importMetaInitialize(meta, context, loader) { | ||
hooksProxy.importMetaInitialize(meta, context, loader); | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -51,17 +51,26 @@ class ModuleJob { | ||
// `loader` is the Loader instance used for loading dependencies. | ||
// `moduleProvider` is a function | ||
constructor(loader, url, importAssertions = { __proto__: null }, | ||
moduleProvider, isMain, inspectBrk, sync = false) { | ||
this.loader = loader; | ||
this.importAssertions = importAssertions; | ||
this.isMain = isMain; | ||
this.inspectBrk = inspectBrk; | ||
this.url = url; | ||
this.module = undefined; | ||
// Expose the promise to the ModuleWrap directly for linking below. | ||
// `this.module` is also filled in below. | ||
this.modulePromise = ReflectApply(moduleProvider, loader, [url, isMain]); | ||
if (sync) { | ||
this.module = this.modulePromise; | ||
this.modulePromise = PromiseResolve(this.module); | ||
} else { | ||
this.modulePromise = PromiseResolve(this.modulePromise); | ||
} | ||
// Wait for the ModuleWrap instance being linked with all dependencies. | ||
const link = async () => { | ||
this.module = await this.modulePromise; | ||
@@ -186,6 +195,20 @@ class ModuleJob { | ||
} | ||
} | ||
runSync() { | ||
assert(this.module instanceof ModuleWrap); | ||
aduh95 marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
if (this.instantiated !== undefined) { | ||
return { __proto__: null, module: this.module }; | ||
} | ||
this.module.instantiate(); | ||
this.instantiated = PromiseResolve(); | ||
const timeout = -1; | ||
JakobJingleheimer marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
const breakOnSigint = false; | ||
this.module.evaluate(timeout, breakOnSigint); | ||
GeoffreyBooth marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
return { __proto__: null, module: this.module }; | ||
} | ||
async run() { | ||
await this.instantiate(); | ||
const timeout = -1; | ||
Uh oh!
There was an error while loading.Please reload this page.