GeezerVison is showing github.com — lib: reduce cycles in esm loader and load it in snapshot · nodejs/node@df47720
File treeExpand file treeCollapse file tree Open diff view settings Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: lib/internal/bootstrap/switches/is_main_thread.js +1Lines changed: 1 addition & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -296,6 +296,7 @@ require('util'); | 296 | 296 | require('url'); // eslint-disable-line no-restricted-modules | 297 | 297 | internalBinding('module_wrap'); | 298 | 298 | require('internal/modules/cjs/loader'); | | 299 | +require('internal/modules/esm/loader'); | 299 | 300 | require('internal/modules/esm/utils'); | 300 | 301 |
| 301 | 302 | // Needed to refresh the time origin. | |
Collapse file Copy file name to clipboardExpand all lines: lib/internal/modules/esm/loader.js +6-24Lines changed: 6 additions & 24 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -65,8 +65,6 @@ const { | 65 | 65 | validateLoadSloppy, | 66 | 66 | } = require('internal/modules/customization_hooks'); | 67 | 67 |
| 68 | | -let defaultResolve, defaultLoadSync; | 69 | | - | 70 | 68 | const { tracingChannel } = require('diagnostics_channel'); | 71 | 69 | const onImport = tracingChannel('module.import'); | 72 | 70 |
| @@ -100,19 +98,9 @@ function newLoadCache() { | 100 | 98 | return new LoadCache(); | 101 | 99 | } | 102 | 100 |
| 103 | | -let _translators; | 104 | | -function lazyLoadTranslators() { | 105 | | - _translators ??= require('internal/modules/esm/translators'); | 106 | | - return _translators; | 107 | | -} | 108 | | - | 109 | | -/** | 110 | | - * Lazy-load translators to avoid potentially unnecessary work at startup (ex if ESM is not used). | 111 | | - * @returns {import('./translators.js').Translators} | 112 | | - */ | 113 | | -function getTranslators() { | 114 | | - return lazyLoadTranslators().translators; | 115 | | -} | | 101 | +const { translators } = require('internal/modules/esm/translators'); | | 102 | +const { defaultResolve } = require('internal/modules/esm/resolve'); | | 103 | +const { defaultLoadSync, throwUnknownModuleFormat } = require('internal/modules/esm/load'); | 116 | 104 |
| 117 | 105 | /** | 118 | 106 | * Generate message about potential race condition caused by requiring a cached module that has started | @@ -181,11 +169,6 @@ class ModuleLoader { | 181 | 169 | */ | 182 | 170 | loadCache = newLoadCache(); | 183 | 171 |
| 184 | | - /** | 185 | | - * Methods which translate input code or other information into ES modules | 186 | | - */ | 187 | | - translators = getTranslators(); | 188 | | - | 189 | 172 | /** | 190 | 173 | * @see {AsyncLoaderHooks.isForAsyncLoaderHookWorker} | 191 | 174 | * Shortcut to this.#asyncLoaderHooks.isForAsyncLoaderHookWorker. | @@ -459,7 +442,7 @@ class ModuleLoader { | 459 | 442 | #translate(url, translateContext, parentURL) { | 460 | 443 | const { translatorKey, format } = translateContext; | 461 | 444 | this.validateLoadResult(url, format); | 462 | | - const translator = getTranslators().get(translatorKey); | | 445 | + const translator = translators.get(translatorKey); | 463 | 446 |
| 464 | 447 | if (!translator) { | 465 | 448 | throw new ERR_UNKNOWN_MODULE_FORMAT(translatorKey, url); | @@ -710,7 +693,7 @@ class ModuleLoader { | 710 | 693 | if (cachedResult != null) { | 711 | 694 | return cachedResult; | 712 | 695 | } | 713 | | - defaultResolve ??= require('internal/modules/esm/resolve').defaultResolve; | | 696 | + | 714 | 697 | const result = defaultResolve(specifier, context); | 715 | 698 | this.#resolveCache.set(requestKey, parentURL, result); | 716 | 699 | return result; | @@ -787,7 +770,6 @@ class ModuleLoader { | 787 | 770 | if (this.#asyncLoaderHooks?.loadSync) { | 788 | 771 | return this.#asyncLoaderHooks.loadSync(url, context); | 789 | 772 | } | 790 | | - defaultLoadSync ??= require('internal/modules/esm/load').defaultLoadSync; | 791 | 773 | return defaultLoadSync(url, context); | 792 | 774 | } | 793 | 775 |
| @@ -813,7 +795,7 @@ class ModuleLoader { | 813 | 795 |
| 814 | 796 | validateLoadResult(url, format) { | 815 | 797 | if (format == null) { | 816 | | - require('internal/modules/esm/load').throwUnknownModuleFormat(url, format); | | 798 | + throwUnknownModuleFormat(url, format); | 817 | 799 | } | 818 | 800 | } | 819 | 801 |
| |
Collapse file Copy file name to clipboardExpand all lines: lib/internal/modules/esm/resolve.js +2-7Lines changed: 2 additions & 7 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -46,8 +46,7 @@ const { | 46 | 46 | ERR_UNSUPPORTED_DIR_IMPORT, | 47 | 47 | ERR_UNSUPPORTED_RESOLVE_REQUEST, | 48 | 48 | } = require('internal/errors').codes; | 49 | | - | 50 | | -const { Module: CJSModule } = require('internal/modules/cjs/loader'); | | 49 | +const { defaultGetFormatWithoutErrors } = require('internal/modules/esm/get_format'); | 51 | 50 | const { getConditionsSet } = require('internal/modules/esm/utils'); | 52 | 51 | const packageJsonReader = require('internal/modules/package_json_reader'); | 53 | 52 | const internalFsBinding = internalBinding('fs'); | @@ -870,6 +869,7 @@ function moduleResolve(specifier, base, conditions, preserveSymlinks) { | 870 | 869 | */ | 871 | 870 | function resolveAsCommonJS(specifier, parentURL) { | 872 | 871 | try { | | 872 | + const { Module: CJSModule } = require('internal/modules/cjs/loader'); | 873 | 873 | const parent = fileURLToPath(parentURL); | 874 | 874 | const tmpModule = new CJSModule(parent, null); | 875 | 875 | tmpModule.paths = CJSModule._nodeModulePaths(parent); | @@ -1043,8 +1043,3 @@ module.exports = { | 1043 | 1043 | packageResolve, | 1044 | 1044 | throwIfInvalidParentURL, | 1045 | 1045 | }; | 1046 | | - | 1047 | | -// cycle | 1048 | | -const { | 1049 | | - defaultGetFormatWithoutErrors, | 1050 | | -} = require('internal/modules/esm/get_format'); |
Collapse file Copy file name to clipboardExpand all lines: lib/internal/modules/esm/translators.js +5-12Lines changed: 5 additions & 12 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -13,7 +13,7 @@ const { | 13 | 13 | StringPrototypeReplaceAll, | 14 | 14 | StringPrototypeSlice, | 15 | 15 | StringPrototypeStartsWith, | 16 | | - globalThis: { WebAssembly }, | | 16 | + globalThis, | 17 | 17 | } = primordials; | 18 | 18 |
| 19 | 19 | const { | @@ -57,16 +57,7 @@ const { maybeCacheSourceMap } = require('internal/source_map/source_map_cache'); | 57 | 57 | const moduleWrap = internalBinding('module_wrap'); | 58 | 58 | const { ModuleWrap, kEvaluationPhase } = moduleWrap; | 59 | 59 |
| 60 | | -// Lazy-loading to avoid circular dependencies. | 61 | | -let getSourceSync; | 62 | | -/** | 63 | | - * @param {Parameters<typeof import('./load').getSourceSync>[0]} url | 64 | | - * @returns {ReturnType<typeof import('./load').getSourceSync>} | 65 | | - */ | 66 | | -function getSource(url) { | 67 | | - getSourceSync ??= require('internal/modules/esm/load').getSourceSync; | 68 | | - return getSourceSync(url); | 69 | | -} | | 60 | +const { getSourceSync } = require('internal/modules/esm/load'); | 70 | 61 |
| 71 | 62 | const { parse: cjsParse } = internalBinding('cjs_lexer'); | 72 | 63 |
| @@ -210,7 +201,7 @@ function createCJSModuleWrap(url, translateContext, parentURL, loadCJS = loadCJS | 210 | 201 | const isMain = (parentURL === undefined); | 211 | 202 | const filename = urlToFilename(url); | 212 | 203 | // In case the source was not provided by the `load` step, we need fetch it now. | 213 | | - source = stringify(source ?? getSource(new URL(url)).source); | | 204 | + source = stringify(source ?? getSourceSync(new URL(url)).source); | 214 | 205 |
| 215 | 206 | const { exportNames, module } = cjsPreparseModuleExports(filename, source, sourceFormat); | 216 | 207 | cjsCache.set(url, module); | @@ -516,6 +507,8 @@ translators.set('json', function jsonStrategy(url, translateContext) { | 516 | 507 | const wasmInstances = new SafeWeakMap(); | 517 | 508 | translators.set('wasm', function(url, translateContext) { | 518 | 509 | const { source } = translateContext; | | 510 | + // WebAssembly global is not available during snapshot building, so we need to get it lazily. | | 511 | + const { WebAssembly } = globalThis; | 519 | 512 | assertBufferSource(source, false, 'load'); | 520 | 513 |
| 521 | 514 | debug(`Translating WASMModule ${url}`, translateContext); | |
Collapse file Copy file name to clipboardExpand all lines: test/parallel/test-bootstrap-modules.js +7-1Lines changed: 7 additions & 1 deletion | Original file line number | Diff line number | Diff line change |
|---|
@@ -115,17 +115,23 @@ expected.beforePreExec = new Set([ | 115 | 115 | 'NativeModule internal/modules/run_main', | 116 | 116 | 'NativeModule internal/net', | 117 | 117 | 'NativeModule internal/dns/utils', | | 118 | + 'NativeModule internal/modules/esm/get_format', | 118 | 119 | ]); | 119 | 120 |
| 120 | 121 | expected.atRunTime = new Set([ | 121 | | - 'NativeModule internal/modules/esm/get_format', | 122 | 122 | 'NativeModule internal/process/pre_execution', | 123 | 123 | ]); | 124 | 124 |
| 125 | 125 | const { isMainThread } = require('worker_threads'); | 126 | 126 |
| 127 | 127 | if (isMainThread) { | 128 | 128 | [ | | 129 | + 'Internal Binding cjs_lexer', | | 130 | + 'NativeModule internal/modules/esm/assert', | | 131 | + 'NativeModule internal/modules/esm/loader', | | 132 | + 'NativeModule internal/modules/esm/load', | | 133 | + 'NativeModule internal/modules/esm/resolve', | | 134 | + 'NativeModule internal/modules/esm/translators', | 129 | 135 | 'NativeModule url', | 130 | 136 | ].forEach(expected.beforePreExec.add.bind(expected.beforePreExec)); | 131 | 137 | } else { // Worker. | |
|