Skip to content

esm: Modify getFormat and getSource loader hooks #34144

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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
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
42 changes: 39 additions & 3 deletions lib/internal/modules/esm/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,29 @@ class Loader {
return format;
}

async getSource(url, format) {
const getSourceResponse = await this._getSource(
url, { format: format }, defaultGetSource);
if (typeof getSourceResponse !== 'object') {
throw new ERR_INVALID_RETURN_VALUE(
'object', 'loader getSource', getSourceResponse);
}

const { source } = getSourceResponse;

// Validate optional format that getSource can return
({ format } = getSourceResponse);
if (typeof format !== 'string' && typeof format !== 'undefined') {
throw new ERR_INVALID_RETURN_PROPERTY_VALUE(
'string', 'loader getSource', 'format', format);
}

return {
source: source,
format: format
};
}

async eval(
source,
url = pathToFileURL(`${process.cwd()}/[eval${++this.evalIndex}]`).href
Expand Down Expand Up @@ -224,7 +247,15 @@ class Loader {

async getModuleJob(specifier, parentURL) {
const url = await this.resolve(specifier, parentURL);
const format = await this.getFormat(url);
let format = await this.getFormat(url);
let source;
if (format !== 'builtin' &&
format !== 'commonjs' &&
translators.get(format)) {
const sourceObj = await this.getSource(url, format);
({ source } = sourceObj);
format = sourceObj.format ? sourceObj.format : format;
}
let job = this.moduleMap.get(url);
// CommonJS will set functions for lazy job evaluation.
if (typeof job === 'function')
Expand All @@ -239,8 +270,13 @@ class Loader {

const inspectBrk = parentURL === undefined &&
format === 'module' && getOptionValue('--inspect-brk');
job = new ModuleJob(this, url, loaderInstance, parentURL === undefined,
inspectBrk);
job = new ModuleJob(
this,
url,
loaderInstance,
source,
parentURL === undefined,
inspectBrk);
this.moduleMap.set(url, job);
return job;
}
Expand Down
5 changes: 2 additions & 3 deletions lib/internal/modules/esm/module_job.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,15 @@ let hasPausedEntry = false;
class ModuleJob {
// `loader` is the Loader instance used for loading dependencies.
// `moduleProvider` is a function
constructor(loader, url, moduleProvider, isMain, inspectBrk) {
constructor(loader, url, moduleProvider, source, isMain, inspectBrk) {
this.loader = loader;
this.isMain = isMain;
this.inspectBrk = inspectBrk;

this.module = undefined;
// Expose the promise to the ModuleWrap directly for linking below.
// `this.module` is also filled in below.
this.modulePromise = moduleProvider.call(loader, url, isMain);

this.modulePromise = moduleProvider.call(loader, url, source, isMain);
// Wait for the ModuleWrap instance being linked with all dependencies.
const link = async () => {
this.module = await this.modulePromise;
Expand Down
16 changes: 4 additions & 12 deletions lib/internal/modules/esm/translators.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ const {
} = require('internal/modules/cjs/helpers');
const CJSModule = require('internal/modules/cjs/loader').Module;
const internalURLModule = require('internal/url');
const { defaultGetSource } = require(
'internal/modules/esm/get_source');
const { defaultTransformSource } = require(
'internal/modules/esm/transform_source');
const createDynamicModule = require(
Expand Down Expand Up @@ -110,9 +108,7 @@ function initializeImportMeta(meta, { url }) {
}

// Strategy for loading a standard JavaScript module
translators.set('module', async function moduleStrategy(url) {
let { source } = await this._getSource(
url, { format: 'module' }, defaultGetSource);
translators.set('module', async function moduleStrategy(url, source) {
assertBufferSource(source, true, 'getSource');
({ source } = await this._transformSource(
source, { url, format: 'module' }, defaultTransformSource));
Expand All @@ -130,7 +126,7 @@ translators.set('module', async function moduleStrategy(url) {
// Strategy for loading a node-style CommonJS module
const isWindows = process.platform === 'win32';
const winSepRegEx = /\//g;
translators.set('commonjs', function commonjsStrategy(url, isMain) {
translators.set('commonjs', function commonjsStrategy(url, source, isMain) {
debug(`Translating CJSModule ${url}`);
const pathname = internalURLModule.fileURLToPath(new URL(url));
const cached = this.cjsCache.get(url);
Expand Down Expand Up @@ -171,7 +167,7 @@ translators.set('builtin', async function builtinStrategy(url) {
});

// Strategy for loading a JSON file
translators.set('json', async function jsonStrategy(url) {
translators.set('json', async function jsonStrategy(url, source) {
emitExperimentalWarning('Importing JSON modules');
debug(`Translating JSONModule ${url}`);
debug(`Loading JSONModule ${url}`);
Expand All @@ -189,8 +185,6 @@ translators.set('json', async function jsonStrategy(url) {
});
}
}
let { source } = await this._getSource(
url, { format: 'json' }, defaultGetSource);
assertBufferSource(source, true, 'getSource');
({ source } = await this._transformSource(
source, { url, format: 'json' }, defaultTransformSource));
Expand Down Expand Up @@ -231,10 +225,8 @@ translators.set('json', async function jsonStrategy(url) {
});

// Strategy for loading a wasm module
translators.set('wasm', async function(url) {
translators.set('wasm', async function(url, source) {
emitExperimentalWarning('Importing Web Assembly modules');
let { source } = await this._getSource(
url, { format: 'wasm' }, defaultGetSource);
assertBufferSource(source, false, 'getSource');
({ source } = await this._transformSource(
source, { url, format: 'wasm' }, defaultTransformSource));
Expand Down
3 changes: 2 additions & 1 deletion test/message/esm_display_syntax_error_module.out
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ await async () => 0;
^^^^^

SyntaxError: Unexpected reserved word
at Loader.moduleStrategy (internal/modules/esm/translators.js:*:*)
at Loader.moduleStrategy (internal/modules/esm/translators.js:*:*)
at async link (internal/modules/esm/module_job.js:*:*)