Skip to content

Conversation

@dididy
Copy link
Contributor

@dididy dididy commented Oct 25, 2025

What is this PR for?

Micro Frontend Migration(Angular to React) Proposal


Summary

  • Implement React-based micro-frontend architecture using Module Federation.
  • Convert published paragraph component to support React rendering.
  • Add environment-based configuration for development and production builds.

Changes

1. React Micro-Frontend Project Setup

  • Created new React project at projects/zeppelin-react/.
  • Configured Webpack Module Federation for micro-frontend architecture.
  • Set up React 18 with TypeScript support.

2. Component Implementation

New React Components:

  • PublishedParagraph: Main entry point for published paragraph rendering.
  • SingleResultRenderer: Template for rendering single paragraph results.

Renderers:

  • HTMLRenderer: Renders HTML content with sanitization.
  • TextRenderer: Renders plain text with ANSI support.
  • ImageRenderer: Renders image outputs.

Visualizations:

  • TableVisualization: Table rendering with sorting, filtering, and export.
  • VisualizationControls: Control panel for table operations.

Common Components:

  • Loading: Loading state indicator.
  • Empty: Empty state display.

3. Angular Integration

  • paragraph.component.ts: Added React widget loading logic via Module Federation.

  • paragraph.component.html: Added React container element.

  • environment.ts / environment.prod.ts: Added reactRemoteEntryUrl configuration.

    • Development: http://localhost:3001/remoteEntry.js
    • Production: /assets/react/remoteEntry.js

4. Build Configuration

  • angular.json: Copy React build output to /assets/react/.

  • webpack.config.js: Configured Module Federation plugin:

    • Dev server: port 3001
    • CORS headers for cross-origin requests
    • Environment-specific publicPath
  • proxy.conf.js: Updated proxy configuration.

5. Package

  • Added React and React-DOM dependencies.
  • Added Webpack and Module Federation plugins.
  • Added Ant Design for React UI components.
  • Added @antv/g2plot for data visualization (also used in Angular version with G2).

License

This PR uses several open-source libraries. The xlsx (v0.18.5) and typescript (v4.6.4) packages are licensed under Apache-2.0, while all other dependencies and devDependencies (such as react, react-dom, antd, @ant-design/icons, etc.) are licensed under MIT. The MIT license is more permissive than Apache-2.0, so including MIT-licensed packages does not violate Apache-2.0 terms. All packages may be used commercially, and license notices should be included when distributing the project.

Technical Details

Module Federation Configuration

// Development: http://localhost:3001/remoteEntry.js
// Production: /assets/react/remoteEntry.js

new ModuleFederationPlugin({
  name: 'reactApp',
  filename: 'remoteEntry.js',
  exposes: {
    './PublishedParagraph': './src/pages/PublishedParagraph'
  }
})

Usage

  • Render published paragraph with React:
    /notebook/{noteId}/paragraph/{paragraphId}?react=true

What type of PR is it?

Improvement

Todos

What is the Jira issue?

ZEPPELIN-6371

How should this be tested?

// Start Zeppelin Server
./mvnw clean install -DskipTests
./mvnw clean package -DskipTests
./bin/zeppelin-daemon.sh start

// Start Zeppelin New UI Client
cd zeppelin-web-angular
nvm use
npm i
npm run start

TextRenderer

http://localhost:4200/#/notebook/2EYDJKFFY/paragraph/20180118-122136_1299905608?react=true

TableVisualization

http://localhost:4200/#/notebook/2EYDJKFFY/paragraph/20180118-122136_1299905608?react=true

ImageRenderer

http://localhost:4200/#/notebook/2F1S9ZY8Z/paragraph/20180117-220535_590781730?react=true

HTMLRenderer - Table

http://localhost:4200/#/notebook/2F1S9ZY8Z/paragraph/paragraph_1580885453474_1167659991?react=true

HTMLRenderer - Script(Bokeh JS)

http://localhost:4200/#/notebook/2F1S9ZY8Z/paragraph/paragraph_1580885707198_-1652524072?react=true

Screenshots (if appropriate)

Questions:

  • Does the license files need to update? No
  • Is there breaking changes for older versions? No
  • Does this needs documentation? No

@dididy dididy force-pushed the feature/micro-frontend branch from 4d444be to e1495e3 Compare October 26, 2025 01:37
@tbonelee tbonelee changed the base branch from master to angular-v13 October 26, 2025 05:59
@dididy dididy force-pushed the feature/micro-frontend branch from e1495e3 to 3570159 Compare October 26, 2025 08:35
@dididy dididy changed the base branch from angular-v13 to master October 26, 2025 08:36
@dididy dididy force-pushed the feature/micro-frontend branch 15 times, most recently from f41c0e3 to 2f2b8d9 Compare October 30, 2025 03:22
@tbonelee
Copy link
Contributor

tbonelee commented Nov 3, 2025

Thank you for the proposal and the PR!

First of all, I agree with the idea of migrating the framework from Angular to React. This change could help lower the barrier for front-end contributions, considering that we currently have few FE committers.

However, since this is quite an epic change, I think it would be good to share this roadmap and gather feedback from Zeppelin developers first.

Below are some examples from previous discussions for reference:

@tbonelee
Copy link
Contributor

tbonelee commented Nov 3, 2025

