refactor: inline all bootstrap files and enable asyncStartup everywhere#4416
refactor: inline all bootstrap files and enable asyncStartup everywhere#4416ScriptedAlchemy wants to merge 32 commits intomasterfrom
Conversation
With `experiments: { asyncStartup: true }` enabled, the manual
`import('./bootstrap')` async boundary is unnecessary. Inline the
bootstrap contents directly into each index file and remove the
now-unused bootstrap files for comprehensive-demo-react16 and
comprehensive-demo-react18.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…verywhere
- Add experiments: { asyncStartup: true } to all webpack/rspack/rsbuild configs
- Add shareStrategy: 'loaded-first' to all MF plugin configs
- Inline ~155 bootstrap files into their index/main entry files
- Delete all bootstrap files (except umd-federation which uses native MFP)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
| import './bootstrap'; | ||
| import React from 'react'; // Must be imported for webpack to work | ||
|
|
||
| import { ReactDOM, createRoot } from 'react-dom/client'; |
Check notice
Code scanning / CodeQL
Unused variable, import, function or class Note
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 5 days ago
To fix the problem, we should remove the unused ReactDOM named import while keeping the createRoot import intact. This eliminates the unused symbol without changing the program’s behavior.
Concretely, in dashboard-admin-react-rspack-material-ui/faq-app/src/index.js, edit the import on line 3 to only import createRoot from 'react-dom/client'. No other code changes are required, as there are no references to ReactDOM elsewhere in the shown snippet. No additional methods, imports, or definitions are needed.
| @@ -1,6 +1,6 @@ | ||
| import React from 'react'; // Must be imported for webpack to work | ||
|
|
||
| import { ReactDOM, createRoot } from 'react-dom/client'; | ||
| import { createRoot } from 'react-dom/client'; | ||
|
|
||
| import './index.css'; | ||
|
|
| import App from './App'; | ||
| import React from 'react'; | ||
| import ReactDOM from 'react-dom'; | ||
| import lodash from 'lodash'; |
Check notice
Code scanning / CodeQL
Unused variable, import, function or class Note
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 5 days ago
To fix an unused import, remove the import statement if the symbol is never referenced in the file and there are no required side effects. In this case, the lodash default import is not referenced anywhere in federated-npm/app3/src/index.js, and lodash is not being imported for side effects. The best minimal fix is to delete line 4 (import lodash from 'lodash';) and leave the other imports and code intact. No additional methods, imports, or definitions are needed.
| @@ -1,5 +1,4 @@ | ||
| import App from './App'; | ||
| import React from 'react'; | ||
| import ReactDOM from 'react-dom'; | ||
| import lodash from 'lodash'; | ||
| ReactDOM.render(<App />, document.getElementById('root')); |
|
|
||
| ReactDOM.render( | ||
| <React.StrictMode> | ||
| <App /> |
Check notice
Code scanning / CodeQL
Syntax error Note
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 5 days ago
In general, to fix this problem you either (a) configure the project to treat this file as TSX (e.g., rename to .tsx and ensure jsx is enabled), or (b) remove JSX syntax from .ts files and use React.createElement / ReactDOM.createRoot (or ReactDOM.render) calls instead. Since we are constrained to editing only this file and cannot rename it or adjust configuration, the best fix is to replace the JSX tree in the ReactDOM.render call with the equivalent React.createElement calls, preserving all existing behavior.
Concretely, in native-federation-react/host/src/app.ts, replace lines 11–13:
<React.StrictMode>
<App />
</React.StrictMode>,with a React.createElement expression that constructs the same component tree without JSX, e.g.:
React.createElement(
React.StrictMode,
null,
React.createElement(App)
),This keeps the call to ReactDOM.render intact, preserves the StrictMode wrapper and App rendering, and uses only plain TypeScript/JavaScript syntax. No additional imports or definitions are needed, because React and App are already imported.
| @@ -8,9 +8,11 @@ | ||
| // import "./index.css"; | ||
|
|
||
| ReactDOM.render( | ||
| <React.StrictMode> | ||
| <App /> | ||
| </React.StrictMode>, | ||
| React.createElement( | ||
| React.StrictMode, | ||
| null, | ||
| React.createElement(App) | ||
| ), | ||
| document.getElementById('root'), | ||
| ); | ||
|
|
| ReactDOM.render( | ||
| <React.StrictMode> | ||
| <App /> | ||
| </React.StrictMode>, |
Check notice
Code scanning / CodeQL
Syntax error Note
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 5 days ago
To fix the parsing error without relying on JSX support, replace the JSX-based call to ReactDOM.render with an equivalent that uses React.createElement. JSX is syntactic sugar for React.createElement, so this preserves functionality while avoiding the / that the non‑JSX parser misinterprets. Specifically, change the ReactDOM.render call on lines 10–15 from:
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root'),
);to an explicit React.createElement tree:
ReactDOM.render(
React.createElement(
React.StrictMode,
null,
React.createElement(App, null),
),
document.getElementById('root'),
);No new imports are needed because React is already imported and provides createElement. All other parts of the file (date-fns usage and the async IIFE using loadRemoteModule) remain unchanged.
| @@ -8,9 +8,11 @@ | ||
| // import "./index.css"; | ||
|
|
||
| ReactDOM.render( | ||
| <React.StrictMode> | ||
| <App /> | ||
| </React.StrictMode>, | ||
| React.createElement( | ||
| React.StrictMode, | ||
| null, | ||
| React.createElement(App, null), | ||
| ), | ||
| document.getElementById('root'), | ||
| ); | ||
|
|
| <React.StrictMode> | ||
| <App /> | ||
| </React.StrictMode>, | ||
| document.getElementById('root'), |
Check notice
Code scanning / CodeQL
Syntax error Note
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 5 days ago
In general, to fix this problem you should make the ReactDOM.render call conform to the syntax rules of the parser used by CodeQL, removing the trailing comma after the last argument so it no longer expects an additional argument or comma.
Concretely, in native-federation-react/host/src/app.ts, locate the ReactDOM.render invocation at lines 10–15. The second argument line currently reads document.getElementById('root'), with a trailing comma. Remove that trailing comma so that the function call has exactly two arguments and ends with document.getElementById('root') followed by the closing parenthesis and semicolon on the next line. No imports, methods, or definitions need to be added; this is purely a minor syntactic adjustment that preserves existing behavior.
| @@ -11,7 +11,7 @@ | ||
| <React.StrictMode> | ||
| <App /> | ||
| </React.StrictMode>, | ||
| document.getElementById('root'), | ||
| document.getElementById('root') | ||
| ); | ||
|
|
||
| const isoDate = '2023-01-01'; |
|
|
||
| const root = document.getElementById('root'); | ||
| if (root) { | ||
| render(<App />, root); |
Check notice
Code scanning / CodeQL
Syntax error Note
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 5 days ago
In general, to fix this problem you should avoid using JSX syntax in a .ts file that is not configured for JSX, and instead use the appropriate Preact/React API (h, createElement, or render’s overload) to construct elements. This keeps the code valid TypeScript without requiring changes to the build configuration or file extensions.
The best targeted fix here is to replace the JSX <App /> with a non-JSX call that creates the same virtual node. In Preact, render accepts a VNode as its first argument, and App can usually be invoked as a function component: render(App({}), root) or render(h(App, {}), root). Since we want to avoid adding new imports or changing existing ones, we should use App({}) directly, which is valid for function components and does not rely on JSX or extra imports. This leaves behavior effectively unchanged: it still renders the App component into root, but avoids JSX syntax that CodeQL flags.
Concretely, in react-preact-runtime-typescript/remote/src/index.ts, on line 6, replace render(<App />, root); with render(App({}), root);. No additional imports or definitions are required, and no other lines in the snippet need modification.
| @@ -3,5 +3,5 @@ | ||
|
|
||
| const root = document.getElementById('root'); | ||
| if (root) { | ||
| render(<App />, root); | ||
| render(App({}), root); | ||
| } |
| const root = ReactDOM.createRoot(rootEl); | ||
| root.render( | ||
| <React.StrictMode> | ||
| <App /> |
Check notice
Code scanning / CodeQL
Syntax error Note
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 5 days ago
In general, the error occurs because JSX syntax (<React.StrictMode> and <App />) is not valid in a .ts file parsed as plain TypeScript. To fix this without changing project configuration or file extensions, replace the JSX with equivalent calls to React.createElement. This preserves existing functionality while eliminating JSX syntax so the TypeScript parser (and CodeQL) see only standard TypeScript.
Concretely, in react-preact-runtime-typescript/shell/src/index.ts, lines 8–12 where root.render currently receives a JSX tree should be changed so that root.render instead receives a React.createElement call that constructs the same element hierarchy: React.createElement(React.StrictMode, null, React.createElement(App)). No new imports or other changes are needed, as React and App are already imported. All other lines remain unchanged.
| @@ -6,8 +6,10 @@ | ||
| if (rootEl) { | ||
| const root = ReactDOM.createRoot(rootEl); | ||
| root.render( | ||
| <React.StrictMode> | ||
| <App /> | ||
| </React.StrictMode>, | ||
| React.createElement( | ||
| React.StrictMode, | ||
| null, | ||
| React.createElement(App), | ||
| ), | ||
| ); | ||
| } |
| root.render( | ||
| <React.StrictMode> | ||
| <App /> | ||
| </React.StrictMode>, |
Check notice
Code scanning / CodeQL
Syntax error Note
|
|
||
| console.log('testValue in main thread', testValue); | ||
|
|
||
| const worker = new SharedWorker(new URL('./worker', import.meta.url)); |
Check notice
Code scanning / CodeQL
Unused variable, import, function or class Note
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 5 days ago
In general, to fix an unused variable warning, either remove the variable declaration (and any associated computation) if it’s not needed, or start using the variable if it was meant to be used. Here, the SharedWorker instantiation is likely needed, but the binding to worker is not, since worker is never referenced.
The best minimal fix is to remove the const worker = part while keeping the new SharedWorker(...) expression. This keeps the side effect of creating the worker while eliminating the unused variable. Concretely, in react-sharedworker/host/src/index.js, change line 5 from const worker = new SharedWorker(new URL('./worker', import.meta.url)); to just new SharedWorker(new URL('./worker', import.meta.url));. No new imports, methods, or additional definitions are required.
| @@ -2,4 +2,4 @@ | ||
|
|
||
| console.log('testValue in main thread', testValue); | ||
|
|
||
| const worker = new SharedWorker(new URL('./worker', import.meta.url)); | ||
| new SharedWorker(new URL('./worker', import.meta.url)); |
| @@ -1 +1,7 @@ | |||
| import './bootstrap'; | |||
| import React, { Suspense } from 'react'; | |||
Check notice
Code scanning / CodeQL
Unused variable, import, function or class Note
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 5 days ago
In general, to fix unused import issues, you either remove the unused bindings or start using them in the code. Here, the best fix without changing functionality is to remove the unused named import Suspense and keep only what is actually used.
Specifically, in rust-wasm/host/src/index.js, line 1 should be changed from import React, { Suspense } from 'react'; to import React from 'react';. No other lines in this file need modification. No additional methods, imports, or definitions are required, because Suspense is not referenced anywhere in the shown code.
| @@ -1,4 +1,4 @@ | ||
| import React, { Suspense } from 'react'; | ||
| import React from 'react'; | ||
| import ReactDOM from 'react-dom'; | ||
| import App from './app.jsx'; | ||
|
|
- Switch react-storybook, clo, modernjs, modernjs-classic-tractor-example, and quasar configs from native webpack/rspack container MFP to @module-federation/enhanced with asyncStartup + shareStrategy - Fix federated-npm app1 runtime plugin: remove beforeLoadShare busy-wait loop that hangs with asyncStartup timing - Add @module-federation/enhanced dependency to react-storybook packages Pre-existing failures (not caused by this PR): - rspack-webpack-offload: "Can not get 'react'" error exists on prior commit - rust-wasm: CI timeout (30min) is an infrastructure issue Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The import:false shared config requires version-first strategy because loaded-first skips remote initialization during sharing init, causing "Can not get 'react'" errors when the share scope is empty. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use the official Modern.js integration plugin instead of manually configuring @module-federation/enhanced/rspack in tools.rspack. This follows the recommended pattern from the Module Federation docs for Modern.js applications. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ugin Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ted builder-rspack-provider - Remove @modern-js/builder-rspack-provider (deprecated, built into appTools) - Upgrade bi-directional apps to @modern-js/app-tools 2.70.4 - Remove unused @module-federation/enhanced from bi-directional - Add 22 missing example directories to pnpm-workspace.yaml - Add modernjs-classic-tractor-example to workspace Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Align runtime-plugin examples with enhanced federation + asyncStartup (remoteType script, uniqueName/library globals) - Fix Playwright strict locator issues - Fix rust-wasm devserver overlay + JSX parsing - Fix quasar sass compiler config
These files are generated by Quasar and should not be committed.
- Keep .quasar ignored/untracked - Use src/mf-bootstrap.js as stable async entry instead of .quasar/main.js
Reverts using .quasar/client-entry.js as direct entry; keep a stable src bootstrap while leaving .quasar untracked.
Split quasar playwright webServer into per-app entries so both ports are awaited; inline umd-federation/app1 bootstrap and switch to enhanced MFP. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The Enhanced MFP BUILD-001 error in CI suggests the relative expose paths cannot be resolved in that environment. Using path.resolve removes any ambiguity about the webpack context directory. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…mples Enhanced MFP has two incompatibilities: - quasar: BUILD-001 in CI when exposing .vue files through Quasar's webpack pipeline - umd-federation: manifest module crashes on UmdPlugin's remote modules (Cannot read 'alias' of undefined) Revert both to native ModuleFederationPlugin. For quasar, resolve MFP from @quasar/app-webpack's own webpack to avoid pnpm dual-instance Compilation mismatch. For umd-federation, restore the bootstrap pattern required by native MFP's shared module loading. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The Enhanced MFP manifest plugin is incompatible with both examples: - quasar: containerManager transforms exposes and triggers BUILD-001 in CI when processing .vue files - umd-federation: manifest StatsPlugin crashes on UmdPlugin remote modules (missing 'alias' property) Setting manifest:false disables the problematic code paths while keeping enhanced MFP features (shareStrategy, asyncStartup). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…le UMD example Quasar: Enhanced MFP's ContainerEntryModule fails to resolve .vue files directly as exposes in CI (BUILD-001). Add intermediary .js wrapper files in src/exposes/ that re-export the .vue components, avoiding the CI-only resolution issue. umd-federation: Revert to native webpack MFP + bootstrap pattern because Enhanced MFP's bundler runtime overwrites __webpack_require__.f.remotes, breaking UmdPlugin's SystemJS-based remote loading. Both e2e suites verified passing locally. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The Quasar CLI does not set cfg.context in its webpack config, leaving it undefined. Enhanced MFP's ContainerPlugin uses compilation.options.context for resolving expose module paths. Explicitly setting cfg.context to __dirname ensures the compiler has the correct base directory. Also switch exposes to absolute paths and add debug logging to diagnose the CI-only BUILD-001 error. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
… instance Enhanced MFP's ContainerExposedDependency eagerly loads webpack's ModuleDependency at module scope via normalizeWebpackPath(). Without FEDERATION_WEBPACK_PATH set at that point, pnpm resolves to the hoisted node_modules/webpack, while Quasar's compiler uses a different webpack instance from @quasar/app-webpack's dependency tree. This class identity mismatch causes moduleGraph.getModule(dep) to return null, triggering BUILD-001 errors in CI. Fix: resolve webpack from @quasar/app-webpack's real path and set the env var before requiring @module-federation/enhanced. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Temporary: add module/entry success/failure hooks and swap expose order to determine if BUILD-001 follows the first position or the HomePage module. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Check dependency factory registration, class identity, expose module presence in module graph, and ContainerEntryModule block resolution. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
With asyncStartup enabled, the MF runtime already handles the async boundary for shared module negotiation. Using a dynamic import() in the entry (mf-bootstrap.js) created a redundant async boundary that prevented webpack from resolving ContainerExposedDependencies in CI. Switch to a static import and remove diagnostic plugins. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
With asyncStartup enabled, the MF runtime handles the async boundary for shared module negotiation automatically. The custom mf-bootstrap.js entry override caused BUILD-001 in CI by interfering with how webpack processes ContainerExposedDependencies. Remove the entry override and let Quasar use its generated .quasar/client-entry.js directly. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Quasar CLI doesn't set cfg.context in its webpack config, so webpack falls back to process.cwd(). The Enhanced MFP's ContainerPlugin uses compilation.options.context for resolving expose entry dependencies. Without proper context, pnpm's strict resolution in CI prevents ContainerExposedDependencies from being resolved, causing BUILD-001. Set cfg.context = __dirname in extendWebpack for both apps. Remove the FEDERATION_WEBPACK_PATH workaround and debug logging (CI diagnostics confirmed webpack identity is already correct). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The Enhanced ModuleFederationPlugin's ContainerEntryModule has a fatal process.exit(1) check (BUILD-001) that fails under @quasar/app-webpack's compilation environment in CI, where expose module resolution timing differs from standard webpack setups. Switch to native webpack container.ModuleFederationPlugin with bootstrap entry files for the async boundary. Resolve webpack from @quasar/app-webpack's dependency tree to avoid class identity mismatches in pnpm. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Resolve ModuleFederationPlugin directly from @quasar/app-webpack's dependency tree to avoid class identity mismatches in pnpm. Use eager shared modules so no async bootstrap boundary is needed, allowing Quasar's default entry to work unmodified. Remove bootstrap files. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The asyncStartup experiment creates a second ContainerEntryModule that interferes with exposed module building under @quasar/app-webpack's compilation environment, triggering a fatal BUILD-001 process.exit(1). Use Enhanced MFP with shareStrategy: 'loaded-first' but without asyncStartup, and keep bootstrap files to provide the async boundary for shared module negotiation. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Summary
bootstrap.*files into their correspondingindex/mainentry files and delete themexperiments: { asyncStartup: true }to all@module-federation/enhancedwebpack/rspack/rsbuild configsshareStrategy: 'loaded-first'to all Module Federation plugin configsWith
experiments: { asyncStartup: true }, Module Federation handles the async boundary internally, making the manualimport('./bootstrap')wrapper unnecessary. This removes the indirection across all examples in the repo.Scope
70+ example projects across the full repo, including:
advanced-api/*(automatic-vendor-sharing, dynamic-remotes, dynamic-remotes-runtime-environment-variables, dynamic-remotes-synchronous-imports)apollo-client/*clo/*,cra/*cloud/azure-functions-node-v4/*complete-react-case/*,comprehensive-demo-react16/*,comprehensive-demo-react18/*css-isolation/*,dashboard-admin-react-rspack-material-ui/*different-react-versions/*(all variants: base, 16-17-typescript, 16-18, isolated, typescript)dynamic-system-host/*,error-boundary/*federated-css/*(consumers-react and expose-remotes)federated-css-react-ssr/*,federated-library-from-cdn/*,federated-npm/*frontend-discovery-service/*,native-federation-react/*,native-federation-tests-typescript-plugins/*nested-remote/*,nextjs-host-react-remote/*react-16-17-18-ssr/*,react-18-code-splitting/*,react-18-server-2-server/*,react-18-ssr/*react-in-vue/*,react-livereload/*,react-manifest-example/*react-nextjs/*,react-preact-runtime-typescript/*react-sharedworker/*(both main bootstrap and worker bootstrap)react-storybook/*,react-webpack-host-vite-remote/*redux-reducer-injection/*,rsbuild-vue3-vuex/*rspack_hmr/*,rspack-webpack-interop/*,rspack-webpack-offload/*runtime-plugins/*(control-sharing, isolate-shared-dependencies, multiple-react-versions, offline-remote, remote-control, remote-router, single-runtime)rust-wasm/*,self-healing/*,server-side-rendering/*shared-context/*,shared-directory/*,shared-routes2/*,shared-routing/*shared-store-cross-framework/*,simple-node/*,third-party-scripts/*typescript/*,typescript-monorepo/*,typescript-project-references/*,typescript-react-fallback/*typescript-react-monorepo/*,typescript-react-monorepo-test/*vue-cli/*,vue2-in-vue3/*basic-host-remote/*,i18next-nextjs-react/*,modernjs/*,modernjs-classic-tractor-example/*,modernjs-ssr/*,quasar-cli-vue3-webpack-javascript/*,server-side-render-only/*,vue3-cli-demo/*Exclusions
umd-federation/app1— uses nativewebpack.container.ModuleFederationPlugin(no asyncStartup support), bootstrap pattern still requiredangular-universal-ssr—server-bootstrap.tsis a server-side Express setup, not an MF async boundaryTest plan
bootstrap.*files exist (exceptumd-federation/app1andangular-universal-ssr)import('./bootstrap')references (except exclusions above)🤖 Generated with Claude Code