zeppelin-web-angular/projects/zeppelin-react/README.md
React micro-frontend that runs alongside the Angular host via Webpack Module Federation.
| Phase | Scope | Status |
|---|---|---|
| 1 | Webpack 5 + Module Federation setup | Done |
| 1.5 | Published paragraph (pilot) | Done |
| 2 | Notebook and interpreter modules | Planned |
The published paragraph was picked as pilot because it's read-only and has almost no coupling to other modules.
Angular host (port 4200) React remote (port 3001)
┌─────────────────────────┐ ┌─────────────────────────┐
│ paragraph.component.ts │ │ webpack.config.js │
│ loads remoteEntry.js ──┼──────>│ ModuleFederationPlugin │
│ calls mount(el, props) │ │ name: 'reactApp' │
└─────────────────────────┘ │ exposes: │
│ ./PublishedParagraph │
└─────────────────────────┘
remoteEntry.js from the React dev server or production assets.window.reactApp as a Module Federation container.container.get('./PublishedParagraph') to get the module.mount(element, props), which calls createRoot() and renders into the DOM element.Append ?react=true to any published paragraph URL to activate React mode.
Run npm install then npm run dev to start the dev server on http://localhost:3001.
The Angular host must be running on port 4200. From zeppelin-web-angular/, npm start runs both servers together.
From projects/zeppelin-react/, run npm run build. Output goes to dist/. In production, Angular loads remoteEntry.js from /assets/react/ (see environment.prod.ts).
From projects/zeppelin-react/, run npm run lint to check, npm run lint:fix to auto-fix. See .eslintrc.json for rules.
src/
├── components/
│ ├── common/ # Empty, Loading
│ ├── renderers/ # HTMLRenderer, ImageRenderer, TextRenderer
│ └── visualizations/ # TableVisualization, VisualizationControls
├── pages/
│ └── PublishedParagraph.tsx # entry component + mount()
├── templates/
│ └── SingleResultRenderer.tsx # routes result types to renderers
├── utils/ # tableUtils, textUtils, exportFile
└── main.ts # re-exports for Module Federation
src/pages/ExampleFeature.tsx).mount(element, props) function that creates a React root and renders the component.webpack.config.js under exposes:
exposes: {
'./PublishedParagraph': './src/pages/PublishedParagraph',
'./ExampleFeature': './src/pages/ExampleFeature'
}
main.ts:
export { ExampleFeature, mount as mountExampleFeature } from './pages/ExampleFeature';
paragraph.component.ts):
const factory = await container.get('./ExampleFeature');
const { mount } = factory();
mount(hostElement, props);