2017-11-26 17:12:09 -06:00
|
|
|
'use strict';
|
|
|
|
|
2019-04-05 11:11:26 +02:00
|
|
|
const {
|
2024-07-14 13:00:49 -07:00
|
|
|
ArrayPrototypePush,
|
2024-07-24 18:30:06 +02:00
|
|
|
FunctionPrototypeCall,
|
2019-11-22 18:04:46 +01:00
|
|
|
JSONParse,
|
2025-02-27 21:10:25 -08:00
|
|
|
ObjectAssign,
|
2024-04-21 18:53:08 +02:00
|
|
|
ObjectPrototypeHasOwnProperty,
|
2023-08-13 06:23:05 +02:00
|
|
|
ReflectApply,
|
2020-12-29 20:07:57 +01:00
|
|
|
SafeArrayIterator,
|
2019-04-05 11:11:26 +02:00
|
|
|
SafeMap,
|
2020-05-14 22:40:37 -07:00
|
|
|
SafeSet,
|
2025-02-27 21:10:25 -08:00
|
|
|
SafeWeakMap,
|
2023-09-29 09:46:32 +01:00
|
|
|
StringPrototypeIncludes,
|
2022-08-05 10:01:32 +02:00
|
|
|
StringPrototypeReplaceAll,
|
2020-11-07 10:19:54 +01:00
|
|
|
StringPrototypeSlice,
|
2020-09-30 04:24:34 -07:00
|
|
|
StringPrototypeStartsWith,
|
2021-04-26 18:03:54 +02:00
|
|
|
globalThis: { WebAssembly },
|
2019-04-05 11:11:26 +02:00
|
|
|
} = primordials;
|
|
|
|
|
2024-03-12 03:18:53 +08:00
|
|
|
const {
|
|
|
|
compileFunctionForCJSLoader,
|
|
|
|
} = internalBinding('contextify');
|
|
|
|
|
2023-11-29 10:12:05 +01:00
|
|
|
const { BuiltinModule } = require('internal/bootstrap/realm');
|
2023-08-13 06:23:05 +02:00
|
|
|
const assert = require('internal/assert');
|
2020-05-14 22:40:37 -07:00
|
|
|
const { readFileSync } = require('fs');
|
2024-11-02 09:42:29 +01:00
|
|
|
const { dirname, extname } = require('path');
|
2018-03-07 02:30:18 +08:00
|
|
|
const {
|
2024-08-22 10:48:33 +02:00
|
|
|
assertBufferSource,
|
2022-08-05 02:32:06 +08:00
|
|
|
loadBuiltinModule,
|
2024-08-22 10:48:33 +02:00
|
|
|
stringify,
|
2019-07-18 09:01:59 -05:00
|
|
|
stripBOM,
|
2024-04-13 21:41:20 +02:00
|
|
|
urlToFilename,
|
2022-12-13 22:24:28 +01:00
|
|
|
} = require('internal/modules/helpers');
|
2024-10-24 20:27:58 +02:00
|
|
|
const { stripTypeScriptModuleTypes } = require('internal/modules/typescript');
|
2020-05-14 22:40:37 -07:00
|
|
|
const {
|
2024-04-08 16:45:55 +02:00
|
|
|
kIsCachedByESMLoader,
|
|
|
|
Module: CJSModule,
|
2024-05-30 13:58:59 -03:00
|
|
|
wrapModuleLoad,
|
2024-04-12 15:39:56 +01:00
|
|
|
kModuleSource,
|
|
|
|
kModuleExport,
|
|
|
|
kModuleExportNames,
|
2024-11-02 09:42:29 +01:00
|
|
|
findLongestRegisteredExtension,
|
|
|
|
resolveForCJSWithHooks,
|
|
|
|
loadSourceForCJSWithHooks,
|
2020-05-14 22:40:37 -07:00
|
|
|
} = require('internal/modules/cjs/loader');
|
2023-08-13 06:23:05 +02:00
|
|
|
const { fileURLToPath, pathToFileURL, URL } = require('internal/url');
|
2020-03-14 07:55:44 -04:00
|
|
|
let debug = require('internal/util/debuglog').debuglog('esm', (fn) => {
|
|
|
|
debug = fn;
|
|
|
|
});
|
2024-07-15 19:58:11 +01:00
|
|
|
const { emitExperimentalWarning, kEmptyObject, setOwnProperty, isWindows } = require('internal/util');
|
2020-03-11 10:38:00 -05:00
|
|
|
const {
|
2024-12-20 11:59:08 +00:00
|
|
|
ERR_INVALID_RETURN_PROPERTY_VALUE,
|
2020-03-11 10:38:00 -05:00
|
|
|
ERR_UNKNOWN_BUILTIN_MODULE,
|
|
|
|
} = require('internal/errors').codes;
|
2019-09-29 14:15:39 -07:00
|
|
|
const { maybeCacheSourceMap } = require('internal/source_map/source_map_cache');
|
2019-10-04 13:37:27 -04:00
|
|
|
const moduleWrap = internalBinding('module_wrap');
|
|
|
|
const { ModuleWrap } = moduleWrap;
|
2024-03-12 03:18:53 +08:00
|
|
|
|
2023-11-29 10:12:05 +01:00
|
|
|
// Lazy-loading to avoid circular dependencies.
|
|
|
|
let getSourceSync;
|
|
|
|
/**
|
|
|
|
* @param {Parameters<typeof import('./load').getSourceSync>[0]} url
|
|
|
|
* @returns {ReturnType<typeof import('./load').getSourceSync>}
|
|
|
|
*/
|
|
|
|
function getSource(url) {
|
|
|
|
getSourceSync ??= require('internal/modules/esm/load').getSourceSync;
|
|
|
|
return getSourceSync(url);
|
|
|
|
}
|
|
|
|
|
2023-09-18 19:48:24 -07:00
|
|
|
/** @type {import('deps/cjs-module-lexer/lexer.js').parse} */
|
2020-10-10 04:08:58 -07:00
|
|
|
let cjsParse;
|
2023-09-18 19:48:24 -07:00
|
|
|
/**
|
2024-09-17 20:38:33 +02:00
|
|
|
* Initializes the CommonJS module lexer parser using the JavaScript version.
|
|
|
|
* TODO(joyeecheung): Use `require('internal/deps/cjs-module-lexer/dist/lexer').initSync()`
|
|
|
|
* when cjs-module-lexer 1.4.0 is rolled in.
|
2023-09-18 19:48:24 -07:00
|
|
|
*/
|
module: support require()ing synchronous ESM graphs
This patch adds `require()` support for synchronous ESM graphs under
the flag `--experimental-require-module`
This is based on the the following design aspect of ESM:
- The resolution can be synchronous (up to the host)
- The evaluation of a synchronous graph (without top-level await) is
also synchronous, and, by the time the module graph is instantiated
(before evaluation starts), this is is already known.
If `--experimental-require-module` is enabled, and the ECMAScript
module being loaded by `require()` meets the following requirements:
- Explicitly marked as an ES module with a `"type": "module"` field in
the closest package.json or a `.mjs` extension.
- Fully synchronous (contains no top-level `await`).
`require()` will load the requested module as an ES Module, and return
the module name space object. In this case it is similar to dynamic
`import()` but is run synchronously and returns the name space object
directly.
```mjs
// point.mjs
export function distance(a, b) {
return (b.x - a.x) ** 2 + (b.y - a.y) ** 2;
}
class Point {
constructor(x, y) { this.x = x; this.y = y; }
}
export default Point;
```
```cjs
const required = require('./point.mjs');
// [Module: null prototype] {
// default: [class Point],
// distance: [Function: distance]
// }
console.log(required);
(async () => {
const imported = await import('./point.mjs');
console.log(imported === required); // true
})();
```
If the module being `require()`'d contains top-level `await`, or the
module graph it `import`s contains top-level `await`,
[`ERR_REQUIRE_ASYNC_MODULE`][] will be thrown. In this case, users
should load the asynchronous module using `import()`.
If `--experimental-print-required-tla` is enabled, instead of throwing
`ERR_REQUIRE_ASYNC_MODULE` before evaluation, Node.js will evaluate the
module, try to locate the top-level awaits, and print their location to
help users fix them.
PR-URL: https://github.com/nodejs/node/pull/51977
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Guy Bedford <guybedford@gmail.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com>
2024-03-12 01:50:24 +08:00
|
|
|
function initCJSParseSync() {
|
|
|
|
if (cjsParse === undefined) {
|
|
|
|
cjsParse = require('internal/deps/cjs-module-lexer/lexer').parse;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-26 17:12:09 -06:00
|
|
|
const translators = new SafeMap();
|
2018-08-28 17:28:46 +02:00
|
|
|
exports.translators = translators;
|
2017-11-26 17:12:09 -06:00
|
|
|
|
2023-09-18 19:48:24 -07:00
|
|
|
/**
|
|
|
|
* Converts a URL to a file path if the URL protocol is 'file:'.
|
|
|
|
* @param {string} url - The URL to convert.
|
|
|
|
*/
|
2019-07-09 16:03:07 -05:00
|
|
|
function errPath(url) {
|
|
|
|
const parsed = new URL(url);
|
|
|
|
if (parsed.protocol === 'file:') {
|
|
|
|
return fileURLToPath(parsed);
|
|
|
|
}
|
|
|
|
return url;
|
|
|
|
}
|
|
|
|
|
2020-05-14 22:40:37 -07:00
|
|
|
// Strategy for loading a standard JavaScript module.
|
module: support require()ing synchronous ESM graphs
This patch adds `require()` support for synchronous ESM graphs under
the flag `--experimental-require-module`
This is based on the the following design aspect of ESM:
- The resolution can be synchronous (up to the host)
- The evaluation of a synchronous graph (without top-level await) is
also synchronous, and, by the time the module graph is instantiated
(before evaluation starts), this is is already known.
If `--experimental-require-module` is enabled, and the ECMAScript
module being loaded by `require()` meets the following requirements:
- Explicitly marked as an ES module with a `"type": "module"` field in
the closest package.json or a `.mjs` extension.
- Fully synchronous (contains no top-level `await`).
`require()` will load the requested module as an ES Module, and return
the module name space object. In this case it is similar to dynamic
`import()` but is run synchronously and returns the name space object
directly.
```mjs
// point.mjs
export function distance(a, b) {
return (b.x - a.x) ** 2 + (b.y - a.y) ** 2;
}
class Point {
constructor(x, y) { this.x = x; this.y = y; }
}
export default Point;
```
```cjs
const required = require('./point.mjs');
// [Module: null prototype] {
// default: [class Point],
// distance: [Function: distance]
// }
console.log(required);
(async () => {
const imported = await import('./point.mjs');
console.log(imported === required); // true
})();
```
If the module being `require()`'d contains top-level `await`, or the
module graph it `import`s contains top-level `await`,
[`ERR_REQUIRE_ASYNC_MODULE`][] will be thrown. In this case, users
should load the asynchronous module using `import()`.
If `--experimental-print-required-tla` is enabled, instead of throwing
`ERR_REQUIRE_ASYNC_MODULE` before evaluation, Node.js will evaluate the
module, try to locate the top-level awaits, and print their location to
help users fix them.
PR-URL: https://github.com/nodejs/node/pull/51977
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Guy Bedford <guybedford@gmail.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com>
2024-03-12 01:50:24 +08:00
|
|
|
translators.set('module', function moduleStrategy(url, source, isMain) {
|
2021-08-25 22:55:14 +02:00
|
|
|
assertBufferSource(source, true, 'load');
|
2020-03-11 10:38:00 -05:00
|
|
|
source = stringify(source);
|
2017-11-26 17:12:09 -06:00
|
|
|
debug(`Translating StandardModule ${url}`);
|
2024-04-04 00:31:48 +01:00
|
|
|
const { compileSourceTextModule } = require('internal/modules/esm/utils');
|
2025-05-26 23:31:54 +01:00
|
|
|
const context = isMain ? { isMain } : undefined;
|
|
|
|
const module = compileSourceTextModule(url, source, this, context);
|
2019-10-04 13:37:27 -04:00
|
|
|
return module;
|
2017-11-26 17:12:09 -06:00
|
|
|
});
|
|
|
|
|
2023-08-13 06:23:05 +02:00
|
|
|
/**
|
|
|
|
* Loads a CommonJS module via the ESM Loader sync CommonJS translator.
|
|
|
|
* This translator creates its own version of the `require` function passed into CommonJS modules.
|
|
|
|
* Any monkey patches applied to the CommonJS Loader will not affect this module.
|
|
|
|
* Any `require` calls in this module will load all children in the same way.
|
2023-09-18 19:48:24 -07:00
|
|
|
* @param {import('internal/modules/cjs/loader').Module} module - The module to load.
|
|
|
|
* @param {string} source - The source code of the module.
|
|
|
|
* @param {string} url - The URL of the module.
|
|
|
|
* @param {string} filename - The filename of the module.
|
2024-04-29 22:21:53 +02:00
|
|
|
* @param {boolean} isMain - Whether the module is the entrypoint
|
2023-08-13 06:23:05 +02:00
|
|
|
*/
|
2024-04-29 22:21:53 +02:00
|
|
|
function loadCJSModule(module, source, url, filename, isMain) {
|
2024-07-05 21:58:35 +02:00
|
|
|
const compileResult = compileFunctionForCJSLoader(source, filename, false /* is_sea_main */, false);
|
2024-04-29 22:21:53 +02:00
|
|
|
|
2025-05-30 11:47:20 +02:00
|
|
|
const { function: compiledWrapper, sourceMapURL, sourceURL } = compileResult;
|
2024-02-06 23:44:59 +08:00
|
|
|
// Cache the source map for the cjs module if present.
|
2024-05-28 23:56:56 +01:00
|
|
|
if (sourceMapURL) {
|
2025-05-30 11:47:20 +02:00
|
|
|
maybeCacheSourceMap(url, source, module, false, sourceURL, sourceMapURL);
|
2024-02-06 23:44:59 +08:00
|
|
|
}
|
|
|
|
|
2024-03-02 03:23:22 +01:00
|
|
|
const cascadedLoader = require('internal/modules/esm/loader').getOrInitializeCascadedLoader();
|
2023-08-13 06:23:05 +02:00
|
|
|
const __dirname = dirname(filename);
|
|
|
|
// eslint-disable-next-line func-name-matching,func-style
|
|
|
|
const requireFn = function require(specifier) {
|
2023-10-14 05:52:38 +02:00
|
|
|
let importAttributes = kEmptyObject;
|
2023-11-29 10:12:05 +01:00
|
|
|
if (!StringPrototypeStartsWith(specifier, 'node:') && !BuiltinModule.normalizeRequirableId(specifier)) {
|
2023-08-13 06:23:05 +02:00
|
|
|
// TODO: do not depend on the monkey-patchable CJS loader here.
|
|
|
|
const path = CJSModule._resolveFilename(specifier, module);
|
2023-11-29 10:12:05 +01:00
|
|
|
switch (extname(path)) {
|
|
|
|
case '.json':
|
|
|
|
importAttributes = { __proto__: null, type: 'json' };
|
|
|
|
break;
|
|
|
|
case '.node':
|
2024-05-30 13:58:59 -03:00
|
|
|
return wrapModuleLoad(specifier, module);
|
2023-11-29 10:12:05 +01:00
|
|
|
default:
|
2023-08-13 06:23:05 +02:00
|
|
|
// fall through
|
|
|
|
}
|
2023-11-29 10:12:05 +01:00
|
|
|
specifier = `${pathToFileURL(path)}`;
|
2023-08-13 06:23:05 +02:00
|
|
|
}
|
2024-09-17 20:38:33 +02:00
|
|
|
const job = cascadedLoader.getModuleJobForRequireInImportedCJS(specifier, url, importAttributes);
|
2023-08-13 06:23:05 +02:00
|
|
|
job.runSync();
|
|
|
|
return cjsCache.get(job.url).exports;
|
|
|
|
};
|
|
|
|
setOwnProperty(requireFn, 'resolve', function resolve(specifier) {
|
|
|
|
if (!StringPrototypeStartsWith(specifier, 'node:')) {
|
|
|
|
const path = CJSModule._resolveFilename(specifier, module);
|
|
|
|
if (specifier !== path) {
|
|
|
|
specifier = `${pathToFileURL(path)}`;
|
|
|
|
}
|
|
|
|
}
|
2024-03-02 03:23:22 +01:00
|
|
|
const { url: resolvedURL } = cascadedLoader.resolveSync(specifier, url, kEmptyObject);
|
2024-04-13 21:41:20 +02:00
|
|
|
return urlToFilename(resolvedURL);
|
2023-08-13 06:23:05 +02:00
|
|
|
});
|
|
|
|
setOwnProperty(requireFn, 'main', process.mainModule);
|
|
|
|
|
|
|
|
ReflectApply(compiledWrapper, module.exports,
|
|
|
|
[module.exports, requireFn, module, filename, __dirname]);
|
|
|
|
setOwnProperty(module, 'loaded', true);
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: can we use a weak map instead?
|
|
|
|
const cjsCache = new SafeMap();
|
2023-09-18 19:48:24 -07:00
|
|
|
/**
|
|
|
|
* Creates a ModuleWrap object for a CommonJS module.
|
|
|
|
* @param {string} url - The URL of the module.
|
|
|
|
* @param {string} source - The source code of the module.
|
|
|
|
* @param {boolean} isMain - Whether the module is the main module.
|
2024-11-02 09:42:29 +01:00
|
|
|
* @param {string} format - Format of the module.
|
2023-09-18 19:48:24 -07:00
|
|
|
* @param {typeof loadCJSModule} [loadCJS=loadCJSModule] - The function to load the CommonJS module.
|
|
|
|
* @returns {ModuleWrap} The ModuleWrap object for the CommonJS module.
|
|
|
|
*/
|
2024-11-02 09:42:29 +01:00
|
|
|
function createCJSModuleWrap(url, source, isMain, format, loadCJS = loadCJSModule) {
|
2017-11-26 17:12:09 -06:00
|
|
|
debug(`Translating CJSModule ${url}`);
|
2020-05-14 22:40:37 -07:00
|
|
|
|
2024-04-13 21:41:20 +02:00
|
|
|
const filename = urlToFilename(url);
|
2023-11-29 10:12:05 +01:00
|
|
|
// In case the source was not provided by the `load` step, we need fetch it now.
|
|
|
|
source = stringify(source ?? getSource(new URL(url)).source);
|
2020-05-14 22:40:37 -07:00
|
|
|
|
2024-12-20 11:59:08 +00:00
|
|
|
const { exportNames, module } = cjsPreparseModuleExports(filename, source, format);
|
2023-08-13 06:23:05 +02:00
|
|
|
cjsCache.set(url, module);
|
2024-07-14 13:00:49 -07:00
|
|
|
|
2025-03-07 13:05:09 -08:00
|
|
|
const wrapperNames = [...exportNames];
|
2024-07-14 13:00:49 -07:00
|
|
|
if (!exportNames.has('default')) {
|
|
|
|
ArrayPrototypePush(wrapperNames, 'default');
|
|
|
|
}
|
2025-03-07 13:05:09 -08:00
|
|
|
if (!exportNames.has('module.exports')) {
|
|
|
|
ArrayPrototypePush(wrapperNames, 'module.exports');
|
|
|
|
}
|
2020-05-14 22:40:37 -07:00
|
|
|
|
2023-08-13 06:23:05 +02:00
|
|
|
if (isMain) {
|
|
|
|
setOwnProperty(process, 'mainModule', module);
|
|
|
|
}
|
|
|
|
|
2024-07-14 13:00:49 -07:00
|
|
|
return new ModuleWrap(url, undefined, wrapperNames, function() {
|
2017-11-26 17:12:09 -06:00
|
|
|
debug(`Loading CJSModule ${url}`);
|
2020-05-14 22:40:37 -07:00
|
|
|
|
2023-08-13 06:23:05 +02:00
|
|
|
if (!module.loaded) {
|
2024-04-29 22:21:53 +02:00
|
|
|
loadCJS(module, source, url, filename, !!isMain);
|
2023-08-13 06:23:05 +02:00
|
|
|
}
|
|
|
|
|
2020-08-02 18:03:48 -07:00
|
|
|
let exports;
|
2024-04-12 15:39:56 +01:00
|
|
|
if (module[kModuleExport] !== undefined) {
|
|
|
|
exports = module[kModuleExport];
|
|
|
|
module[kModuleExport] = undefined;
|
2020-08-02 18:03:48 -07:00
|
|
|
} else {
|
2023-08-13 06:23:05 +02:00
|
|
|
({ exports } = module);
|
2020-05-14 22:40:37 -07:00
|
|
|
}
|
|
|
|
for (const exportName of exportNames) {
|
2025-03-07 13:05:09 -08:00
|
|
|
if (exportName === 'default' || exportName === 'module.exports' ||
|
|
|
|
!ObjectPrototypeHasOwnProperty(exports, exportName)) {
|
2020-05-14 22:40:37 -07:00
|
|
|
continue;
|
2023-09-15 12:18:13 -07:00
|
|
|
}
|
2020-05-14 22:40:37 -07:00
|
|
|
// We might trigger a getter -> dont fail.
|
|
|
|
let value;
|
|
|
|
try {
|
|
|
|
value = exports[exportName];
|
2022-02-02 21:57:11 -08:00
|
|
|
} catch {
|
|
|
|
// Continue regardless of error.
|
|
|
|
}
|
2020-05-14 22:40:37 -07:00
|
|
|
this.setExport(exportName, value);
|
2020-08-02 18:03:48 -07:00
|
|
|
}
|
|
|
|
this.setExport('default', exports);
|
2024-07-14 13:00:49 -07:00
|
|
|
this.setExport('module.exports', exports);
|
2024-04-08 16:45:55 +02:00
|
|
|
}, module);
|
2023-08-13 06:23:05 +02:00
|
|
|
}
|
|
|
|
|
2024-12-20 11:59:08 +00:00
|
|
|
/**
|
|
|
|
* Creates a ModuleWrap object for a CommonJS module without source texts.
|
|
|
|
* @param {string} url - The URL of the module.
|
|
|
|
* @param {boolean} isMain - Whether the module is the main module.
|
|
|
|
* @returns {ModuleWrap} The ModuleWrap object for the CommonJS module.
|
|
|
|
*/
|
|
|
|
function createCJSNoSourceModuleWrap(url, isMain) {
|
|
|
|
debug(`Translating CJSModule without source ${url}`);
|
|
|
|
|
|
|
|
const filename = urlToFilename(url);
|
|
|
|
|
|
|
|
const module = cjsEmplaceModuleCacheEntry(filename);
|
|
|
|
cjsCache.set(url, module);
|
|
|
|
|
|
|
|
if (isMain) {
|
|
|
|
setOwnProperty(process, 'mainModule', module);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Addon export names are not known until the addon is loaded.
|
|
|
|
const exportNames = ['default', 'module.exports'];
|
|
|
|
return new ModuleWrap(url, undefined, exportNames, function evaluationCallback() {
|
|
|
|
debug(`Loading CJSModule ${url}`);
|
|
|
|
|
|
|
|
if (!module.loaded) {
|
|
|
|
wrapModuleLoad(filename, null, isMain);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @type {import('./loader').ModuleExports} */
|
|
|
|
let exports;
|
|
|
|
if (module[kModuleExport] !== undefined) {
|
|
|
|
exports = module[kModuleExport];
|
|
|
|
module[kModuleExport] = undefined;
|
|
|
|
} else {
|
|
|
|
({ exports } = module);
|
|
|
|
}
|
|
|
|
|
|
|
|
this.setExport('default', exports);
|
|
|
|
this.setExport('module.exports', exports);
|
|
|
|
}, module);
|
|
|
|
}
|
|
|
|
|
module: support require()ing synchronous ESM graphs
This patch adds `require()` support for synchronous ESM graphs under
the flag `--experimental-require-module`
This is based on the the following design aspect of ESM:
- The resolution can be synchronous (up to the host)
- The evaluation of a synchronous graph (without top-level await) is
also synchronous, and, by the time the module graph is instantiated
(before evaluation starts), this is is already known.
If `--experimental-require-module` is enabled, and the ECMAScript
module being loaded by `require()` meets the following requirements:
- Explicitly marked as an ES module with a `"type": "module"` field in
the closest package.json or a `.mjs` extension.
- Fully synchronous (contains no top-level `await`).
`require()` will load the requested module as an ES Module, and return
the module name space object. In this case it is similar to dynamic
`import()` but is run synchronously and returns the name space object
directly.
```mjs
// point.mjs
export function distance(a, b) {
return (b.x - a.x) ** 2 + (b.y - a.y) ** 2;
}
class Point {
constructor(x, y) { this.x = x; this.y = y; }
}
export default Point;
```
```cjs
const required = require('./point.mjs');
// [Module: null prototype] {
// default: [class Point],
// distance: [Function: distance]
// }
console.log(required);
(async () => {
const imported = await import('./point.mjs');
console.log(imported === required); // true
})();
```
If the module being `require()`'d contains top-level `await`, or the
module graph it `import`s contains top-level `await`,
[`ERR_REQUIRE_ASYNC_MODULE`][] will be thrown. In this case, users
should load the asynchronous module using `import()`.
If `--experimental-print-required-tla` is enabled, instead of throwing
`ERR_REQUIRE_ASYNC_MODULE` before evaluation, Node.js will evaluate the
module, try to locate the top-level awaits, and print their location to
help users fix them.
PR-URL: https://github.com/nodejs/node/pull/51977
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Guy Bedford <guybedford@gmail.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com>
2024-03-12 01:50:24 +08:00
|
|
|
translators.set('commonjs-sync', function requireCommonJS(url, source, isMain) {
|
|
|
|
initCJSParseSync();
|
|
|
|
|
2024-11-02 09:42:29 +01:00
|
|
|
return createCJSModuleWrap(url, source, isMain, 'commonjs', (module, source, url, filename, isMain) => {
|
module: support require()ing synchronous ESM graphs
This patch adds `require()` support for synchronous ESM graphs under
the flag `--experimental-require-module`
This is based on the the following design aspect of ESM:
- The resolution can be synchronous (up to the host)
- The evaluation of a synchronous graph (without top-level await) is
also synchronous, and, by the time the module graph is instantiated
(before evaluation starts), this is is already known.
If `--experimental-require-module` is enabled, and the ECMAScript
module being loaded by `require()` meets the following requirements:
- Explicitly marked as an ES module with a `"type": "module"` field in
the closest package.json or a `.mjs` extension.
- Fully synchronous (contains no top-level `await`).
`require()` will load the requested module as an ES Module, and return
the module name space object. In this case it is similar to dynamic
`import()` but is run synchronously and returns the name space object
directly.
```mjs
// point.mjs
export function distance(a, b) {
return (b.x - a.x) ** 2 + (b.y - a.y) ** 2;
}
class Point {
constructor(x, y) { this.x = x; this.y = y; }
}
export default Point;
```
```cjs
const required = require('./point.mjs');
// [Module: null prototype] {
// default: [class Point],
// distance: [Function: distance]
// }
console.log(required);
(async () => {
const imported = await import('./point.mjs');
console.log(imported === required); // true
})();
```
If the module being `require()`'d contains top-level `await`, or the
module graph it `import`s contains top-level `await`,
[`ERR_REQUIRE_ASYNC_MODULE`][] will be thrown. In this case, users
should load the asynchronous module using `import()`.
If `--experimental-print-required-tla` is enabled, instead of throwing
`ERR_REQUIRE_ASYNC_MODULE` before evaluation, Node.js will evaluate the
module, try to locate the top-level awaits, and print their location to
help users fix them.
PR-URL: https://github.com/nodejs/node/pull/51977
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Guy Bedford <guybedford@gmail.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com>
2024-03-12 01:50:24 +08:00
|
|
|
assert(module === CJSModule._cache[filename]);
|
2024-05-30 13:58:59 -03:00
|
|
|
wrapModuleLoad(filename, null, isMain);
|
module: support require()ing synchronous ESM graphs
This patch adds `require()` support for synchronous ESM graphs under
the flag `--experimental-require-module`
This is based on the the following design aspect of ESM:
- The resolution can be synchronous (up to the host)
- The evaluation of a synchronous graph (without top-level await) is
also synchronous, and, by the time the module graph is instantiated
(before evaluation starts), this is is already known.
If `--experimental-require-module` is enabled, and the ECMAScript
module being loaded by `require()` meets the following requirements:
- Explicitly marked as an ES module with a `"type": "module"` field in
the closest package.json or a `.mjs` extension.
- Fully synchronous (contains no top-level `await`).
`require()` will load the requested module as an ES Module, and return
the module name space object. In this case it is similar to dynamic
`import()` but is run synchronously and returns the name space object
directly.
```mjs
// point.mjs
export function distance(a, b) {
return (b.x - a.x) ** 2 + (b.y - a.y) ** 2;
}
class Point {
constructor(x, y) { this.x = x; this.y = y; }
}
export default Point;
```
```cjs
const required = require('./point.mjs');
// [Module: null prototype] {
// default: [class Point],
// distance: [Function: distance]
// }
console.log(required);
(async () => {
const imported = await import('./point.mjs');
console.log(imported === required); // true
})();
```
If the module being `require()`'d contains top-level `await`, or the
module graph it `import`s contains top-level `await`,
[`ERR_REQUIRE_ASYNC_MODULE`][] will be thrown. In this case, users
should load the asynchronous module using `import()`.
If `--experimental-print-required-tla` is enabled, instead of throwing
`ERR_REQUIRE_ASYNC_MODULE` before evaluation, Node.js will evaluate the
module, try to locate the top-level awaits, and print their location to
help users fix them.
PR-URL: https://github.com/nodejs/node/pull/51977
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Guy Bedford <guybedford@gmail.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com>
2024-03-12 01:50:24 +08:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2023-08-13 06:23:05 +02:00
|
|
|
// Handle CommonJS modules referenced by `require` calls.
|
|
|
|
// This translator function must be sync, as `require` is sync.
|
|
|
|
translators.set('require-commonjs', (url, source, isMain) => {
|
2024-09-17 20:38:33 +02:00
|
|
|
initCJSParseSync();
|
2023-08-13 06:23:05 +02:00
|
|
|
assert(cjsParse);
|
|
|
|
|
2024-11-02 09:42:29 +01:00
|
|
|
return createCJSModuleWrap(url, source, isMain, 'commonjs');
|
2017-11-26 17:12:09 -06:00
|
|
|
});
|
|
|
|
|
2024-07-24 18:30:06 +02:00
|
|
|
// Handle CommonJS modules referenced by `require` calls.
|
|
|
|
// This translator function must be sync, as `require` is sync.
|
|
|
|
translators.set('require-commonjs-typescript', (url, source, isMain) => {
|
|
|
|
assert(cjsParse);
|
2024-10-24 20:27:58 +02:00
|
|
|
const code = stripTypeScriptModuleTypes(stringify(source), url);
|
2024-11-02 09:42:29 +01:00
|
|
|
return createCJSModuleWrap(url, code, isMain, 'commonjs-typescript');
|
2024-07-24 18:30:06 +02:00
|
|
|
});
|
|
|
|
|
2023-08-13 06:23:05 +02:00
|
|
|
// Handle CommonJS modules referenced by `import` statements or expressions,
|
|
|
|
// or as the initial entry point when the ESM loader handles a CommonJS entry.
|
2024-09-17 20:38:33 +02:00
|
|
|
translators.set('commonjs', function commonjsStrategy(url, source, isMain) {
|
2023-08-13 06:23:05 +02:00
|
|
|
if (!cjsParse) {
|
2024-09-17 20:38:33 +02:00
|
|
|
initCJSParseSync();
|
2023-08-13 06:23:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// For backward-compatibility, it's possible to return a nullish value for
|
|
|
|
// CJS source associated with a file: URL. In this case, the source is
|
|
|
|
// obtained by calling the monkey-patchable CJS loader.
|
2024-04-29 22:21:53 +02:00
|
|
|
const cjsLoader = source == null ? (module, source, url, filename, isMain) => {
|
|
|
|
assert(module === CJSModule._cache[filename]);
|
2024-05-30 13:58:59 -03:00
|
|
|
wrapModuleLoad(filename, undefined, isMain);
|
2023-08-13 06:23:05 +02:00
|
|
|
} : loadCJSModule;
|
|
|
|
|
|
|
|
try {
|
|
|
|
// We still need to read the FS to detect the exports.
|
|
|
|
source ??= readFileSync(new URL(url), 'utf8');
|
|
|
|
} catch {
|
|
|
|
// Continue regardless of error.
|
|
|
|
}
|
2024-11-02 09:42:29 +01:00
|
|
|
return createCJSModuleWrap(url, source, isMain, 'commonjs', cjsLoader);
|
2023-08-13 06:23:05 +02:00
|
|
|
});
|
|
|
|
|
2024-12-20 11:59:08 +00:00
|
|
|
/**
|
|
|
|
* Get or create an entry in the CJS module cache for the given filename.
|
|
|
|
* @param {string} filename CJS module filename
|
|
|
|
* @returns {CJSModule} the cached CJS module entry
|
|
|
|
*/
|
|
|
|
function cjsEmplaceModuleCacheEntry(filename, exportNames) {
|
|
|
|
// TODO: Do we want to keep hitting the user mutable CJS loader here?
|
|
|
|
let cjsMod = CJSModule._cache[filename];
|
|
|
|
if (cjsMod) {
|
|
|
|
return cjsMod;
|
|
|
|
}
|
|
|
|
|
|
|
|
cjsMod = new CJSModule(filename);
|
|
|
|
cjsMod.filename = filename;
|
|
|
|
cjsMod.paths = CJSModule._nodeModulePaths(cjsMod.path);
|
|
|
|
cjsMod[kIsCachedByESMLoader] = true;
|
|
|
|
CJSModule._cache[filename] = cjsMod;
|
|
|
|
|
|
|
|
return cjsMod;
|
|
|
|
}
|
|
|
|
|
2023-09-18 19:48:24 -07:00
|
|
|
/**
|
|
|
|
* Pre-parses a CommonJS module's exports and re-exports.
|
|
|
|
* @param {string} filename - The filename of the module.
|
|
|
|
* @param {string} [source] - The source code of the module.
|
2024-12-20 11:59:08 +00:00
|
|
|
* @param {string} [format]
|
2023-09-18 19:48:24 -07:00
|
|
|
*/
|
2024-12-20 11:59:08 +00:00
|
|
|
function cjsPreparseModuleExports(filename, source, format) {
|
|
|
|
const module = cjsEmplaceModuleCacheEntry(filename);
|
|
|
|
if (module[kModuleExportNames] !== undefined) {
|
2024-04-12 15:39:56 +01:00
|
|
|
return { module, exportNames: module[kModuleExportNames] };
|
2020-05-14 22:40:37 -07:00
|
|
|
}
|
|
|
|
|
2024-11-02 09:42:29 +01:00
|
|
|
if (source === undefined) {
|
|
|
|
({ source } = loadSourceForCJSWithHooks(module, filename, format));
|
|
|
|
}
|
|
|
|
module[kModuleSource] = source;
|
|
|
|
|
|
|
|
debug(`Preparsing exports of ${filename}`);
|
2020-09-30 04:24:34 -07:00
|
|
|
let exports, reexports;
|
|
|
|
try {
|
|
|
|
({ exports, reexports } = cjsParse(source || ''));
|
|
|
|
} catch {
|
|
|
|
exports = [];
|
|
|
|
reexports = [];
|
|
|
|
}
|
2020-05-14 22:40:37 -07:00
|
|
|
|
2020-12-29 20:07:57 +01:00
|
|
|
const exportNames = new SafeSet(new SafeArrayIterator(exports));
|
2020-05-14 22:40:37 -07:00
|
|
|
|
|
|
|
// Set first for cycles.
|
2024-04-12 15:39:56 +01:00
|
|
|
module[kModuleExportNames] = exportNames;
|
2020-05-14 22:40:37 -07:00
|
|
|
|
2024-11-02 09:42:29 +01:00
|
|
|
// If there are any re-exports e.g. `module.exports = { ...require(...) }`,
|
|
|
|
// pre-parse the dependencies to find transitively exported names.
|
2020-05-14 22:40:37 -07:00
|
|
|
if (reexports.length) {
|
2024-11-02 09:42:29 +01:00
|
|
|
module.filename ??= filename;
|
|
|
|
module.paths ??= CJSModule._nodeModulePaths(dirname(filename));
|
|
|
|
|
2023-08-13 06:23:05 +02:00
|
|
|
for (let i = 0; i < reexports.length; i++) {
|
2024-11-02 09:42:29 +01:00
|
|
|
debug(`Preparsing re-exports of '${filename}'`);
|
2023-08-13 06:23:05 +02:00
|
|
|
const reexport = reexports[i];
|
|
|
|
let resolved;
|
2024-11-02 09:42:29 +01:00
|
|
|
let format;
|
2023-08-13 06:23:05 +02:00
|
|
|
try {
|
2024-11-02 09:42:29 +01:00
|
|
|
({ format, filename: resolved } = resolveForCJSWithHooks(reexport, module, false));
|
|
|
|
} catch (e) {
|
|
|
|
debug(`Failed to resolve '${reexport}', skipping`, e);
|
2023-08-13 06:23:05 +02:00
|
|
|
continue;
|
|
|
|
}
|
2024-11-02 09:42:29 +01:00
|
|
|
|
|
|
|
if (format === 'commonjs' ||
|
|
|
|
(!BuiltinModule.normalizeRequirableId(resolved) && findLongestRegisteredExtension(resolved) === '.js')) {
|
2024-12-20 11:59:08 +00:00
|
|
|
const { exportNames: reexportNames } = cjsPreparseModuleExports(resolved, undefined, format);
|
2023-09-15 12:18:13 -07:00
|
|
|
for (const name of reexportNames) {
|
2023-08-13 06:23:05 +02:00
|
|
|
exportNames.add(name);
|
2023-09-15 12:18:13 -07:00
|
|
|
}
|
2023-08-13 06:23:05 +02:00
|
|
|
}
|
2020-05-14 22:40:37 -07:00
|
|
|
}
|
2023-08-13 06:23:05 +02:00
|
|
|
}
|
2020-05-14 22:40:37 -07:00
|
|
|
|
|
|
|
return { module, exportNames };
|
|
|
|
}
|
|
|
|
|
2017-11-26 17:12:09 -06:00
|
|
|
// Strategy for loading a node builtin CommonJS module that isn't
|
|
|
|
// through normal resolution
|
2023-08-13 06:23:05 +02:00
|
|
|
translators.set('builtin', function builtinStrategy(url) {
|
2017-11-26 17:12:09 -06:00
|
|
|
debug(`Translating BuiltinModule ${url}`);
|
2020-09-27 21:24:44 -07:00
|
|
|
// Slice 'node:' scheme
|
2020-11-07 10:19:54 +01:00
|
|
|
const id = StringPrototypeSlice(url, 5);
|
2022-08-05 02:32:06 +08:00
|
|
|
const module = loadBuiltinModule(id, url);
|
2023-08-13 06:23:05 +02:00
|
|
|
cjsCache.set(url, module);
|
2020-11-07 10:19:54 +01:00
|
|
|
if (!StringPrototypeStartsWith(url, 'node:') || !module) {
|
2020-09-27 21:24:44 -07:00
|
|
|
throw new ERR_UNKNOWN_BUILTIN_MODULE(url);
|
2019-03-09 18:12:05 +01:00
|
|
|
}
|
2019-09-27 12:12:18 -05:00
|
|
|
debug(`Loading BuiltinModule ${url}`);
|
|
|
|
return module.getESMFacade();
|
2017-11-26 17:12:09 -06:00
|
|
|
});
|
|
|
|
|
2018-02-12 13:02:42 +02:00
|
|
|
// Strategy for loading a JSON file
|
2023-08-13 06:23:05 +02:00
|
|
|
translators.set('json', function jsonStrategy(url, source) {
|
2021-08-25 22:55:14 +02:00
|
|
|
assertBufferSource(source, true, 'load');
|
2018-08-28 17:28:46 +02:00
|
|
|
debug(`Loading JSONModule ${url}`);
|
2020-11-07 10:19:54 +01:00
|
|
|
const pathname = StringPrototypeStartsWith(url, 'file:') ?
|
|
|
|
fileURLToPath(url) : null;
|
2023-09-29 09:46:32 +01:00
|
|
|
const shouldCheckAndPopulateCJSModuleCache =
|
|
|
|
// We want to involve the CJS loader cache only for `file:` URL with no search query and no hash.
|
|
|
|
pathname && !StringPrototypeIncludes(url, '?') && !StringPrototypeIncludes(url, '#');
|
2019-07-09 16:03:07 -05:00
|
|
|
let modulePath;
|
|
|
|
let module;
|
2023-09-29 09:46:32 +01:00
|
|
|
if (shouldCheckAndPopulateCJSModuleCache) {
|
2019-07-09 16:03:07 -05:00
|
|
|
modulePath = isWindows ?
|
2022-08-05 10:01:32 +02:00
|
|
|
StringPrototypeReplaceAll(pathname, '/', '\\') : pathname;
|
2019-07-09 16:03:07 -05:00
|
|
|
module = CJSModule._cache[modulePath];
|
2024-09-24 15:48:15 -04:00
|
|
|
if (module?.loaded) {
|
2019-07-09 16:03:07 -05:00
|
|
|
const exports = module.exports;
|
2019-10-04 20:08:00 -07:00
|
|
|
return new ModuleWrap(url, undefined, ['default'], function() {
|
2019-10-04 13:37:27 -04:00
|
|
|
this.setExport('default', exports);
|
2019-10-04 20:08:00 -07:00
|
|
|
});
|
2019-07-09 16:03:07 -05:00
|
|
|
}
|
2018-08-28 17:28:46 +02:00
|
|
|
}
|
2020-03-11 10:38:00 -05:00
|
|
|
source = stringify(source);
|
2023-09-29 09:46:32 +01:00
|
|
|
if (shouldCheckAndPopulateCJSModuleCache) {
|
2019-07-09 16:03:07 -05:00
|
|
|
// A require call could have been called on the same file during loading and
|
|
|
|
// that resolves synchronously. To make sure we always return the identical
|
|
|
|
// export, we have to check again if the module already exists or not.
|
2023-08-13 06:23:05 +02:00
|
|
|
// TODO: remove CJS loader from here as well.
|
2019-07-09 16:03:07 -05:00
|
|
|
module = CJSModule._cache[modulePath];
|
2024-09-24 15:48:15 -04:00
|
|
|
if (module?.loaded) {
|
2019-07-09 16:03:07 -05:00
|
|
|
const exports = module.exports;
|
2019-10-04 20:08:00 -07:00
|
|
|
return new ModuleWrap(url, undefined, ['default'], function() {
|
2019-10-04 13:37:27 -04:00
|
|
|
this.setExport('default', exports);
|
2019-10-04 20:08:00 -07:00
|
|
|
});
|
2019-07-09 16:03:07 -05:00
|
|
|
}
|
2019-05-13 14:19:28 +02:00
|
|
|
}
|
2018-08-28 17:28:46 +02:00
|
|
|
try {
|
2019-12-14 22:27:48 -05:00
|
|
|
const exports = JSONParse(stripBOM(source));
|
2018-08-28 17:28:46 +02:00
|
|
|
module = {
|
|
|
|
exports,
|
2023-02-28 12:14:11 +01:00
|
|
|
loaded: true,
|
2018-08-28 17:28:46 +02:00
|
|
|
};
|
|
|
|
} catch (err) {
|
|
|
|
// TODO (BridgeAR): We could add a NodeCore error that wraps the JSON
|
|
|
|
// parse error instead of just manipulating the original error message.
|
|
|
|
// That would allow to add further properties and maybe additional
|
|
|
|
// debugging information.
|
2019-07-09 16:03:07 -05:00
|
|
|
err.message = errPath(url) + ': ' + err.message;
|
2018-08-28 17:28:46 +02:00
|
|
|
throw err;
|
|
|
|
}
|
2023-09-29 09:46:32 +01:00
|
|
|
if (shouldCheckAndPopulateCJSModuleCache) {
|
2019-07-09 16:03:07 -05:00
|
|
|
CJSModule._cache[modulePath] = module;
|
|
|
|
}
|
2023-08-13 06:23:05 +02:00
|
|
|
cjsCache.set(url, module);
|
2019-10-04 20:08:00 -07:00
|
|
|
return new ModuleWrap(url, undefined, ['default'], function() {
|
2018-08-28 17:28:46 +02:00
|
|
|
debug(`Parsing JSONModule ${url}`);
|
2019-10-04 13:37:27 -04:00
|
|
|
this.setExport('default', module.exports);
|
2019-10-04 20:08:00 -07:00
|
|
|
});
|
2017-11-26 17:12:09 -06:00
|
|
|
});
|
2019-04-30 00:27:20 +08:00
|
|
|
|
|
|
|
// Strategy for loading a wasm module
|
2025-02-27 21:10:25 -08:00
|
|
|
// This logic should collapse into WebAssembly Module Record in future.
|
|
|
|
/**
|
|
|
|
* @type {WeakMap<
|
|
|
|
* import('internal/modules/esm/utils').ModuleNamespaceObject,
|
|
|
|
* WebAssembly.Instance
|
|
|
|
* >} [[Instance]] slot proxy for WebAssembly Module Record
|
|
|
|
*/
|
|
|
|
const wasmInstances = new SafeWeakMap();
|
2021-08-25 22:55:14 +02:00
|
|
|
translators.set('wasm', async function(url, source) {
|
2021-11-09 20:39:29 -08:00
|
|
|
emitExperimentalWarning('Importing WebAssembly modules');
|
2021-08-25 22:55:14 +02:00
|
|
|
|
|
|
|
assertBufferSource(source, false, 'load');
|
|
|
|
|
2019-04-30 00:27:20 +08:00
|
|
|
debug(`Translating WASMModule ${url}`);
|
2021-08-25 22:55:14 +02:00
|
|
|
|
2019-04-30 00:27:20 +08:00
|
|
|
let compiled;
|
|
|
|
try {
|
2024-09-17 20:38:33 +02:00
|
|
|
// TODO(joyeecheung): implement a translator that just uses
|
|
|
|
// compiled = new WebAssembly.Module(source) to compile it
|
|
|
|
// synchronously.
|
2019-12-14 22:27:48 -05:00
|
|
|
compiled = await WebAssembly.compile(source);
|
2019-04-30 00:27:20 +08:00
|
|
|
} catch (err) {
|
2019-07-09 16:03:07 -05:00
|
|
|
err.message = errPath(url) + ': ' + err.message;
|
2019-04-30 00:27:20 +08:00
|
|
|
throw err;
|
|
|
|
}
|
|
|
|
|
2025-02-27 21:10:25 -08:00
|
|
|
const importsList = new SafeSet();
|
|
|
|
const wasmGlobalImports = [];
|
|
|
|
for (const impt of WebAssembly.Module.imports(compiled)) {
|
|
|
|
if (impt.kind === 'global') {
|
|
|
|
ArrayPrototypePush(wasmGlobalImports, impt);
|
|
|
|
}
|
|
|
|
importsList.add(impt.module);
|
|
|
|
}
|
|
|
|
|
|
|
|
const exportsList = new SafeSet();
|
|
|
|
const wasmGlobalExports = new SafeSet();
|
|
|
|
for (const expt of WebAssembly.Module.exports(compiled)) {
|
|
|
|
if (expt.kind === 'global') {
|
|
|
|
wasmGlobalExports.add(expt.name);
|
|
|
|
}
|
|
|
|
exportsList.add(expt.name);
|
|
|
|
}
|
2019-04-30 00:27:20 +08:00
|
|
|
|
2025-02-27 21:10:25 -08:00
|
|
|
const createDynamicModule = require('internal/modules/esm/create_dynamic_module');
|
|
|
|
|
|
|
|
const { module } = createDynamicModule([...importsList], [...exportsList], url, (reflect) => {
|
|
|
|
for (const impt of importsList) {
|
|
|
|
const importNs = reflect.imports[impt];
|
|
|
|
const wasmInstance = wasmInstances.get(importNs);
|
|
|
|
if (wasmInstance) {
|
|
|
|
const wrappedModule = ObjectAssign({ __proto__: null }, reflect.imports[impt]);
|
|
|
|
for (const { module, name } of wasmGlobalImports) {
|
|
|
|
if (module !== impt) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// Import of Wasm module global -> get direct WebAssembly.Global wrapped value.
|
|
|
|
// JS API validations otherwise remain the same.
|
|
|
|
wrappedModule[name] = wasmInstance[name];
|
|
|
|
}
|
|
|
|
reflect.imports[impt] = wrappedModule;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// In cycles importing unexecuted Wasm, wasmInstance will be undefined, which will fail during
|
|
|
|
// instantiation, since all bindings will be in the Temporal Deadzone (TDZ).
|
2019-04-30 00:27:20 +08:00
|
|
|
const { exports } = new WebAssembly.Instance(compiled, reflect.imports);
|
2025-02-27 21:10:25 -08:00
|
|
|
wasmInstances.set(module.getNamespace(), exports);
|
|
|
|
for (const expt of exportsList) {
|
|
|
|
let val = exports[expt];
|
|
|
|
// Unwrap WebAssembly.Global for JS bindings
|
|
|
|
if (wasmGlobalExports.has(expt)) {
|
|
|
|
try {
|
|
|
|
// v128 will throw in GetGlobalValue, see:
|
|
|
|
// https://webassembly.github.io/esm-integration/js-api/index.html#getglobalvalue
|
|
|
|
val = val.value;
|
|
|
|
} catch {
|
|
|
|
// v128 doesn't support ToJsValue() -> use undefined (ideally should stay in TDZ)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
reflect.exports[expt].set(val);
|
2023-09-15 12:18:13 -07:00
|
|
|
}
|
2025-02-04 11:31:10 -08:00
|
|
|
});
|
|
|
|
// WebAssembly modules support source phase imports, to import the compiled module
|
|
|
|
// separate from the linked instance.
|
|
|
|
module.setModuleSourceObject(compiled);
|
|
|
|
return module;
|
2019-04-30 00:27:20 +08:00
|
|
|
});
|
2024-07-24 18:30:06 +02:00
|
|
|
|
2024-12-20 11:59:08 +00:00
|
|
|
// Strategy for loading a addon
|
|
|
|
translators.set('addon', function translateAddon(url, source, isMain) {
|
|
|
|
emitExperimentalWarning('Importing addons');
|
|
|
|
|
|
|
|
// The addon must be loaded from file system with dlopen. Assert
|
|
|
|
// the source is null.
|
|
|
|
if (source !== null) {
|
|
|
|
throw new ERR_INVALID_RETURN_PROPERTY_VALUE(
|
|
|
|
'null',
|
|
|
|
'load',
|
|
|
|
'source',
|
|
|
|
source);
|
|
|
|
}
|
|
|
|
|
|
|
|
debug(`Translating addon ${url}`);
|
|
|
|
|
|
|
|
return createCJSNoSourceModuleWrap(url, isMain);
|
|
|
|
});
|
|
|
|
|
2024-07-24 18:30:06 +02:00
|
|
|
// Strategy for loading a commonjs TypeScript module
|
2025-06-12 13:21:54 +02:00
|
|
|
translators.set('commonjs-typescript', function(url, source, isMain) {
|
2024-09-19 15:36:52 +02:00
|
|
|
assertBufferSource(source, true, 'load');
|
2024-10-24 20:27:58 +02:00
|
|
|
const code = stripTypeScriptModuleTypes(stringify(source), url);
|
2024-07-24 18:30:06 +02:00
|
|
|
debug(`Translating TypeScript ${url}`);
|
2025-06-12 13:21:54 +02:00
|
|
|
return FunctionPrototypeCall(translators.get('commonjs'), this, url, code, isMain);
|
2024-07-24 18:30:06 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
// Strategy for loading an esm TypeScript module
|
2025-06-12 13:21:54 +02:00
|
|
|
translators.set('module-typescript', function(url, source, isMain) {
|
2024-09-19 15:36:52 +02:00
|
|
|
assertBufferSource(source, true, 'load');
|
2024-10-24 20:27:58 +02:00
|
|
|
const code = stripTypeScriptModuleTypes(stringify(source), url);
|
2024-07-24 18:30:06 +02:00
|
|
|
debug(`Translating TypeScript ${url}`);
|
2025-06-12 13:21:54 +02:00
|
|
|
return FunctionPrototypeCall(translators.get('module'), this, url, code, isMain);
|
2024-07-24 18:30:06 +02:00
|
|
|
});
|