@@ -51,6 +51,7 @@ const { |
51 | 51 | kErrored, |
52 | 52 | kSourcePhase, |
53 | 53 | throwIfPromiseRejected, |
| 54 | + setImportMetaResolveInitializer, |
54 | 55 | } = internalBinding('module_wrap'); |
55 | 56 | const { |
56 | 57 | urlToFilename, |
@@ -62,7 +63,8 @@ const { |
62 | 63 | loadWithHooks: loadWithSyncHooks, |
63 | 64 | validateLoadSloppy, |
64 | 65 | } = require('internal/modules/customization_hooks'); |
65 | | -let defaultResolve, defaultLoadSync, importMetaInitializer; |
| 66 | + |
| 67 | +let defaultResolve, defaultLoadSync; |
66 | 68 |
|
67 | 69 | const { tracingChannel } = require('diagnostics_channel'); |
68 | 70 | const onImport = tracingChannel('module.import'); |
@@ -183,13 +185,6 @@ class ModuleLoader { |
183 | 185 | */ |
184 | 186 | translators = getTranslators(); |
185 | 187 |
|
186 | | - /** |
187 | | - * Truthy to allow the use of `import.meta.resolve`. This is needed |
188 | | - * currently because the `Hooks` class does not have `resolveSync` |
189 | | - * implemented and `import.meta.resolve` requires it. |
190 | | - */ |
191 | | - allowImportMetaResolve; |
192 | | - |
193 | 188 | /** |
194 | 189 | * @see {AsyncLoaderHooks.isForAsyncLoaderHookWorker} |
195 | 190 | * Shortcut to this.#asyncLoaderHooks.isForAsyncLoaderHookWorker. |
@@ -200,9 +195,10 @@ class ModuleLoader { |
200 | 195 | * Asynchronous loader hooks to pass requests to. |
201 | 196 | * |
202 | 197 | * Note that this value _MUST_ be set with `#setAsyncLoaderHooks` |
203 | | - * because it needs to copy `#asyncLoaderHooks.allowImportMetaResolve` |
204 | | - * to this property and failure to do so will cause undefined |
205 | | - * behavior when invoking `import.meta.resolve`. |
| 198 | + * because it needs to copy `#asyncLoaderHooks.isForAsyncLoaderHookWorker` |
| 199 | + * to this property. |
| 200 | + * TODO(joyeecheung): this was a legacy of the previous setup of import.meta.resolve |
| 201 | + * configuration; put this information in the environment directly instead. |
206 | 202 | * |
207 | 203 | * When the ModuleLoader is created on a loader hook thread, this is |
208 | 204 | * {@link AsyncLoaderHooksOnLoaderHookWorker}, and its methods directly call out |
@@ -234,10 +230,8 @@ class ModuleLoader { |
234 | 230 | #setAsyncLoaderHooks(asyncLoaderHooks) { |
235 | 231 | this.#asyncLoaderHooks = asyncLoaderHooks; |
236 | 232 | if (asyncLoaderHooks) { |
237 | | - this.allowImportMetaResolve = asyncLoaderHooks.allowImportMetaResolve; |
238 | 233 | this.isForAsyncLoaderHookWorker = asyncLoaderHooks.isForAsyncLoaderHookWorker; |
239 | 234 | } else { |
240 | | - this.allowImportMetaResolve = true; |
241 | 235 | this.isForAsyncLoaderHookWorker = false; |
242 | 236 | } |
243 | 237 | } |
@@ -821,15 +815,6 @@ class ModuleLoader { |
821 | 815 | } |
822 | 816 | } |
823 | 817 |
|
824 | | - importMetaInitialize(meta, context) { |
825 | | - if (this.#asyncLoaderHooks) { |
826 | | - return this.#asyncLoaderHooks.importMetaInitialize(meta, context, this); |
827 | | - } |
828 | | - importMetaInitializer ??= require('internal/modules/esm/initialize_import_meta').initializeImportMeta; |
829 | | - meta = importMetaInitializer(meta, context, this); |
830 | | - return meta; |
831 | | - } |
832 | | - |
833 | 818 | /** |
834 | 819 | * Block until the async loader hooks have been initialized. |
835 | 820 | * |
@@ -883,8 +868,47 @@ function createModuleLoader(asyncLoaderHooks) { |
883 | 868 | return new ModuleLoader(asyncLoaderHooks); |
884 | 869 | } |
885 | 870 |
|
886 | | -let cascadedLoader; |
| 871 | +let allowImportMetaResolveParentURL; |
| 872 | +/** |
| 873 | + * This is only called from the native ImportMetaObjectInitialize function to set up import.meta.resolve |
| 874 | + * when import.meta.resolve is accessed for the first time in a module. |
| 875 | + * @param {ModuleLoader} loader The cascaded loader to use. Bound when this function gets passed to native land. |
| 876 | + * @param {string} moduleURL URL of the module accessing import.meta |
| 877 | + * @returns {function(string, URL['href']=): string} The import.meta.resolve function |
| 878 | + */ |
| 879 | +function createImportMetaResolve(loader, moduleURL) { |
| 880 | + /** |
| 881 | + * @param {string} specifier The module specifier to resolve. |
| 882 | + * @param {URL['href']} [parentURL] Optional parent URL to resolve against. Ignored unless |
| 883 | + * `--experimental-import-meta-resolve` is enabled. |
| 884 | + * @returns {string} |
| 885 | + */ |
| 886 | + return function resolve(specifier, parentURL) { |
| 887 | + // The second argument is ignored unless --experimental-import-meta-resolve is enabled. |
| 888 | + // Even then, if it's not provided, parentURL defaults to the url of the module accessing |
| 889 | + // import.meta.resolve. |
| 890 | + allowImportMetaResolveParentURL ??= getOptionValue('--experimental-import-meta-resolve'); |
| 891 | + parentURL = allowImportMetaResolveParentURL ? (parentURL ?? moduleURL) : moduleURL; |
| 892 | + |
| 893 | + let url; |
| 894 | + try { |
| 895 | + ({ url } = loader.resolveSync(parentURL, { specifier, __proto__: null })); |
| 896 | + return url; |
| 897 | + } catch (error) { |
| 898 | + switch (error?.code) { |
| 899 | + case 'ERR_UNSUPPORTED_DIR_IMPORT': |
| 900 | + case 'ERR_MODULE_NOT_FOUND': |
| 901 | + ({ url } = error); |
| 902 | + if (url) { |
| 903 | + return url; |
| 904 | + } |
| 905 | + } |
| 906 | + throw error; |
| 907 | + } |
| 908 | + }; |
| 909 | +} |
887 | 910 |
|
| 911 | +let cascadedLoader; |
888 | 912 | /** |
889 | 913 | * This is a singleton ESM loader that integrates the loader hooks, if any. |
890 | 914 | * It it used by other internal built-ins when they need to load user-land ESM code |
@@ -898,7 +922,16 @@ let cascadedLoader; |
898 | 922 | * @returns {ModuleLoader} |
899 | 923 | */ |
900 | 924 | function getOrInitializeCascadedLoader(asyncLoaderHooks) { |
901 | | - cascadedLoader ??= createModuleLoader(asyncLoaderHooks); |
| 925 | + if (!cascadedLoader) { |
| 926 | + cascadedLoader = createModuleLoader(asyncLoaderHooks); |
| 927 | + // import.meta.resolve is not allowed in the async loader hook worker thread. |
| 928 | + // So only set up the import.meta.resolve initializer when we are initializing |
| 929 | + // the non-loader-hook-thread cascaded loader. When the native land doesn't see it, |
| 930 | + // it knows the loader is running on the loader hook thread. |
| 931 | + if (!(asyncLoaderHooks?.isForAsyncLoaderHookWorker)) { |
| 932 | + setImportMetaResolveInitializer(createImportMetaResolve.bind(null, cascadedLoader)); |
| 933 | + } |
| 934 | + } |
902 | 935 | return cascadedLoader; |
903 | 936 | } |
904 | 937 |
|
|