Additional requests: if you have some time, could you extract the commits which fix the E2E tests into an separate PR?
We could merge that first to fix brokent tests in master branch, and then rebase that change back into this PR.

tbonelee pushed a commit that referenced this pull request Nov 3, 2025
### What is this PR for?
#5111 (comment)

#5108
After upgrading Playwright to the latest version(1.53.2 to 1.56.1), several test cases started failing on WebKit. The issue was resolved by rolling back to the previous minor version(1.55.1).

[related issue]
microsoft/playwright#37766

### What type of PR is it?
Hot Fix

### Todos

### What is the Jira issue?

### How should this be tested?

### Screenshots (if appropriate)

### Questions:
* Does the license files need to update? No
* Is there breaking changes for older versions? No
* Does this needs documentation? No


Closes #5115 from dididy/fix/e2e.

Signed-off-by: ChanHo Lee <chanholee@apache.org>
tbonelee pushed a commit that referenced this pull request Nov 3, 2025
### What is this PR for?
#5111 (comment)

#5108
After upgrading Playwright to the latest version(1.53.2 to 1.56.1), several test cases started failing on WebKit. The issue was resolved by rolling back to the previous minor version(1.55.1).

[related issue]
microsoft/playwright#37766

### What type of PR is it?
Hot Fix

### Todos

### What is the Jira issue?

### How should this be tested?

### Screenshots (if appropriate)

### Questions:
* Does the license files need to update? No
* Is there breaking changes for older versions? No
* Does this needs documentation? No

Closes #5115 from dididy/fix/e2e.

Signed-off-by: ChanHo Lee <chanholee@apache.org>
(cherry picked from commit bf62a2a)
Signed-off-by: ChanHo Lee <chanholee@apache.org>
@dididy dididy force-pushed the feature/micro-frontend branch from 0889582 to cd54756 Compare November 6, 2025 03:01
await page.goto(reactModeUrl);
await waitForZeppelinReady(page);

// URL 이동 완료까지 명시적으로 대기
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a Korean comment.
(I haven't started the review yet, just leaving a quick note.)

Copy link
Contributor

@tbonelee tbonelee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the hard work!

I've pushed a few fixes for type errors, incorrect type definitions that caused the graph.mode value to be read incorrectly, and an issue where table header names were omitted when exporting to an xlsx file.
To address the incorrect type definitions, I replaced the types defined in zeppelin-react with the ones already defined in zeppelin-sdk.

You can check the changes here:
https://github.com/tbonelee/zeppelin/commits/PR_5111-review/

Please take a look and let me know if these changes make sense.

Lastly, it would be great if you could run Prettier once as well. It would add new lines at the EOF automatically.

Details

tbonelee@5772731

  • This fixes type incompatibilies which cause type errors. You could check fixes by running npx tsc --noEmit at the root of the zeppelin-react before and after this commit.

tbonelee@85c40f8

  • This fixes wrong use of Zeppelin related types.
  • It also fixes the bug which could not set current mode in TableVisualization

tbonelee@60ca558

  • Fixed a minor type error.

tbonelee@e954a16

  • Fixed an issue where table header names were omitted.
  • Replace .json_to_sheet() with .aoa_to_sheet().

Comment on lines +103 to +118
test('should enter published paragraph in React mode via URL with react=true', async ({ page }) => {
await test.step('Given I navigate to React mode URL', async () => {
const reactModeUrl = `/#/notebook/${testNotebook.noteId}/paragraph/${testNotebook.paragraphId}?react=true`;
await page.goto(reactModeUrl);
await waitForZeppelinReady(page);

await page.waitForURL(`**/${testNotebook.noteId}/paragraph/${testNotebook.paragraphId}*`, {
timeout: 15000
});
});

await test.step('Then React mode should be active', async () => {
const currentUrl = page.url();
expect(currentUrl).toContain('react=true');
});
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there's no special handling in place, navigating to a URL that includes query parameters will always result in those parameters being present in the final URL. In that case, wouldn't this test always pass regardless of whether React mode is actually active?

It may be better to either remove this test or revise it to validate React mode using a different, more reliable indicator.

Comment on lines +168 to +176
// Only clear output if result exists
if (await paragraphResult.isVisible()) {
const settingsButton = paragraphElement.locator('a[nz-dropdown]');
await settingsButton.click();

const clearOutputButton = page.locator('li.list-item:has-text("Clear output")');
await clearOutputButton.click();
await expect(paragraphResult).toBeHidden();
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think test scenarios should be as deterministic as possible.
Since beforeEach creates a new notebook, we may not need a conditional if block here to clear the output.
It should be sufficient to assert that the paragraph result is hidden with something like expect(paragraphResult).toBeHidden().

showIcon
/>
);
}; No newline at end of file
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A new line at the EOF is needed.

</Typography.Title>
</div>
);
}; No newline at end of file
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A new line at the EOF is needed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should highlight code blocks like the Angular version.
Please check

.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should handle ANSI color escape codes. See

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that, at this point, this doesn’t necessarily need to be a React custom hook and could simply be implemented as a regular utility function.
Do you have any plans for it to hold state or anything similar?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we'd better add a .gitignore file inside zeppelin-react directory to ignore dist and node_modules in zeppelin-react.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants