|
2 | 2 |
|
3 | 3 | const {
|
4 | 4 | ArrayPrototypePush,
|
5 |
| - Boolean, |
6 | 5 | FunctionPrototypeCall,
|
7 | 6 | JSONParse,
|
8 | 7 | ObjectAssign,
|
@@ -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');
|
@@ -186,7 +186,7 @@ function createCJSModuleWrap(url, source, isMain, format, loadCJS = loadCJSModul
|
186 | 186 | // In case the source was not provided by the `load` step, we need fetch it now.
|
187 | 187 | source = stringify(source ?? getSource(new URL(url)).source);
|
188 | 188 |
|
189 |
| - const { exportNames, module } = cjsPreparseModuleExports(filename, source, isMain, format); |
| 189 | + const { exportNames, module } = cjsPreparseModuleExports(filename, source, format); |
190 | 190 | cjsCache.set(url, module);
|
191 | 191 | const namesWithDefault = exportNames.has('default') ?
|
192 | 192 | [...exportNames] : ['default', ...exportNames];
|
@@ -227,6 +227,47 @@ function createCJSModuleWrap(url, source, isMain, format, loadCJS = loadCJSModul
|
227 | 227 | }, module);
|
228 | 228 | }
|
229 | 229 |
|
| 230 | +/** |
| 231 | + * Creates a ModuleWrap object for a CommonJS module without source texts. |
| 232 | + * @param {string} url - The URL of the module. |
| 233 | + * @param {boolean} isMain - Whether the module is the main module. |
| 234 | + * @returns {ModuleWrap} The ModuleWrap object for the CommonJS module. |
| 235 | + */ |
| 236 | +function createCJSNoSourceModuleWrap(url, isMain) { |
| 237 | + debug(`Translating CJSModule without source ${url}`); |
| 238 | + |
| 239 | + const filename = urlToFilename(url); |
| 240 | + |
| 241 | + const module = cjsEmplaceModuleCacheEntry(filename); |
| 242 | + cjsCache.set(url, module); |
| 243 | + |
| 244 | + if (isMain) { |
| 245 | + setOwnProperty(process, 'mainModule', module); |
| 246 | + } |
| 247 | + |
| 248 | + // Addon export names are not known until the addon is loaded. |
| 249 | + const exportNames = ['default', 'module.exports']; |
| 250 | + return new ModuleWrap(url, undefined, exportNames, function evaluationCallback() { |
| 251 | + debug(`Loading CJSModule ${url}`); |
| 252 | + |
| 253 | + if (!module.loaded) { |
| 254 | + wrapModuleLoad(filename, null, isMain); |
| 255 | + } |
| 256 | + |
| 257 | + /** @type {import('./loader').ModuleExports} */ |
| 258 | + let exports; |
| 259 | + if (module[kModuleExport] !== undefined) { |
| 260 | + exports = module[kModuleExport]; |
| 261 | + module[kModuleExport] = undefined; |
| 262 | + } else { |
| 263 | + ({ exports } = module); |
| 264 | + } |
| 265 | + |
| 266 | + this.setExport('default', exports); |
| 267 | + this.setExport('module.exports', exports); |
| 268 | + }, module); |
| 269 | +} |
| 270 | + |
230 | 271 | translators.set('commonjs-sync', function requireCommonJS(url, source, isMain) {
|
231 | 272 | initCJSParseSync();
|
232 | 273 |
|
@@ -277,26 +318,38 @@ translators.set('commonjs', function commonjsStrategy(url, source, isMain) {
|
277 | 318 | return createCJSModuleWrap(url, source, isMain, 'commonjs', cjsLoader);
|
278 | 319 | });
|
279 | 320 |
|
| 321 | +/** |
| 322 | + * Get or create an entry in the CJS module cache for the given filename. |
| 323 | + * @param {string} filename CJS module filename |
| 324 | + * @returns {CJSModule} the cached CJS module entry |
| 325 | + */ |
| 326 | +function cjsEmplaceModuleCacheEntry(filename, exportNames) { |
| 327 | + // TODO: Do we want to keep hitting the user mutable CJS loader here? |
| 328 | + let cjsMod = CJSModule._cache[filename]; |
| 329 | + if (cjsMod) { |
| 330 | + return cjsMod; |
| 331 | + } |
| 332 | + |
| 333 | + cjsMod = new CJSModule(filename); |
| 334 | + cjsMod.filename = filename; |
| 335 | + cjsMod.paths = CJSModule._nodeModulePaths(cjsMod.path); |
| 336 | + cjsMod[kIsCachedByESMLoader] = true; |
| 337 | + CJSModule._cache[filename] = cjsMod; |
| 338 | + |
| 339 | + return cjsMod; |
| 340 | +} |
| 341 | + |
280 | 342 | /**
|
281 | 343 | * Pre-parses a CommonJS module's exports and re-exports.
|
282 | 344 | * @param {string} filename - The filename of the module.
|
283 | 345 | * @param {string} [source] - The source code of the module.
|
284 |
| - * @param {boolean} isMain - Whether it is pre-parsing for the entry point. |
285 |
| - * @param {string} format |
| 346 | + * @param {string} [format] |
286 | 347 | */
|
287 |
| -function cjsPreparseModuleExports(filename, source, isMain, format) { |
288 |
| - let module = CJSModule._cache[filename]; |
289 |
| - if (module && module[kModuleExportNames] !== undefined) { |
| 348 | +function cjsPreparseModuleExports(filename, source, format) { |
| 349 | + const module = cjsEmplaceModuleCacheEntry(filename); |
| 350 | + if (module[kModuleExportNames] !== undefined) { |
290 | 351 | return { module, exportNames: module[kModuleExportNames] };
|
291 | 352 | }
|
292 |
| - const loaded = Boolean(module); |
293 |
| - if (!loaded) { |
294 |
| - module = new CJSModule(filename); |
295 |
| - module.filename = filename; |
296 |
| - module.paths = CJSModule._nodeModulePaths(module.path); |
297 |
| - module[kIsCachedByESMLoader] = true; |
298 |
| - CJSModule._cache[filename] = module; |
299 |
| - } |
300 | 353 |
|
301 | 354 | if (source === undefined) {
|
302 | 355 | ({ source } = loadSourceForCJSWithHooks(module, filename, format));
|
@@ -337,7 +390,7 @@ function cjsPreparseModuleExports(filename, source, isMain, format) {
|
337 | 390 |
|
338 | 391 | if (format === 'commonjs' ||
|
339 | 392 | (!BuiltinModule.normalizeRequirableId(resolved) && findLongestRegisteredExtension(resolved) === '.js')) {
|
340 |
| - const { exportNames: reexportNames } = cjsPreparseModuleExports(resolved, undefined, false, format); |
| 393 | + const { exportNames: reexportNames } = cjsPreparseModuleExports(resolved, undefined, format); |
341 | 394 | for (const name of reexportNames) {
|
342 | 395 | exportNames.add(name);
|
343 | 396 | }
|
@@ -519,6 +572,25 @@ translators.set('wasm', function(url, source) {
|
519 | 572 | return module;
|
520 | 573 | });
|
521 | 574 |
|
| 575 | +// Strategy for loading a addon |
| 576 | +translators.set('addon', function translateAddon(url, source, isMain) { |
| 577 | + emitExperimentalWarning('Importing addons'); |
| 578 | + |
| 579 | + // The addon must be loaded from file system with dlopen. Assert |
| 580 | + // the source is null. |
| 581 | + if (source !== null) { |
| 582 | + throw new ERR_INVALID_RETURN_PROPERTY_VALUE( |
| 583 | + 'null', |
| 584 | + 'load', |
| 585 | + 'source', |
| 586 | + source); |
| 587 | + } |
| 588 | + |
| 589 | + debug(`Translating addon ${url}`); |
| 590 | + |
| 591 | + return createCJSNoSourceModuleWrap(url, isMain); |
| 592 | +}); |
| 593 | + |
522 | 594 | // Strategy for loading a commonjs TypeScript module
|
523 | 595 | translators.set('commonjs-typescript', function(url, source, isMain) {
|
524 | 596 | assertBufferSource(source, true, 'load');
|
|
0 commit comments