|
1 | 1 | import ErrorCodeTitle from '@components/ErrorCodeTitle'; |
2 | 2 | import EnableAsyncEntry from '@components/en/EnableAsyncEntry'; |
3 | 3 | import Runtime from '@components/en/runtime/index'; |
| 4 | +import { Tab, Tabs } from '@theme'; |
4 | 5 |
|
5 | 6 | # Runtime |
6 | 7 |
|
@@ -45,6 +46,97 @@ There are corresponding solutions for the reasons: |
45 | 46 | 4. Loading a ESM remote from a non-esm host |
46 | 47 | - setting `type: 'module'` on the remote config |
47 | 48 |
|
| 49 | +### Getting More Detailed Error Information |
| 50 | + |
| 51 | +If you have confirmed that `window[remoteEntryKey]` does not exist (i.e. the script failed to register the container), but there is no clear error message in the console, it may be because the producer script is a cross-origin resource. Browsers hide error details for cross-origin scripts by default (`filename`, `lineno`, and `message` are all empty). |
| 52 | + |
| 53 | +You can add a `crossorigin` attribute to the script via the [`createScript`](../../plugin/dev/index#createscript) hook, provided that the producer server has `Access-Control-Allow-Origin` configured. |
| 54 | + |
| 55 | +First, create the runtime plugin file: |
| 56 | + |
| 57 | +```ts title="script-crossorigin-plugin.ts" |
| 58 | +import { ModuleFederationRuntimePlugin } from '@module-federation/runtime/types'; |
| 59 | + |
| 60 | +export default function MFScriptPlugin(): ModuleFederationRuntimePlugin { |
| 61 | + return { |
| 62 | + name: 'script-crossorigin-plugin', |
| 63 | + createScript({ url }) { |
| 64 | + const script = document.createElement('script'); |
| 65 | + script.src = url; |
| 66 | + script.crossOrigin = 'anonymous'; |
| 67 | + return script; |
| 68 | + }, |
| 69 | + // If preloadRemote is used in your project, also implement createLink to keep |
| 70 | + // crossorigin consistent. Without this, the preload (no-cors) and actual load |
| 71 | + // (cors) will have different cache keys, causing the preload to be wasted. |
| 72 | + createLink({ url, attrs }) { |
| 73 | + const link = document.createElement('link'); |
| 74 | + link.setAttribute('href', url); |
| 75 | + link.setAttribute('crossorigin', 'anonymous'); |
| 76 | + if (attrs) { |
| 77 | + Object.entries(attrs).forEach(([key, value]) => { |
| 78 | + if (key !== 'crossorigin') { |
| 79 | + link.setAttribute(key, String(value)); |
| 80 | + } |
| 81 | + }); |
| 82 | + } |
| 83 | + return link; |
| 84 | + }, |
| 85 | + }; |
| 86 | +} |
| 87 | +``` |
| 88 | + |
| 89 | +Then register the plugin: |
| 90 | + |
| 91 | +<Tabs> |
| 92 | + <Tab label="Build Plugin"> |
| 93 | + |
| 94 | +Register via the `runtimePlugins` field in your build config: |
| 95 | + |
| 96 | +```ts title="rspack.config.ts" |
| 97 | +const path = require('path'); |
| 98 | +module.exports = { |
| 99 | + plugins: [ |
| 100 | + new ModuleFederationPlugin({ |
| 101 | + name: 'host', |
| 102 | + remotes: { /* ... */ }, |
| 103 | + runtimePlugins: [ |
| 104 | + path.resolve(__dirname, './script-crossorigin-plugin.ts'), |
| 105 | + ], |
| 106 | + }), |
| 107 | + ], |
| 108 | +}; |
| 109 | +``` |
| 110 | + |
| 111 | + </Tab> |
| 112 | + <Tab label="Runtime API"> |
| 113 | + |
| 114 | +Register via the `plugins` field in the `init` API: |
| 115 | + |
| 116 | +```ts title="index.ts" |
| 117 | +import { init } from '@module-federation/runtime'; |
| 118 | +import MFScriptPlugin from './script-crossorigin-plugin'; |
| 119 | + |
| 120 | +init({ |
| 121 | + name: 'host', |
| 122 | + remotes: [/* ... */], |
| 123 | + plugins: [MFScriptPlugin()], |
| 124 | +}); |
| 125 | +``` |
| 126 | + |
| 127 | + </Tab> |
| 128 | +</Tabs> |
| 129 | + |
| 130 | +Once added, runtime exceptions thrown by cross-origin scripts will include the full `filename`, `lineno`, and `message`, making it easier to locate the specific error. |
| 131 | + |
| 132 | +:::tip |
| 133 | + |
| 134 | +* If the server does not have CORS headers configured, adding the `crossorigin` attribute will instead cause the script to fail to load (network error). Confirm the server is correctly configured before using this approach. |
| 135 | + |
| 136 | +* MF does not sync this automatically because doing so would require calling the `createScript` hook speculatively during preload to read the `crossOrigin` value — hook implementations may have side effects (e.g. registering listeners, mutating global state), so invoking the hook twice could cause unpredictable behavior. |
| 137 | + |
| 138 | +::: |
| 139 | + |
48 | 140 | ## RUNTIME-002 |
49 | 141 |
|
50 | 142 | <ErrorCodeTitle code='RUNTIME-002'/> |
@@ -182,6 +274,10 @@ The script file downloaded successfully, but its IIFE threw a runtime exception |
182 | 274 | A `ScriptExecutionError` means the script was downloaded successfully — retrying will not fix this type of error. Focus on investigating compatibility or runtime errors in the producer's code first. |
183 | 275 | ::: |
184 | 276 |
|
| 277 | +### Getting More Detailed Error Information |
| 278 | + |
| 279 | +Prior to **v2.2.0**, RUNTIME-008 error messages may not include specific exception details. If the error message is not descriptive enough, refer to 「[RUNTIME-001 Getting More Detailed Error Information](#getting-more-detailed-error-information)」 for how to add the `crossorigin` attribute to retrieve the full error stack. |
| 280 | + |
185 | 281 | ## RUNTIME-009 |
186 | 282 |
|
187 | 283 | <ErrorCodeTitle code='RUNTIME-009'/> |
|
0 commit comments