|
3 | 3 | const {
|
4 | 4 | ArrayPrototypeMap,
|
5 | 5 | ArrayPrototypePush,
|
6 |
| - Boolean, |
7 | 6 | FunctionPrototypeCall,
|
8 | 7 | JSONParse,
|
9 | 8 | ObjectKeys,
|
@@ -52,6 +51,7 @@ let debug = require('internal/util/debuglog').debuglog('esm', (fn) => {
|
52 | 51 | });
|
53 | 52 | const { emitExperimentalWarning, kEmptyObject, setOwnProperty, isWindows } = require('internal/util');
|
54 | 53 | const {
|
| 54 | + ERR_INVALID_RETURN_PROPERTY_VALUE, |
55 | 55 | ERR_UNKNOWN_BUILTIN_MODULE,
|
56 | 56 | } = require('internal/errors').codes;
|
57 | 57 | const { maybeCacheSourceMap } = require('internal/source_map/source_map_cache');
|
@@ -185,7 +185,7 @@ function createCJSModuleWrap(url, source, isMain, format, loadCJS = loadCJSModul
|
185 | 185 | // In case the source was not provided by the `load` step, we need fetch it now.
|
186 | 186 | source = stringify(source ?? getSource(new URL(url)).source);
|
187 | 187 |
|
188 |
| - const { exportNames, module } = cjsPreparseModuleExports(filename, source, isMain, format); |
| 188 | + const { exportNames, module } = cjsPreparseModuleExports(filename, source, format); |
189 | 189 | cjsCache.set(url, module);
|
190 | 190 |
|
191 | 191 | const wrapperNames = [...exportNames, 'module.exports'];
|
@@ -229,6 +229,47 @@ function createCJSModuleWrap(url, source, isMain, format, loadCJS = loadCJSModul
|
229 | 229 | }, module);
|
230 | 230 | }
|
231 | 231 |
|
| 232 | +/** |
| 233 | + * Creates a ModuleWrap object for a CommonJS module without source texts. |
| 234 | + * @param {string} url - The URL of the module. |
| 235 | + * @param {boolean} isMain - Whether the module is the main module. |
| 236 | + * @returns {ModuleWrap} The ModuleWrap object for the CommonJS module. |
| 237 | + */ |
| 238 | +function createCJSNoSourceModuleWrap(url, isMain) { |
| 239 | + debug(`Translating CJSModule without source ${url}`); |
| 240 | + |
| 241 | + const filename = urlToFilename(url); |
| 242 | + |
| 243 | + const module = cjsEmplaceModuleCacheEntry(filename); |
| 244 | + cjsCache.set(url, module); |
| 245 | + |
| 246 | + if (isMain) { |
| 247 | + setOwnProperty(process, 'mainModule', module); |
| 248 | + } |
| 249 | + |
| 250 | + // Addon export names are not known until the addon is loaded. |
| 251 | + const exportNames = ['default', 'module.exports']; |
| 252 | + return new ModuleWrap(url, undefined, exportNames, function evaluationCallback() { |
| 253 | + debug(`Loading CJSModule ${url}`); |
| 254 | + |
| 255 | + if (!module.loaded) { |
| 256 | + wrapModuleLoad(filename, null, isMain); |
| 257 | + } |
| 258 | + |
| 259 | + /** @type {import('./loader').ModuleExports} */ |
| 260 | + let exports; |
| 261 | + if (module[kModuleExport] !== undefined) { |
| 262 | + exports = module[kModuleExport]; |
| 263 | + module[kModuleExport] = undefined; |
| 264 | + } else { |
| 265 | + ({ exports } = module); |
| 266 | + } |
| 267 | + |
| 268 | + this.setExport('default', exports); |
| 269 | + this.setExport('module.exports', exports); |
| 270 | + }, module); |
| 271 | +} |
| 272 | + |
232 | 273 | translators.set('commonjs-sync', function requireCommonJS(url, source, isMain) {
|
233 | 274 | initCJSParseSync();
|
234 | 275 |
|
@@ -280,26 +321,38 @@ translators.set('commonjs', function commonjsStrategy(url, source, isMain) {
|
280 | 321 | return createCJSModuleWrap(url, source, isMain, 'commonjs', cjsLoader);
|
281 | 322 | });
|
282 | 323 |
|
| 324 | +/** |
| 325 | + * Get or create an entry in the CJS module cache for the given filename. |
| 326 | + * @param {string} filename CJS module filename |
| 327 | + * @returns {CJSModule} the cached CJS module entry |
| 328 | + */ |
| 329 | +function cjsEmplaceModuleCacheEntry(filename, exportNames) { |
| 330 | + // TODO: Do we want to keep hitting the user mutable CJS loader here? |
| 331 | + let cjsMod = CJSModule._cache[filename]; |
| 332 | + if (cjsMod) { |
| 333 | + return cjsMod; |
| 334 | + } |
| 335 | + |
| 336 | + cjsMod = new CJSModule(filename); |
| 337 | + cjsMod.filename = filename; |
| 338 | + cjsMod.paths = CJSModule._nodeModulePaths(cjsMod.path); |
| 339 | + cjsMod[kIsCachedByESMLoader] = true; |
| 340 | + CJSModule._cache[filename] = cjsMod; |
| 341 | + |
| 342 | + return cjsMod; |
| 343 | +} |
| 344 | + |
283 | 345 | /**
|
284 | 346 | * Pre-parses a CommonJS module's exports and re-exports.
|
285 | 347 | * @param {string} filename - The filename of the module.
|
286 | 348 | * @param {string} [source] - The source code of the module.
|
287 |
| - * @param {boolean} isMain - Whether it is pre-parsing for the entry point. |
288 |
| - * @param {string} format |
| 349 | + * @param {string} [format] |
289 | 350 | */
|
290 |
| -function cjsPreparseModuleExports(filename, source, isMain, format) { |
291 |
| - let module = CJSModule._cache[filename]; |
292 |
| - if (module && module[kModuleExportNames] !== undefined) { |
| 351 | +function cjsPreparseModuleExports(filename, source, format) { |
| 352 | + const module = cjsEmplaceModuleCacheEntry(filename); |
| 353 | + if (module[kModuleExportNames] !== undefined) { |
293 | 354 | return { module, exportNames: module[kModuleExportNames] };
|
294 | 355 | }
|
295 |
| - const loaded = Boolean(module); |
296 |
| - if (!loaded) { |
297 |
| - module = new CJSModule(filename); |
298 |
| - module.filename = filename; |
299 |
| - module.paths = CJSModule._nodeModulePaths(module.path); |
300 |
| - module[kIsCachedByESMLoader] = true; |
301 |
| - CJSModule._cache[filename] = module; |
302 |
| - } |
303 | 356 |
|
304 | 357 | if (source === undefined) {
|
305 | 358 | ({ source } = loadSourceForCJSWithHooks(module, filename, format));
|
@@ -340,7 +393,7 @@ function cjsPreparseModuleExports(filename, source, isMain, format) {
|
340 | 393 |
|
341 | 394 | if (format === 'commonjs' ||
|
342 | 395 | (!BuiltinModule.normalizeRequirableId(resolved) && findLongestRegisteredExtension(resolved) === '.js')) {
|
343 |
| - const { exportNames: reexportNames } = cjsPreparseModuleExports(resolved, undefined, false, format); |
| 396 | + const { exportNames: reexportNames } = cjsPreparseModuleExports(resolved, undefined, format); |
344 | 397 | for (const name of reexportNames) {
|
345 | 398 | exportNames.add(name);
|
346 | 399 | }
|
@@ -462,6 +515,25 @@ translators.set('wasm', async function(url, source) {
|
462 | 515 | }).module;
|
463 | 516 | });
|
464 | 517 |
|
| 518 | +// Strategy for loading a addon |
| 519 | +translators.set('addon', function translateAddon(url, source, isMain) { |
| 520 | + emitExperimentalWarning('Importing addons'); |
| 521 | + |
| 522 | + // The addon must be loaded from file system with dlopen. Assert |
| 523 | + // the source is null. |
| 524 | + if (source !== null) { |
| 525 | + throw new ERR_INVALID_RETURN_PROPERTY_VALUE( |
| 526 | + 'null', |
| 527 | + 'load', |
| 528 | + 'source', |
| 529 | + source); |
| 530 | + } |
| 531 | + |
| 532 | + debug(`Translating addon ${url}`); |
| 533 | + |
| 534 | + return createCJSNoSourceModuleWrap(url, isMain); |
| 535 | +}); |
| 536 | + |
465 | 537 | // Strategy for loading a commonjs TypeScript module
|
466 | 538 | translators.set('commonjs-typescript', function(url, source) {
|
467 | 539 | emitExperimentalWarning('Type Stripping');
|
|
0 commit comments