diff --git a/packages/examples/react-vite-dynamic/README.md b/packages/examples/react-vite-dynamic/README.md
new file mode 100644
index 00000000..ef5e2f34
--- /dev/null
+++ b/packages/examples/react-vite-dynamic/README.md
@@ -0,0 +1,14 @@
+# React - Vite Federation Demo
+
+This example demos consumption of federated modules from a vite bundle. `host` (react based) depends on a component exposed by `remote` app (react based).
+
+## Running
+
+Install `pnpm` as per instructions provided [here](https://pnpm.io/installation)
+
+Run `pnpm install`, then `pnpm run build` and `pnpm run serve`. This will build and serve both `host` and `remote` on ports 5000, 5001 respectively.
+
+- HOST: [localhost:5000](http://localhost:5000/)
+- REMOTE: [localhost:5001](http://localhost:5001/)
+
+`CTRL + C` can only stop the host server. You can run `pnpm stop` to stop all services.
diff --git a/packages/examples/react-vite-dynamic/__tests__/react-vite.spec.ts b/packages/examples/react-vite-dynamic/__tests__/react-vite.spec.ts
new file mode 100644
index 00000000..d5b3e742
--- /dev/null
+++ b/packages/examples/react-vite-dynamic/__tests__/react-vite.spec.ts
@@ -0,0 +1,22 @@
+import { browserLogs, page } from '~utils'
+import { expect, test } from 'vitest'
+
+test('should have no 404s', () => {
+ browserLogs.forEach((msg) => {
+ expect(msg).not.toMatch('404')
+ })
+})
+
+test('remote button', async () => {
+ expect(
+ await page.textContent('#click-btn')
+ ).toBe('Click me: 0')
+})
+
+test('click event', async () => {
+ await page.click('#click-btn');
+ expect(
+ await page.textContent('#click-btn')
+ ).toBe('Click me: 1')
+})
+
diff --git a/packages/examples/react-vite-dynamic/host/index.html b/packages/examples/react-vite-dynamic/host/index.html
new file mode 100644
index 00000000..79c47019
--- /dev/null
+++ b/packages/examples/react-vite-dynamic/host/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ Vite + React
+
+
+
+
+
+
diff --git a/packages/examples/react-vite-dynamic/host/package.json b/packages/examples/react-vite-dynamic/host/package.json
new file mode 100644
index 00000000..a334cbce
--- /dev/null
+++ b/packages/examples/react-vite-dynamic/host/package.json
@@ -0,0 +1,23 @@
+{
+ "name": "@react-vite-dynamic/app",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite --port 5000 --strictPort",
+ "build": "vite build",
+ "preview": "vite preview --port 5000 --strictPort",
+ "serve": "vite preview --port 5000 --strictPort"
+ },
+ "dependencies": {
+ "@originjs/vite-plugin-federation": "^1.2.3",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0"
+ },
+ "devDependencies": {
+ "@types/react": "^18.0.17",
+ "@types/react-dom": "^18.0.6",
+ "@vitejs/plugin-react": "^3.0.0",
+ "vite": "^4.3.2"
+ }
+}
diff --git a/packages/examples/react-vite-dynamic/host/public/vite.svg b/packages/examples/react-vite-dynamic/host/public/vite.svg
new file mode 100644
index 00000000..e7b8dfb1
--- /dev/null
+++ b/packages/examples/react-vite-dynamic/host/public/vite.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/packages/examples/react-vite-dynamic/host/src/App.css b/packages/examples/react-vite-dynamic/host/src/App.css
new file mode 100644
index 00000000..2c5e2ef5
--- /dev/null
+++ b/packages/examples/react-vite-dynamic/host/src/App.css
@@ -0,0 +1,41 @@
+#root {
+ max-width: 1280px;
+ margin: 0 auto;
+ padding: 2rem;
+ text-align: center;
+}
+
+.logo {
+ height: 6em;
+ padding: 1.5em;
+ will-change: filter;
+}
+.logo:hover {
+ filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+ filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+ from {
+ transform: rotate(0deg);
+ }
+ to {
+ transform: rotate(360deg);
+ }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+ a:nth-of-type(2) .logo {
+ animation: logo-spin infinite 20s linear;
+ }
+}
+
+.card {
+ padding: 2em;
+}
+
+.read-the-docs {
+ color: #888;
+}
diff --git a/packages/examples/react-vite-dynamic/host/src/App.jsx b/packages/examples/react-vite-dynamic/host/src/App.jsx
new file mode 100644
index 00000000..e5ffaeec
--- /dev/null
+++ b/packages/examples/react-vite-dynamic/host/src/App.jsx
@@ -0,0 +1,30 @@
+import reactLogo from './assets/react.svg'
+import './App.css'
+import {RemoteButton} from "./RemoteComponent.jsx";
+
+function App() {
+ return (
+
+
+
Vite + React
+
+
+
+ Edit src/App.jsx
and save to test HMR
+
+
+
+ Click on the Vite and React logos to learn more
+
+
+ )
+}
+
+export default App
diff --git a/packages/examples/react-vite-dynamic/host/src/RemoteComponent.jsx b/packages/examples/react-vite-dynamic/host/src/RemoteComponent.jsx
new file mode 100644
index 00000000..581c87d2
--- /dev/null
+++ b/packages/examples/react-vite-dynamic/host/src/RemoteComponent.jsx
@@ -0,0 +1,74 @@
+import {lazy, Suspense} from "react";
+import {ErrorBoundary} from "react-error-boundary";
+
+const remotesMap = {};
+// const __vite__import = name => import(/* @vite-ignore */name);
+
+const shareScope = {
+ // 'react': {
+ // 'default': {
+ // get: () => __vite__import('http://localhost:5001/assets/__federation_shared_react.js'),
+ // loaded: 1
+ // }
+ // },
+ // 'react-dom': {
+ // 'default': {
+ // get: () => __vite__import('http://localhost:5001/assets/__federation_shared_react-dom.js'),
+ // loaded: 1
+ // }
+ // },
+};
+
+if (!globalThis.__federation_shared__){
+ globalThis.__federation_shared__=shareScope
+}
+var __federation__ = {
+ ensure: async (remoteId) => {
+ const remote = remotesMap[remoteId];
+ if (remote.inited) {
+ return remote.lib;
+ }
+ return new Promise((resolve) => {
+ // debugger;
+ import(/* @vite-ignore */ remote.url).then((lib) => {
+ debugger;
+ console.log('lib', lib);
+ if (!remote.inited) {
+ lib.init(globalThis.__federation_shared__);
+ remote.lib = lib;
+ remote.inited = true;
+ }
+ resolve(remote.lib);
+ });
+ });
+ },
+};
+const loadComponent = (url, scope, module) => async () => {
+ remotesMap[scope] = {
+ url: url,
+ };
+
+ return __federation__.ensure(scope).then((remote) => remote.get(module).then((factory) => factory()));
+};
+
+const ModuleLoader = ({module, props, scope, url}) => {
+ if (!module) {
+ return Module name cannot be empty;
+ }
+
+ const Component = lazy(loadComponent(url, scope, module));
+
+ return (
+ Loading...>}>
+
+
+ );
+};
+
+export const RemoteButton = () => {
+ const url = 'http://localhost:5001/assets/remoteEntry.js'
+
+ return Failed to load remote component...>}>
+
+
+}
diff --git a/packages/examples/react-vite-dynamic/host/src/assets/react.svg b/packages/examples/react-vite-dynamic/host/src/assets/react.svg
new file mode 100644
index 00000000..6c87de9b
--- /dev/null
+++ b/packages/examples/react-vite-dynamic/host/src/assets/react.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/packages/examples/react-vite-dynamic/host/src/index.css b/packages/examples/react-vite-dynamic/host/src/index.css
new file mode 100644
index 00000000..917888c1
--- /dev/null
+++ b/packages/examples/react-vite-dynamic/host/src/index.css
@@ -0,0 +1,70 @@
+:root {
+ font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
+ font-size: 16px;
+ line-height: 24px;
+ font-weight: 400;
+
+ color-scheme: light dark;
+ color: rgba(255, 255, 255, 0.87);
+ background-color: #242424;
+
+ font-synthesis: none;
+ text-rendering: optimizeLegibility;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-text-size-adjust: 100%;
+}
+
+a {
+ font-weight: 500;
+ color: #646cff;
+ text-decoration: inherit;
+}
+a:hover {
+ color: #535bf2;
+}
+
+body {
+ margin: 0;
+ display: flex;
+ place-items: center;
+ min-width: 320px;
+ min-height: 100vh;
+}
+
+h1 {
+ font-size: 3.2em;
+ line-height: 1.1;
+}
+
+button {
+ border-radius: 8px;
+ border: 1px solid transparent;
+ padding: 0.6em 1.2em;
+ font-size: 1em;
+ font-weight: 500;
+ font-family: inherit;
+ background-color: #1a1a1a;
+ cursor: pointer;
+ transition: border-color 0.25s;
+}
+button:hover {
+ border-color: #646cff;
+}
+button:focus,
+button:focus-visible {
+ outline: 4px auto -webkit-focus-ring-color;
+}
+
+@media (prefers-color-scheme: light) {
+ :root {
+ color: #213547;
+ background-color: #ffffff;
+ }
+ a:hover {
+ color: #747bff;
+ }
+ button {
+ background-color: #f9f9f9;
+ }
+}
diff --git a/packages/examples/react-vite-dynamic/host/src/main.jsx b/packages/examples/react-vite-dynamic/host/src/main.jsx
new file mode 100644
index 00000000..9af0bb63
--- /dev/null
+++ b/packages/examples/react-vite-dynamic/host/src/main.jsx
@@ -0,0 +1,10 @@
+import React from 'react'
+import ReactDOM from 'react-dom/client'
+import App from './App'
+import './index.css'
+
+ReactDOM.createRoot(document.getElementById('root')).render(
+
+
+
+)
diff --git a/packages/examples/react-vite-dynamic/host/vite.config.js b/packages/examples/react-vite-dynamic/host/vite.config.js
new file mode 100644
index 00000000..e0fc7580
--- /dev/null
+++ b/packages/examples/react-vite-dynamic/host/vite.config.js
@@ -0,0 +1,21 @@
+import { defineConfig } from 'vite'
+import federation from '@originjs/vite-plugin-federation'
+import react from '@vitejs/plugin-react'
+
+// https://vitejs.dev/config/
+export default defineConfig({
+ plugins: [
+ react(),
+ federation({
+ name: 'app',
+ remotes: {},
+ shared: ['react','react-dom']
+ })
+ ],
+ build: {
+ modulePreload: false,
+ target: 'esnext',
+ minify: false,
+ cssCodeSplit: false
+ }
+})
diff --git a/packages/examples/react-vite-dynamic/package.json b/packages/examples/react-vite-dynamic/package.json
new file mode 100644
index 00000000..d3282093
--- /dev/null
+++ b/packages/examples/react-vite-dynamic/package.json
@@ -0,0 +1,20 @@
+{
+ "name": "react-vite-dynamic",
+ "private": true,
+ "version": "1.0.0",
+ "scripts": {
+ "build": "pnpm --parallel --filter \"./**\" build",
+ "serve": "pnpm --parallel --filter \"./**\" preview",
+ "build:remotes": "pnpm --parallel --filter \"./remote\" build",
+ "serve:remotes": "pnpm --parallel --filter \"./remote\" serve",
+ "dev:hosts": "pnpm --filter \"./host\" dev",
+ "stop": "kill-port --port 5000,5001"
+ },
+ "devDependencies": {
+ "kill-port": "^2.0.1"
+ },
+ "dependencies": {
+ "@originjs/vite-plugin-federation": "^1.2.3",
+ "react-error-boundary": "^4.0.10"
+ }
+}
diff --git a/packages/examples/react-vite-dynamic/pnpm-workspace.yaml b/packages/examples/react-vite-dynamic/pnpm-workspace.yaml
new file mode 100644
index 00000000..0a8dec21
--- /dev/null
+++ b/packages/examples/react-vite-dynamic/pnpm-workspace.yaml
@@ -0,0 +1,3 @@
+packages:
+ - "host"
+ - "remote"
diff --git a/packages/examples/react-vite-dynamic/remote/index.html b/packages/examples/react-vite-dynamic/remote/index.html
new file mode 100644
index 00000000..79c47019
--- /dev/null
+++ b/packages/examples/react-vite-dynamic/remote/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ Vite + React
+
+
+
+
+
+
diff --git a/packages/examples/react-vite-dynamic/remote/package.json b/packages/examples/react-vite-dynamic/remote/package.json
new file mode 100644
index 00000000..6d6f96fb
--- /dev/null
+++ b/packages/examples/react-vite-dynamic/remote/package.json
@@ -0,0 +1,22 @@
+{
+ "name": "@react-vite-dynamic/shared",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite --port 5001 --strictPort",
+ "build": "vite build",
+ "preview": "vite preview --port 5001 --strictPort",
+ "serve": "vite preview --port 5001 --strictPort"
+ },
+ "dependencies": {
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0"
+ },
+ "devDependencies": {
+ "@types/react": "^18.0.17",
+ "@types/react-dom": "^18.0.6",
+ "@vitejs/plugin-react": "^3.0.0",
+ "vite": "^4.3.2"
+ }
+}
\ No newline at end of file
diff --git a/packages/examples/react-vite-dynamic/remote/public/vite.svg b/packages/examples/react-vite-dynamic/remote/public/vite.svg
new file mode 100644
index 00000000..e7b8dfb1
--- /dev/null
+++ b/packages/examples/react-vite-dynamic/remote/public/vite.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/packages/examples/react-vite-dynamic/remote/src/App.css b/packages/examples/react-vite-dynamic/remote/src/App.css
new file mode 100644
index 00000000..2c5e2ef5
--- /dev/null
+++ b/packages/examples/react-vite-dynamic/remote/src/App.css
@@ -0,0 +1,41 @@
+#root {
+ max-width: 1280px;
+ margin: 0 auto;
+ padding: 2rem;
+ text-align: center;
+}
+
+.logo {
+ height: 6em;
+ padding: 1.5em;
+ will-change: filter;
+}
+.logo:hover {
+ filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.react:hover {
+ filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+ from {
+ transform: rotate(0deg);
+ }
+ to {
+ transform: rotate(360deg);
+ }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+ a:nth-of-type(2) .logo {
+ animation: logo-spin infinite 20s linear;
+ }
+}
+
+.card {
+ padding: 2em;
+}
+
+.read-the-docs {
+ color: #888;
+}
diff --git a/packages/examples/react-vite-dynamic/remote/src/App.jsx b/packages/examples/react-vite-dynamic/remote/src/App.jsx
new file mode 100644
index 00000000..475d22e3
--- /dev/null
+++ b/packages/examples/react-vite-dynamic/remote/src/App.jsx
@@ -0,0 +1,33 @@
+import { useState } from 'react'
+import reactLogo from './assets/react.svg'
+import './App.css'
+import { Button } from "./components/Button"
+
+function App() {
+ const [count, setCount] = useState(0)
+
+ return (
+
+
+
Vite + React
+
+
+
+ Edit src/App.jsx
and save to test HMR
+
+
+
+ Click on the Vite and React logos to learn more
+
+
+ )
+}
+
+export default App
diff --git a/packages/examples/react-vite-dynamic/remote/src/assets/react.svg b/packages/examples/react-vite-dynamic/remote/src/assets/react.svg
new file mode 100644
index 00000000..6c87de9b
--- /dev/null
+++ b/packages/examples/react-vite-dynamic/remote/src/assets/react.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/packages/examples/react-vite-dynamic/remote/src/components/Button.css b/packages/examples/react-vite-dynamic/remote/src/components/Button.css
new file mode 100644
index 00000000..7be6694f
--- /dev/null
+++ b/packages/examples/react-vite-dynamic/remote/src/components/Button.css
@@ -0,0 +1,9 @@
+.shared-btn {
+ background-color: skyblue;
+ border: 1px solid white;
+ color: white;
+ padding: 15px 30px;
+ text-align: center;
+ text-decoration: none;
+ font-size: 18px;
+}
\ No newline at end of file
diff --git a/packages/examples/react-vite-dynamic/remote/src/components/Button.jsx b/packages/examples/react-vite-dynamic/remote/src/components/Button.jsx
new file mode 100644
index 00000000..5fa941bd
--- /dev/null
+++ b/packages/examples/react-vite-dynamic/remote/src/components/Button.jsx
@@ -0,0 +1,15 @@
+
+import "./Button.css"
+
+import { useState } from "react"
+
+export const Button = () => {
+ const [state, setState] = useState(0)
+ return (
+
+
+
+ )
+}
+
+export default Button
\ No newline at end of file
diff --git a/packages/examples/react-vite-dynamic/remote/src/index.css b/packages/examples/react-vite-dynamic/remote/src/index.css
new file mode 100644
index 00000000..917888c1
--- /dev/null
+++ b/packages/examples/react-vite-dynamic/remote/src/index.css
@@ -0,0 +1,70 @@
+:root {
+ font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
+ font-size: 16px;
+ line-height: 24px;
+ font-weight: 400;
+
+ color-scheme: light dark;
+ color: rgba(255, 255, 255, 0.87);
+ background-color: #242424;
+
+ font-synthesis: none;
+ text-rendering: optimizeLegibility;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-text-size-adjust: 100%;
+}
+
+a {
+ font-weight: 500;
+ color: #646cff;
+ text-decoration: inherit;
+}
+a:hover {
+ color: #535bf2;
+}
+
+body {
+ margin: 0;
+ display: flex;
+ place-items: center;
+ min-width: 320px;
+ min-height: 100vh;
+}
+
+h1 {
+ font-size: 3.2em;
+ line-height: 1.1;
+}
+
+button {
+ border-radius: 8px;
+ border: 1px solid transparent;
+ padding: 0.6em 1.2em;
+ font-size: 1em;
+ font-weight: 500;
+ font-family: inherit;
+ background-color: #1a1a1a;
+ cursor: pointer;
+ transition: border-color 0.25s;
+}
+button:hover {
+ border-color: #646cff;
+}
+button:focus,
+button:focus-visible {
+ outline: 4px auto -webkit-focus-ring-color;
+}
+
+@media (prefers-color-scheme: light) {
+ :root {
+ color: #213547;
+ background-color: #ffffff;
+ }
+ a:hover {
+ color: #747bff;
+ }
+ button {
+ background-color: #f9f9f9;
+ }
+}
diff --git a/packages/examples/react-vite-dynamic/remote/src/main.jsx b/packages/examples/react-vite-dynamic/remote/src/main.jsx
new file mode 100644
index 00000000..9af0bb63
--- /dev/null
+++ b/packages/examples/react-vite-dynamic/remote/src/main.jsx
@@ -0,0 +1,10 @@
+import React from 'react'
+import ReactDOM from 'react-dom/client'
+import App from './App'
+import './index.css'
+
+ReactDOM.createRoot(document.getElementById('root')).render(
+
+
+
+)
diff --git a/packages/examples/react-vite-dynamic/remote/vite.config.js b/packages/examples/react-vite-dynamic/remote/vite.config.js
new file mode 100644
index 00000000..2d4d045f
--- /dev/null
+++ b/packages/examples/react-vite-dynamic/remote/vite.config.js
@@ -0,0 +1,24 @@
+import { defineConfig } from 'vite'
+import react from '@vitejs/plugin-react'
+import federation from '@originjs/vite-plugin-federation'
+
+// https://vitejs.dev/config/
+export default defineConfig({
+ plugins: [
+ react(),
+ federation({
+ name: "remote_app",
+ filename: "remoteEntry.js",
+ exposes: {
+ './Button': './src/components/Button'
+ },
+ shared: ['react','react-dom']
+ })
+ ],
+ build: {
+ modulePreload: false,
+ target: 'esnext',
+ minify: false,
+ cssCodeSplit: false
+ }
+})