diff --git a/.github/workflows/CI-CD.yml b/.github/workflows/CI-CD.yml
deleted file mode 100644
index 1807049..0000000
--- a/.github/workflows/CI-CD.yml
+++ /dev/null
@@ -1,27 +0,0 @@
-name: pkg-pr-new - Publish Any Commit
-on: [push, pull_request]
-
-jobs:
- build:
- runs-on: ubuntu-latest
-
- steps:
- - name: Checkout code
- uses: actions/checkout@v4
-
- - run: corepack enable
- - uses: actions/setup-node@v4
- with:
- node-version: 20
- cache: 'pnpm'
-
- - name: Install dependencies
- run: pnpm install
-
- - name: Build
- run: pnpm build
-
- - run: pnpx pkg-pr-new publish --compact
- working-directory: ./lib
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml
new file mode 100644
index 0000000..5add237
--- /dev/null
+++ b/.github/workflows/pr.yml
@@ -0,0 +1,19 @@
+name: Validate PR title
+
+on:
+ pull_request:
+ branches:
+ - main
+
+permissions:
+ pull-requests: read
+
+jobs:
+ ############ SEMANTIC PR TITLE VALIDATION ############
+ semantic-pr:
+ name: Validate PR title
+ runs-on: ubuntu-latest
+ steps:
+ - uses: amannn/action-semantic-pull-request@v5.5.3
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.gitignore b/.gitignore
index 0ae7e5c..2ee0033 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,5 @@
node_modules
-/lib
+dist
+.DS_Store
+.idea
+.__mf__win
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 9cefca0..59b3455 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,7 +1,7 @@
{
"editor.codeActionsOnSave": {
- "source.organizeImports": true,
- "source.fixAll": true
+ "source.organizeImports": "explicit",
+ "source.fixAll": "explicit"
},
"editor.formatOnSave": true
}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 26133cb..463bc58 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,13 @@
# Changelog
+## [1.0.0-alpha-7c3ba59]
+
+### Features
+
+- new configuration based on Module Federation 2.0 via @module-federation/runtime library
+
+# Changelog
+
## [0.2.8]
### Chores
diff --git a/README.md b/README.md
index 6456a59..4dd60d0 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,6 @@
-# Vite/Rollup plugin for Module Federation
+# Vite plugin for Module Federation
+
+[![npm](https://img.shields.io/npm/v/@module-federation/vite.svg)](https://www.npmjs.com/package/@module-federation/vite)
## Reason why 🤔
@@ -9,65 +11,85 @@ This plugin makes Module Federation work together with [Vite](https://vitejs.dev
## Working implementations
-### [React](https://github.com/module-federation/module-federation-examples/tree/master/vite-react-microfrontends)
-### [Svelte](https://github.com/module-federation/module-federation-examples/tree/master/vite-svelte-microfrontends)
-### [Vue](https://github.com/module-federation/module-federation-examples/tree/master/vite-vue-microfrontends)
+### [Vue](https://github.com/gioboa/vue-microfrontend-demo)
+### [React](https://github.com/gioboa/react-microfrontend-demo)
-## Getting started 🚀
+### [More examples here](https://github.com/module-federation/vite/tree/main/examples)
+
+```
+pnpm install && pnpm run dev-vv # vite+vite dev demo
+```
-This plugin is based on top of [native-federation](https://www.npmjs.com/package/@softarc/native-federation) so this library is a [peer dependency](https://docs.npmjs.com/cli/v8/configuring-npm/package-json#peerdependencies).
+```
+pnpm install && pnpm run preview-vv # vite+vite build demo
+```
-You need to extend the Vite configuration with this plugin:
+## Getting started 🚀
-```typescript
+https://module-federation.io/guide/basic/webpack.html
+
+```js
+// vite.config.js
import { defineConfig } from 'vite';
+import vue from '@vitejs/plugin-vue';
import { federation } from '@module-federation/vite';
-import { createEsBuildAdapter } from '@softarc/native-federation-esbuild';
+import topLevelAwait from 'vite-plugin-top-level-await';
// https://vitejs.dev/config/
-export default defineConfig(async ({ command }) => ({
- server: {
- fs: {
- allow: ['.', '../shared'],
- },
- },
+export default defineConfig({
plugins: [
- await federation({
- options: {
- workspaceRoot: __dirname,
- outputPath: 'dist',
- tsConfig: 'tsconfig.json',
- federationConfig: 'module-federation/federation.config.cjs',
- verbose: false,
- dev: command === 'serve',
+ federation({
+ name: 'bbc',
+ remotes: {
+ mfapp01: 'mfapp01@https://unpkg.com/mf-app-01@1.0.9/dist/remoteEntry.js',
+ remote2: 'mfapp02@https://unpkg.com/mf-app-02/dist/remoteEntry.js',
+ remote3:
+ 'remote1@https://unpkg.com/react-manifest-example_remote1@1.0.6/dist/mf-manifest.json',
+ // "remote4": {
+ // entry: "http://localhost:5174/dd/remoteEntry.js",
+ // globalEntryName: "bb",
+ // type: "esm"
+ // }
+ },
+ exposes: {
+ './App': './src/App.vue',
+ },
+ filename: 'dd/remoteEntry.js',
+ shared: {
+ vue: {},
+ react: {
+ requiredVersion: '18',
+ },
},
- adapter: createEsBuildAdapter({ plugins: [...], }),
}),
- [...]
+ // If you set build.target: "chrome89", you can remove this plugin
+ // topLevelAwait(),
],
-}));
+ server: {
+ port: 5173,
+ // dev mode please set origin
+ origin: 'http://localhost:5173',
+ },
+ build: {
+ target: 'chrome89',
+ },
+});
```
-
+## roadmap
-### Define configs
+- ✅ ~~feat: generate mf-manifest.json~~
+- ✅ ~~feat: support chrome plugin~~
-You need to define two different configurations in the `federationConfig` property.
-Here are two examples:
+* ✅ ~~feat: support runtime plugins~~
+* feat: nuxt ssr
-- [host](https://www.npmjs.com/package/@softarc/native-federation#configuring-hosts)
-- [remote](https://www.npmjs.com/package/@softarc/native-federation#configuring-remotes)
-
+- feat: download remote d.ts
+- feat: generate d.ts
+- feat: support @vitejs/plugin-legacy
+- feat: Another plugin, when only some remote modules are started, automatically completes HMR[(#54)](https://github.com/module-federation/vite/issues/54)
### So far so good 🎉
Now you are ready to use Module Federation in Vite!
-
-## Thanks 🤝
-
-Big thanks to:
-
-[Manfred Steyer](https://twitter.com/manfredsteyer), Speaker, Trainer, Consultant and Author with focus on Angular. Google Developer Expert (GDE) and Microsoft MVP.
-
-who collaborate with me to make this possible.
diff --git a/examples/nuxt-vite/nuxt-host/.gitignore b/examples/nuxt-vite/nuxt-host/.gitignore
new file mode 100644
index 0000000..4a7f73a
--- /dev/null
+++ b/examples/nuxt-vite/nuxt-host/.gitignore
@@ -0,0 +1,24 @@
+# Nuxt dev/build outputs
+.output
+.data
+.nuxt
+.nitro
+.cache
+dist
+
+# Node dependencies
+node_modules
+
+# Logs
+logs
+*.log
+
+# Misc
+.DS_Store
+.fleet
+.idea
+
+# Local env files
+.env
+.env.*
+!.env.example
diff --git a/examples/nuxt-vite/nuxt-host/app.vue b/examples/nuxt-vite/nuxt-host/app.vue
new file mode 100644
index 0000000..04857f5
--- /dev/null
+++ b/examples/nuxt-vite/nuxt-host/app.vue
@@ -0,0 +1,21 @@
+
+
+
Nuxt host
+
+
+ Mode1: {{ runtimeConfig.app.buildId ? ' dev ' : ' prod ' }} mode
+
+
+
+
+
+
diff --git a/examples/nuxt-vite/nuxt-host/nuxt.config.ts b/examples/nuxt-vite/nuxt-host/nuxt.config.ts
new file mode 100644
index 0000000..0a98f9d
--- /dev/null
+++ b/examples/nuxt-vite/nuxt-host/nuxt.config.ts
@@ -0,0 +1,33 @@
+import { federation } from '@module-federation/vite';
+import TopAwait from 'vite-plugin-top-level-await';
+
+export default defineNuxtConfig({
+ compatibilityDate: '2024-04-03',
+ debug: true,
+ devtools: { enabled: true },
+ vite: {
+ plugins: [
+ federation({
+ name: 'nuxhost',
+ remotes: {
+ '@namespace/viteViteRemote': 'viteRemote@http://localhost:3000/_nuxt/mf-manifest.json',
+ },
+ filename: 'remoteEntry.js',
+ shared: {
+ // vue: {},
+ },
+ runtimePlugins: ['./utils/mfPlugins'],
+ // exposes: {
+ // "./App": "./App.vue"
+ // }
+ // manifest: {
+ // fileName: "_nuxt/mf-manifest.json",
+ // }
+ }),
+ new TopAwait(),
+ ],
+ build: {
+ target: 'chrome89',
+ },
+ },
+});
diff --git a/examples/nuxt-vite/nuxt-host/package.json b/examples/nuxt-vite/nuxt-host/package.json
new file mode 100644
index 0000000..558a8c9
--- /dev/null
+++ b/examples/nuxt-vite/nuxt-host/package.json
@@ -0,0 +1,20 @@
+{
+ "name": "examples-nuxt-vite-host",
+ "private": true,
+ "type": "module",
+ "scripts": {
+ "build": "nuxt build",
+ "dev": "NODE_OPTIONS=--experimental-vm-modules nuxt dev --experimental-vm-modules --port=3001",
+ "generate": "nuxt generate",
+ "preview": "NITRO_PORT=3001 nuxt preview",
+ "postinstall": "nuxt prepare"
+ },
+ "dependencies": {
+ "nuxt": "^3.13.0",
+ "vue": "latest",
+ "@module-federation/vite": "workspace:*"
+ },
+ "devDependencies": {
+ "vite-plugin-top-level-await": "^1.4.4"
+ }
+}
diff --git a/examples/nuxt-vite/nuxt-host/public/favicon.ico b/examples/nuxt-vite/nuxt-host/public/favicon.ico
new file mode 100644
index 0000000..18993ad
Binary files /dev/null and b/examples/nuxt-vite/nuxt-host/public/favicon.ico differ
diff --git a/examples/nuxt-vite/nuxt-host/public/robots.txt b/examples/nuxt-vite/nuxt-host/public/robots.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/examples/nuxt-vite/nuxt-host/public/robots.txt
@@ -0,0 +1 @@
+
diff --git a/examples/nuxt-vite/nuxt-host/server/tsconfig.json b/examples/nuxt-vite/nuxt-host/server/tsconfig.json
new file mode 100644
index 0000000..b9ed69c
--- /dev/null
+++ b/examples/nuxt-vite/nuxt-host/server/tsconfig.json
@@ -0,0 +1,3 @@
+{
+ "extends": "../.nuxt/tsconfig.server.json"
+}
diff --git a/examples/nuxt-vite/nuxt-host/tsconfig.json b/examples/nuxt-vite/nuxt-host/tsconfig.json
new file mode 100644
index 0000000..a746f2a
--- /dev/null
+++ b/examples/nuxt-vite/nuxt-host/tsconfig.json
@@ -0,0 +1,4 @@
+{
+ // https://nuxt.com/docs/guide/concepts/typescript
+ "extends": "./.nuxt/tsconfig.json"
+}
diff --git a/examples/nuxt-vite/nuxt-host/utils/mfPlugins.js b/examples/nuxt-vite/nuxt-host/utils/mfPlugins.js
new file mode 100644
index 0000000..b36c158
--- /dev/null
+++ b/examples/nuxt-vite/nuxt-host/utils/mfPlugins.js
@@ -0,0 +1,22 @@
+const runtimePlugin = () => {
+ return {
+ name: 'module-federation-example-plugin',
+ beforeInit(args) {
+ return args;
+ },
+ init(args) {
+ console.log('init: ', args);
+ return args;
+ },
+ beforeLoadShare(args) {
+ console.log('beforeLoadShare: ', args);
+ return args;
+ },
+ beforeRequest(args) {
+ console.log('before request hook', args);
+ return args;
+ },
+ };
+};
+
+export default runtimePlugin;
diff --git a/examples/nuxt-vite/nuxt-remote/.gitignore b/examples/nuxt-vite/nuxt-remote/.gitignore
new file mode 100644
index 0000000..4a7f73a
--- /dev/null
+++ b/examples/nuxt-vite/nuxt-remote/.gitignore
@@ -0,0 +1,24 @@
+# Nuxt dev/build outputs
+.output
+.data
+.nuxt
+.nitro
+.cache
+dist
+
+# Node dependencies
+node_modules
+
+# Logs
+logs
+*.log
+
+# Misc
+.DS_Store
+.fleet
+.idea
+
+# Local env files
+.env
+.env.*
+!.env.example
diff --git a/examples/nuxt-vite/nuxt-remote/app.vue b/examples/nuxt-vite/nuxt-remote/app.vue
new file mode 100644
index 0000000..34930cb
--- /dev/null
+++ b/examples/nuxt-vite/nuxt-remote/app.vue
@@ -0,0 +1,14 @@
+
+
+
Nuxt host
+
+
+ Mode: {{ runtimeConfig.app.buildId ? ' dev ' : ' prod ' }} mode
+
+
+
+
+
+
diff --git a/examples/nuxt-vite/nuxt-remote/nuxt.config.ts b/examples/nuxt-vite/nuxt-remote/nuxt.config.ts
new file mode 100644
index 0000000..99cdd3a
--- /dev/null
+++ b/examples/nuxt-vite/nuxt-remote/nuxt.config.ts
@@ -0,0 +1,30 @@
+import { federation } from '@module-federation/vite';
+import TopAwait from 'vite-plugin-top-level-await';
+
+export default defineNuxtConfig({
+ compatibilityDate: '2024-04-03',
+ debug: true,
+ devtools: { enabled: true },
+ vite: {
+ plugins: [
+ federation({
+ name: 'nuxremote',
+ filename: 'remoteEntry.js',
+ shared: {
+ // vue: {},
+ },
+ runtimePlugins: ['./utils/mfPlugins'],
+ exposes: {
+ './app': './app.vue',
+ },
+ manifest: {
+ fileName: '_nuxt/mf-manifest.json',
+ },
+ }),
+ new TopAwait(),
+ ],
+ build: {
+ target: 'chrome89',
+ },
+ },
+});
diff --git a/examples/nuxt-vite/nuxt-remote/package.json b/examples/nuxt-vite/nuxt-remote/package.json
new file mode 100644
index 0000000..25e6f10
--- /dev/null
+++ b/examples/nuxt-vite/nuxt-remote/package.json
@@ -0,0 +1,20 @@
+{
+ "name": "examples-nuxt-vite-remote",
+ "private": true,
+ "type": "module",
+ "scripts": {
+ "build": "nuxt build",
+ "dev": "NODE_OPTIONS=--experimental-vm-modules nuxt dev --experimental-vm-modules",
+ "generate": "nuxt generate",
+ "preview": "nuxt preview --port=3001",
+ "postinstall": "nuxt prepare"
+ },
+ "dependencies": {
+ "@module-federation/vite": "workspace:*",
+ "nuxt": "^3.13.0",
+ "vue": "latest"
+ },
+ "devDependencies": {
+ "vite-plugin-top-level-await": "^1.4.4"
+ }
+}
diff --git a/examples/nuxt-vite/nuxt-remote/public/favicon.ico b/examples/nuxt-vite/nuxt-remote/public/favicon.ico
new file mode 100644
index 0000000..18993ad
Binary files /dev/null and b/examples/nuxt-vite/nuxt-remote/public/favicon.ico differ
diff --git a/examples/nuxt-vite/nuxt-remote/public/robots.txt b/examples/nuxt-vite/nuxt-remote/public/robots.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/examples/nuxt-vite/nuxt-remote/public/robots.txt
@@ -0,0 +1 @@
+
diff --git a/examples/nuxt-vite/nuxt-remote/server/tsconfig.json b/examples/nuxt-vite/nuxt-remote/server/tsconfig.json
new file mode 100644
index 0000000..b9ed69c
--- /dev/null
+++ b/examples/nuxt-vite/nuxt-remote/server/tsconfig.json
@@ -0,0 +1,3 @@
+{
+ "extends": "../.nuxt/tsconfig.server.json"
+}
diff --git a/examples/nuxt-vite/nuxt-remote/tsconfig.json b/examples/nuxt-vite/nuxt-remote/tsconfig.json
new file mode 100644
index 0000000..a746f2a
--- /dev/null
+++ b/examples/nuxt-vite/nuxt-remote/tsconfig.json
@@ -0,0 +1,4 @@
+{
+ // https://nuxt.com/docs/guide/concepts/typescript
+ "extends": "./.nuxt/tsconfig.json"
+}
diff --git a/examples/rust-vite/rust-host/README.md b/examples/rust-vite/rust-host/README.md
new file mode 100644
index 0000000..37b1dd3
--- /dev/null
+++ b/examples/rust-vite/rust-host/README.md
@@ -0,0 +1,29 @@
+# Rsbuild Project
+
+## Setup
+
+Install the dependencies:
+
+```bash
+pnpm install
+```
+
+## Get Started
+
+Start the dev server:
+
+```bash
+pnpm dev
+```
+
+Build the app for production:
+
+```bash
+pnpm build
+```
+
+Preview the production build locally:
+
+```bash
+pnpm preview
+```
diff --git a/examples/rust-vite/rust-host/package.json b/examples/rust-vite/rust-host/package.json
new file mode 100644
index 0000000..c17369f
--- /dev/null
+++ b/examples/rust-vite/rust-host/package.json
@@ -0,0 +1,24 @@
+{
+ "name": "examples-rust-vite-rust",
+ "version": "1.0.0",
+ "scripts": {
+ "dev": "rsbuild dev",
+ "build": "rsbuild build",
+ "preview": "npm run build && rsbuild"
+ },
+ "dependencies": {
+ "@module-federation/enhanced": "0.2.5",
+ "antd": "^5.16.2",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0",
+ "react-router-dom": "^6.22.3",
+ "vue": "^3.4.29"
+ },
+ "devDependencies": {
+ "@rsbuild/core": "0.7.10",
+ "@rsbuild/plugin-react": "0.7.10",
+ "@types/react": "18.3.3",
+ "@types/react-dom": "18.3.0",
+ "typescript": "5.5.3"
+ }
+}
diff --git a/examples/rust-vite/rust-host/rsbuild.config.ts b/examples/rust-vite/rust-host/rsbuild.config.ts
new file mode 100644
index 0000000..0190b81
--- /dev/null
+++ b/examples/rust-vite/rust-host/rsbuild.config.ts
@@ -0,0 +1,48 @@
+import { ModuleFederationPlugin } from '@module-federation/enhanced/rspack';
+import { defineConfig } from '@rsbuild/core';
+import { pluginReact } from '@rsbuild/plugin-react';
+
+export default defineConfig({
+ server: {
+ port: 5172,
+ open: true,
+ },
+ dev: {
+ // It is necessary to configure assetPrefix, and in the production environment, you need to configure output.assetPrefix
+ assetPrefix: 'http://localhost:5172',
+ },
+ tools: {
+ rspack: (config, { appendPlugins }) => {
+ config.output!.uniqueName = 'app1';
+ appendPlugins([
+ new ModuleFederationPlugin({
+ name: 'examples_rust',
+ remotes: {
+ viteRemote: 'http://localhost:5173/dd/remoteEntry.js',
+ },
+ remoteType: 'module',
+ exposes: {
+ './app': './src/app.tsx',
+ },
+ manifest: {
+ filePath: 'manifestpath',
+ },
+ shared: [
+ 'react',
+ 'react-dom',
+ 'vue',
+ // 'antd'
+ ],
+ }),
+ ]);
+ },
+ },
+ plugins: [
+ pluginReact({
+ splitChunks: {
+ react: false,
+ router: false,
+ },
+ }),
+ ],
+});
diff --git a/examples/rust-vite/rust-host/src/App.tsx b/examples/rust-vite/rust-host/src/App.tsx
new file mode 100644
index 0000000..37d47fb
--- /dev/null
+++ b/examples/rust-vite/rust-host/src/App.tsx
@@ -0,0 +1,11 @@
+import ViteApp from 'viteRemote/App';
+
+export default function Button() {
+ return (
+
+ rust host
+
+
+
+ );
+}
diff --git a/examples/rust-vite/rust-host/src/bootstrap.tsx b/examples/rust-vite/rust-host/src/bootstrap.tsx
new file mode 100644
index 0000000..b19d261
--- /dev/null
+++ b/examples/rust-vite/rust-host/src/bootstrap.tsx
@@ -0,0 +1,11 @@
+import React from 'react';
+import ReactDOM from 'react-dom/client';
+import App from './App';
+
+//@ts-ignore
+const root = ReactDOM.createRoot(document.getElementById('root')!);
+root.render(
+
+
+
+);
diff --git a/examples/rust-vite/rust-host/src/env.d.ts b/examples/rust-vite/rust-host/src/env.d.ts
new file mode 100644
index 0000000..b0ac762
--- /dev/null
+++ b/examples/rust-vite/rust-host/src/env.d.ts
@@ -0,0 +1 @@
+///
diff --git a/examples/rust-vite/rust-host/src/index.tsx b/examples/rust-vite/rust-host/src/index.tsx
new file mode 100644
index 0000000..b93c7a0
--- /dev/null
+++ b/examples/rust-vite/rust-host/src/index.tsx
@@ -0,0 +1 @@
+import('./bootstrap');
diff --git a/examples/rust-vite/rust-host/tsconfig.json b/examples/rust-vite/rust-host/tsconfig.json
new file mode 100644
index 0000000..77055e1
--- /dev/null
+++ b/examples/rust-vite/rust-host/tsconfig.json
@@ -0,0 +1,16 @@
+{
+ "compilerOptions": {
+ "baseUrl": "./",
+ "target": "ES2020",
+ "lib": ["DOM", "ES2020"],
+ "module": "ESNext",
+ "jsx": "react-jsx",
+ "strict": true,
+ "skipLibCheck": true,
+ "isolatedModules": true,
+ "resolveJsonModule": true,
+ "moduleResolution": "bundler",
+ "useDefineForClassFields": true
+ },
+ "include": ["src"]
+}
diff --git a/examples/rust-vite/vite-remote/.gitignore b/examples/rust-vite/vite-remote/.gitignore
new file mode 100644
index 0000000..6026b06
--- /dev/null
+++ b/examples/rust-vite/vite-remote/.gitignore
@@ -0,0 +1,26 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+pnpm-lock.yaml
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git a/examples/rust-vite/vite-remote/index.html b/examples/rust-vite/vite-remote/index.html
new file mode 100644
index 0000000..d15bba7
--- /dev/null
+++ b/examples/rust-vite/vite-remote/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ Vite + Vue
+
+
+
+
+
+
diff --git a/examples/rust-vite/vite-remote/package.json b/examples/rust-vite/vite-remote/package.json
new file mode 100644
index 0000000..7bd9e7f
--- /dev/null
+++ b/examples/rust-vite/vite-remote/package.json
@@ -0,0 +1,23 @@
+{
+ "name": "examples-rust-vite-vite",
+ "version": "0.0.3",
+ "type": "module",
+ "scripts": {
+ "dev": "vite --force",
+ "build": "vite build",
+ "preview": "vite build && http-server --cors -p 5173 dist"
+ },
+ "dependencies": {
+ "@module-federation/vite": "workspace:*",
+ "react": "^18.3.1",
+ "react-dom": "^18.2.0",
+ "vue": "^3.4.35",
+ "vue-router": "^4.4.0"
+ },
+ "devDependencies": {
+ "@swc/core": "~1.6.0",
+ "@vitejs/plugin-react": "^4.3.1",
+ "vite": "^5.3.1",
+ "vite-plugin-top-level-await": "^1.4.1"
+ }
+}
diff --git a/examples/rust-vite/vite-remote/src/App.jsx b/examples/rust-vite/vite-remote/src/App.jsx
new file mode 100644
index 0000000..069cb28
--- /dev/null
+++ b/examples/rust-vite/vite-remote/src/App.jsx
@@ -0,0 +1,20 @@
+import Mfapp01App from 'mfapp01/App';
+import R from 'react';
+import RD from 'react-dom';
+import Remote2App from 'remote2/App';
+import Button from 'remote3/button';
+import { ref } from 'vue';
+
+console.log('share vue', ref);
+console.log('share React', R, RD, import('remote3/button'), import('react'));
+
+export default function () {
+ return (
+
+ vite react
+
+
+
+
+ );
+}
diff --git a/examples/rust-vite/vite-remote/src/assets/vue.svg b/examples/rust-vite/vite-remote/src/assets/vue.svg
new file mode 100644
index 0000000..770e9d3
--- /dev/null
+++ b/examples/rust-vite/vite-remote/src/assets/vue.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/examples/rust-vite/vite-remote/src/main.jsx b/examples/rust-vite/vite-remote/src/main.jsx
new file mode 100644
index 0000000..b907c04
--- /dev/null
+++ b/examples/rust-vite/vite-remote/src/main.jsx
@@ -0,0 +1,11 @@
+import React from 'react';
+import ReactDOM from 'react-dom/client';
+import App from './App';
+
+//@ts-ignore
+const root = ReactDOM.createRoot(document.getElementById('app'));
+root.render(
+
+
+
+);
diff --git a/examples/rust-vite/vite-remote/src/mfPlugins.js b/examples/rust-vite/vite-remote/src/mfPlugins.js
new file mode 100644
index 0000000..ef8f547
--- /dev/null
+++ b/examples/rust-vite/vite-remote/src/mfPlugins.js
@@ -0,0 +1,11 @@
+const runtimePlugin = () => {
+ return {
+ name: 'module-federation-example-plugin',
+ beforeRequest(args) {
+ console.log('before request hook');
+ return args;
+ },
+ };
+};
+
+export default runtimePlugin;
diff --git a/examples/rust-vite/vite-remote/src/style.css b/examples/rust-vite/vite-remote/src/style.css
new file mode 100644
index 0000000..bb131d6
--- /dev/null
+++ b/examples/rust-vite/vite-remote/src/style.css
@@ -0,0 +1,79 @@
+:root {
+ font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
+ line-height: 1.5;
+ 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;
+}
+
+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;
+}
+
+.card {
+ padding: 2em;
+}
+
+#app {
+ max-width: 1280px;
+ margin: 0 auto;
+ padding: 2rem;
+ text-align: center;
+}
+
+@media (prefers-color-scheme: light) {
+ :root {
+ color: #213547;
+ background-color: #ffffff;
+ }
+ a:hover {
+ color: #747bff;
+ }
+ button {
+ background-color: #f9f9f9;
+ }
+}
diff --git a/examples/rust-vite/vite-remote/vite.config.js b/examples/rust-vite/vite-remote/vite.config.js
new file mode 100644
index 0000000..dc41bfc
--- /dev/null
+++ b/examples/rust-vite/vite-remote/vite.config.js
@@ -0,0 +1,42 @@
+import { federation } from '@module-federation/vite';
+import react from '@vitejs/plugin-react';
+import { defineConfig } from 'vite';
+import topLevelAwait from 'vite-plugin-top-level-await';
+
+// https://vitejs.dev/config/
+export default defineConfig({
+ server: {
+ open: true,
+ port: 5173,
+ },
+ base: 'http://localhost:5173',
+ plugins: [
+ react(),
+ federation({
+ name: 'viteRemote',
+ remotes: {
+ mfapp01: 'mfapp01@https://unpkg.com/mf-app-01@1.0.11/dist/remoteEntry.js',
+ remote2: 'mfapp02@https://unpkg.com/mf-app-02/dist/remoteEntry.js',
+ remote3:
+ 'remote1@https://unpkg.com/react-manifest-example_remote1@1.0.6/dist/mf-manifest.json',
+ },
+ exposes: {
+ './App': './src/App.jsx',
+ },
+ filename: 'dd/remoteEntry.js',
+ shared: {
+ vue: {},
+ react: {
+ requiredVersion: '18',
+ },
+ 'react-dom': {},
+ },
+ runtimePlugins: ['./src/mfPlugins'],
+ }),
+ // If you set build.target: "chrome89", you can remove this plugin
+ false && topLevelAwait(),
+ ],
+ build: {
+ target: 'chrome89',
+ },
+});
diff --git a/examples/vite-vite/vite-host/.gitignore b/examples/vite-vite/vite-host/.gitignore
new file mode 100644
index 0000000..6026b06
--- /dev/null
+++ b/examples/vite-vite/vite-host/.gitignore
@@ -0,0 +1,26 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+pnpm-lock.yaml
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git a/examples/vite-vite/vite-host/index.html b/examples/vite-vite/vite-host/index.html
new file mode 100644
index 0000000..54331db
--- /dev/null
+++ b/examples/vite-vite/vite-host/index.html
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+ Vite React Host
+
+
+
+
+
+
+
diff --git a/examples/vite-vite/vite-host/package.json b/examples/vite-vite/vite-host/package.json
new file mode 100644
index 0000000..94783f6
--- /dev/null
+++ b/examples/vite-vite/vite-host/package.json
@@ -0,0 +1,29 @@
+{
+ "name": "examples-vite-vite-host",
+ "version": "0.0.3",
+ "type": "module",
+ "scripts": {
+ "dev": "vite --force",
+ "build": "vite build",
+ "preview": "vite build && vite preview"
+ },
+ "dependencies": {
+ "@emotion/react": "^11.13.0",
+ "@emotion/styled": "^11.13.0",
+ "@module-federation/vite": "workspace:*",
+ "@mui/material": "^5.13.4",
+ "ag-grid-community": "^30.2.0",
+ "ag-grid-react": "^30.2.0",
+ "react": "18.3.1",
+ "react-dom": "18.3.1",
+ "styled-components": "5.3.3",
+ "vue": "^3.4.37",
+ "vue-router": "^4.4.3"
+ },
+ "devDependencies": {
+ "@swc/core": "~1.7.10",
+ "@vitejs/plugin-react": "^4.3.1",
+ "vite": "^5.4.0",
+ "vite-plugin-top-level-await": "^1.4.4"
+ }
+}
\ No newline at end of file
diff --git a/examples/vite-vite/vite-host/public/compare.html b/examples/vite-vite/vite-host/public/compare.html
new file mode 100644
index 0000000..f49bc4e
--- /dev/null
+++ b/examples/vite-vite/vite-host/public/compare.html
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+ Vite Mf Compare
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/vite-vite/vite-host/src/App.jsx b/examples/vite-vite/vite-host/src/App.jsx
new file mode 100644
index 0000000..06da0d3
--- /dev/null
+++ b/examples/vite-vite/vite-host/src/App.jsx
@@ -0,0 +1,63 @@
+import Mfapp01App from 'mfapp01/App';
+import R from 'react';
+import RD from 'react-dom/client';
+import Remote2App from 'remote2/App';
+import Button from 'remote3/button';
+
+import App from '@namespace/viteViteRemote';
+import { AgGridDemo } from '@namespace/viteViteRemote/AgGridDemo';
+import App1 from '@namespace/viteViteRemote/App1';
+import { App2 } from '@namespace/viteViteRemote/App2';
+import { EmotionDemo } from '@namespace/viteViteRemote/EmotionDemo';
+import { MuiDemo } from '@namespace/viteViteRemote/MuiDemo';
+import StyledDemo from '@namespace/viteViteRemote/StyledDemo';
+import { ref } from 'vue';
+
+console.log('Share Vue', ref);
+console.log('Share React', R, RD);
+
+export default function () {
+ return (
+
+
+ Vite React (v {R.version}) app running from Host in{' '}
+ {import.meta.env.DEV ? ' Dev ' : ' prod '} mode
+
+
+
+
+
+
Vite Remote Default App
+
+
+
Vite Remote App1
+
+
+
Vite Remote App2
+
+
+
Vite Remote AgGridDemo
+
+
+
Vite Remote MuiDemo
+
+
+
Styled Components Demo
+
+
+
Emotion Styled Components Demo
+
+
+
+
+
Button
+
+
+
Remote2App
+
+
+
Mfapp01App
+
+
+ );
+}
\ No newline at end of file
diff --git a/examples/vite-vite/vite-host/src/assets/vue.svg b/examples/vite-vite/vite-host/src/assets/vue.svg
new file mode 100644
index 0000000..770e9d3
--- /dev/null
+++ b/examples/vite-vite/vite-host/src/assets/vue.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/examples/vite-vite/vite-host/src/main.jsx b/examples/vite-vite/vite-host/src/main.jsx
new file mode 100644
index 0000000..0847c7b
--- /dev/null
+++ b/examples/vite-vite/vite-host/src/main.jsx
@@ -0,0 +1,13 @@
+import React from 'react';
+import ReactDOM from 'react-dom/client';
+import App from './App';
+import './style.css';
+
+//@ts-ignore
+const root = ReactDOM.createRoot(document.getElementById('app'));
+root.render(
+
+ MF HOST Demo
+
+
+);
diff --git a/examples/vite-vite/vite-host/src/mfPlugins.js b/examples/vite-vite/vite-host/src/mfPlugins.js
new file mode 100644
index 0000000..b36c158
--- /dev/null
+++ b/examples/vite-vite/vite-host/src/mfPlugins.js
@@ -0,0 +1,22 @@
+const runtimePlugin = () => {
+ return {
+ name: 'module-federation-example-plugin',
+ beforeInit(args) {
+ return args;
+ },
+ init(args) {
+ console.log('init: ', args);
+ return args;
+ },
+ beforeLoadShare(args) {
+ console.log('beforeLoadShare: ', args);
+ return args;
+ },
+ beforeRequest(args) {
+ console.log('before request hook', args);
+ return args;
+ },
+ };
+};
+
+export default runtimePlugin;
diff --git a/examples/vite-vite/vite-host/src/style.css b/examples/vite-vite/vite-host/src/style.css
new file mode 100644
index 0000000..bb131d6
--- /dev/null
+++ b/examples/vite-vite/vite-host/src/style.css
@@ -0,0 +1,79 @@
+:root {
+ font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
+ line-height: 1.5;
+ 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;
+}
+
+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;
+}
+
+.card {
+ padding: 2em;
+}
+
+#app {
+ max-width: 1280px;
+ margin: 0 auto;
+ padding: 2rem;
+ text-align: center;
+}
+
+@media (prefers-color-scheme: light) {
+ :root {
+ color: #213547;
+ background-color: #ffffff;
+ }
+ a:hover {
+ color: #747bff;
+ }
+ button {
+ background-color: #f9f9f9;
+ }
+}
diff --git a/examples/vite-vite/vite-host/vite.config.js b/examples/vite-vite/vite-host/vite.config.js
new file mode 100644
index 0000000..062e38d
--- /dev/null
+++ b/examples/vite-vite/vite-host/vite.config.js
@@ -0,0 +1,50 @@
+import { federation } from '@module-federation/vite';
+import react from '@vitejs/plugin-react';
+import { defineConfig } from 'vite';
+import topLevelAwait from 'vite-plugin-top-level-await';
+
+// https://vitejs.dev/config/
+export default defineConfig({
+ server: {
+ open: true,
+ port: 5175,
+ },
+ preview: {
+ port: 5175,
+ },
+ // base: 'http://localhost:5175',
+ plugins: [
+ react(),
+ federation({
+ name: 'viteViteHost',
+ remotes: {
+ mfapp01: 'mfapp01@https://unpkg.com/mf-app-01@1.0.11/dist/remoteEntry.js',
+ remote2: 'mfapp02@https://unpkg.com/mf-app-02/dist/remoteEntry.js',
+ remote3:
+ 'remote1@https://unpkg.com/react-manifest-example_remote1@1.0.6/dist/mf-manifest.json',
+ '@namespace/viteViteRemote': 'http://localhost:5176/mf-manifest.json',
+ },
+ filename: 'remoteEntry-[hash].js',
+ manifest: true,
+ shared: {
+ vue: {},
+ 'react/': {
+ requiredVersion: '18',
+ },
+ 'react-dom': {},
+ 'ag-grid-community': {},
+ 'ag-grid-react': {},
+ '@emotion/react': {},
+ 'styled-components': { singleton: true },
+ '@emotion/styled': {},
+ '@mui/material': {},
+ },
+ runtimePlugins: ['./src/mfPlugins'],
+ }),
+ // If you set build.target: "chrome89", you can remove this plugin
+ false && topLevelAwait(),
+ ],
+ build: {
+ target: 'chrome89',
+ },
+});
diff --git a/examples/vite-vite/vite-remote/.gitignore b/examples/vite-vite/vite-remote/.gitignore
new file mode 100644
index 0000000..6026b06
--- /dev/null
+++ b/examples/vite-vite/vite-remote/.gitignore
@@ -0,0 +1,26 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+pnpm-lock.yaml
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git a/examples/vite-vite/vite-remote/index.html b/examples/vite-vite/vite-remote/index.html
new file mode 100644
index 0000000..70fcc41
--- /dev/null
+++ b/examples/vite-vite/vite-remote/index.html
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+ Vite React Remote
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/vite-vite/vite-remote/package.json b/examples/vite-vite/vite-remote/package.json
new file mode 100644
index 0000000..c21ff8a
--- /dev/null
+++ b/examples/vite-vite/vite-remote/package.json
@@ -0,0 +1,30 @@
+{
+ "name": "examples-vite-vite-remote",
+ "version": "0.0.3",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "vite build",
+ "preview": "vite build&&vite preview"
+ },
+ "dependencies": {
+ "@emotion/react": "^11.13.0",
+ "@emotion/styled": "^11.13.0",
+ "@module-federation/vite": "workspace:*",
+ "@mui/material": "^5.13.4",
+ "ag-grid-community": "^30.2.0",
+ "ag-grid-react": "^30.2.0",
+ "react": "18.2.0",
+ "react-dom": "18.2.0",
+ "sass-embedded": "^1.77.8",
+ "styled-components": "5.3.3",
+ "vue": "^3.4.37",
+ "vue-router": "^4.4.3"
+ },
+ "devDependencies": {
+ "@swc/core": "~1.7.10",
+ "@vitejs/plugin-react": "^4.3.1",
+ "vite": "^5.4.0",
+ "vite-plugin-top-level-await": "^1.4.4"
+ }
+}
\ No newline at end of file
diff --git a/examples/vite-vite/vite-remote/public/vite.svg b/examples/vite-vite/vite-remote/public/vite.svg
new file mode 100644
index 0000000..f7aeec4
--- /dev/null
+++ b/examples/vite-vite/vite-remote/public/vite.svg
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/vite-vite/vite-remote/src/AgGridDemo.jsx b/examples/vite-vite/vite-remote/src/AgGridDemo.jsx
new file mode 100644
index 0000000..797e21b
--- /dev/null
+++ b/examples/vite-vite/vite-remote/src/AgGridDemo.jsx
@@ -0,0 +1,37 @@
+import 'ag-grid-community/styles/ag-grid.css';
+import 'ag-grid-community/styles/ag-theme-alpine.css';
+import { AgGridReact } from 'ag-grid-react';
+import { useState } from 'react';
+import './agGrid.css';
+
+
+export const AgGridDemo = ({ }) => {
+ const [rowData] = useState([
+ { make: 'Toyota', model: 'Celica', price: 35000 },
+ { make: 'Ford', model: 'Mondeo', price: 32000 },
+ { make: 'Porsche', model: 'Boxter', price: 72000 },
+ ]);
+
+ const [columnDefs] = useState([{ field: 'make' }, { field: 'model' }, { field: 'price' }]);
+
+ return (
+
+ );
+};
\ No newline at end of file
diff --git a/examples/vite-vite/vite-remote/src/App.css b/examples/vite-vite/vite-remote/src/App.css
new file mode 100644
index 0000000..d59a1cb
--- /dev/null
+++ b/examples/vite-vite/vite-remote/src/App.css
@@ -0,0 +1,37 @@
+.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;
+ }
\ No newline at end of file
diff --git a/examples/vite-vite/vite-remote/src/App.jsx b/examples/vite-vite/vite-remote/src/App.jsx
new file mode 100644
index 0000000..1faa18f
--- /dev/null
+++ b/examples/vite-vite/vite-remote/src/App.jsx
@@ -0,0 +1,29 @@
+import { useState } from 'react';
+import './App.css';
+import reactLogo from './assets/react.svg';
+// import viteLogo from './assets/vite.svg';
+
+function App() {
+ const [count, setCount] = useState(0);
+
+ return (
+
+
+
Vite + React
+
+
+ Edit src/App.jsx
and save to test HMR
+
+
+
+ );
+}
+
+export default App;
\ No newline at end of file
diff --git a/examples/vite-vite/vite-remote/src/App1.jsx b/examples/vite-vite/vite-remote/src/App1.jsx
new file mode 100644
index 0000000..bbe3ec5
--- /dev/null
+++ b/examples/vite-vite/vite-remote/src/App1.jsx
@@ -0,0 +1,12 @@
+import React from 'react';
+import vueImg from "./assets/vue.svg";
+
+export default function () {
+ return (
+
+
+ Vite React App1 as default export via remote in
+
{import.meta.env.DEV ? ' Dev ' : ' prod '} mode
+
+ );
+}
diff --git a/examples/vite-vite/vite-remote/src/App2.jsx b/examples/vite-vite/vite-remote/src/App2.jsx
new file mode 100644
index 0000000..684ca63
--- /dev/null
+++ b/examples/vite-vite/vite-remote/src/App2.jsx
@@ -0,0 +1,12 @@
+import React from 'react';
+import ReactDOM from 'react-dom/client';
+import "./app2.sass";
+
+console.log("App2 shared React", React, ReactDOM)
+export function App2() {
+ return (
+
+ Vite react (v. {React.version})App2 as named export via remote with Sass use
+
+ );
+}
diff --git a/examples/vite-vite/vite-remote/src/EmotionDemo.jsx b/examples/vite-vite/vite-remote/src/EmotionDemo.jsx
new file mode 100644
index 0000000..93afbf1
--- /dev/null
+++ b/examples/vite-vite/vite-remote/src/EmotionDemo.jsx
@@ -0,0 +1,17 @@
+import styled from '@emotion/styled';
+
+const Heading = styled('h1')`
+ background-color: ${props => props.bg};
+ padding:${props => props.pd};
+ color: ${props => props.fg};
+`;
+
+export const EmotionDemo = () => {
+ return (
+
+
+ Heading with a green background and yellow text.
+
+
+ );
+}
diff --git a/examples/vite-vite/vite-remote/src/Mui5Widget.module.css b/examples/vite-vite/vite-remote/src/Mui5Widget.module.css
new file mode 100644
index 0000000..7067c71
--- /dev/null
+++ b/examples/vite-vite/vite-remote/src/Mui5Widget.module.css
@@ -0,0 +1,12 @@
+.container {
+ padding: 20px;
+ border: 2px;
+ border-style: solid;
+ border-color: cadetblue;
+ }
+
+ .myButton {
+ color: black;
+ background-color: blueviolet;
+ font-size: 10px;
+ }
\ No newline at end of file
diff --git a/examples/vite-vite/vite-remote/src/MuiDemo.jsx b/examples/vite-vite/vite-remote/src/MuiDemo.jsx
new file mode 100644
index 0000000..388fb25
--- /dev/null
+++ b/examples/vite-vite/vite-remote/src/MuiDemo.jsx
@@ -0,0 +1,96 @@
+import { css } from '@emotion/react';
+import { createTheme, Paper, StyledEngineProvider, ThemeProvider, Typography } from '@mui/material';
+import Button from '@mui/material/Button';
+import React from 'react';
+import styles from './Mui5Widget.module.css';
+
+const FooterClasses = {
+ root: {
+ padding: '10px',
+ },
+};
+
+// Emotion
+const emotionClass = css`
+ background-color: orange;
+ color: red;
+ border: 1px solid black;
+ font-size: 20px;
+ margin: 10px;
+`;
+
+// Create Theme
+const theme = createTheme({
+ palette: {
+ background: {
+ paper: '#FF0000',
+ },
+ text: {
+ primary: '#173A5E',
+ secondary: '#46505A',
+ },
+ action: {
+ active: '#001E3C',
+ },
+ },
+ components: {
+ // Name of the component
+ MuiButtonBase: {
+ defaultProps: {
+ // The props to change the default for.
+ disableRipple: true, // No more ripple, on the whole application 💣!
+ },
+ },
+ MuiButton: {
+ styleOverrides: {
+ // Name of the slot
+ root: {
+ // Some CSS
+ fontSize: '1rem',
+ fontFamily: 'Arial',
+ margin: 10,
+ border: '2px solid yellow',
+ },
+ },
+ },
+ },
+});
+
+export const MuiDemo = ({ }) => {
+ return (
+
+
+
+ Button OutSide Theme
+
+
+
+ Button Theme Styled
+
+
+
+
+
+ Button Theme Styled overriden
+
+
+
+
+
+ Button Emotion Styled
+
+
+
+
+
+ Button CSS Module Styled
+
+
+
+
+
+
+ );
+};
diff --git a/examples/vite-vite/vite-remote/src/StyledDemo.jsx b/examples/vite-vite/vite-remote/src/StyledDemo.jsx
new file mode 100644
index 0000000..fe27b5e
--- /dev/null
+++ b/examples/vite-vite/vite-remote/src/StyledDemo.jsx
@@ -0,0 +1,9 @@
+import React from 'react';
+import styled from 'styled-components';
+
+export default styled(function ({ className }) {
+ return Styled components
;
+})`
+ background: salmon;
+ padding: 30px;
+`;
\ No newline at end of file
diff --git a/examples/vite-vite/vite-remote/src/agGrid.css b/examples/vite-vite/vite-remote/src/agGrid.css
new file mode 100644
index 0000000..8e96cba
--- /dev/null
+++ b/examples/vite-vite/vite-remote/src/agGrid.css
@@ -0,0 +1,15 @@
+#grid1 .ag-header-cell {
+ background-color: #b02e2e;
+ }
+
+ #grid1 .ag-row {
+ font-weight: bold;
+ }
+
+ #grid2 .ag-header-cell {
+ background-color: #26ea2c;
+ }
+
+ #grid2 .ag-row {
+ font-weight: bold;
+ }
\ No newline at end of file
diff --git a/examples/vite-vite/vite-remote/src/app2.sass b/examples/vite-vite/vite-remote/src/app2.sass
new file mode 100644
index 0000000..5f88ad7
--- /dev/null
+++ b/examples/vite-vite/vite-remote/src/app2.sass
@@ -0,0 +1,4 @@
+.container
+ background-image: url(./assets/viteback.png)
+ height: 200px
+ color: orange
diff --git a/examples/vite-vite/vite-remote/src/assets/react.svg b/examples/vite-vite/vite-remote/src/assets/react.svg
new file mode 100644
index 0000000..15895c2
--- /dev/null
+++ b/examples/vite-vite/vite-remote/src/assets/react.svg
@@ -0,0 +1,6 @@
+
+
+
\ No newline at end of file
diff --git a/examples/vite-vite/vite-remote/src/assets/viteback.png b/examples/vite-vite/vite-remote/src/assets/viteback.png
new file mode 100644
index 0000000..a0464ee
Binary files /dev/null and b/examples/vite-vite/vite-remote/src/assets/viteback.png differ
diff --git a/examples/vite-vite/vite-remote/src/assets/vue.svg b/examples/vite-vite/vite-remote/src/assets/vue.svg
new file mode 100644
index 0000000..770e9d3
--- /dev/null
+++ b/examples/vite-vite/vite-remote/src/assets/vue.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/examples/vite-vite/vite-remote/src/main.jsx b/examples/vite-vite/vite-remote/src/main.jsx
new file mode 100644
index 0000000..d1b4a91
--- /dev/null
+++ b/examples/vite-vite/vite-remote/src/main.jsx
@@ -0,0 +1,43 @@
+import React from 'react';
+import ReactDOM from 'react-dom/client';
+import { AgGridDemo } from './AgGridDemo';
+import App from './App';
+import App1 from './App1';
+import { App2 } from './App2';
+import { EmotionDemo } from './EmotionDemo';
+import { MuiDemo } from './MuiDemo';
+import StyledDemo from './StyledDemo';
+
+const root = ReactDOM.createRoot(document.getElementById('app'));
+root.render(
+
+ MF Remote as standalone app
+
+
+ Vite React (v {React.version}) app running from Remote in{' '}
+ {import.meta.env.DEV ? ' Dev ' : ' prod '} mode
+
+
+
+ App
+
+
+ App1
+
+
+ App2
+
+
+ AgGridDemo
+
+
+ MuiDemo
+
+
+ Styled Components Demo
+
+
+ Emotion Styled Components Demo
+
+
+);
diff --git a/examples/vite-vite/vite-remote/vite.config.js b/examples/vite-vite/vite-remote/vite.config.js
new file mode 100644
index 0000000..46624fa
--- /dev/null
+++ b/examples/vite-vite/vite-remote/vite.config.js
@@ -0,0 +1,66 @@
+import { federation } from '@module-federation/vite';
+import react from '@vitejs/plugin-react';
+import { defineConfig } from 'vite';
+import topLevelAwait from 'vite-plugin-top-level-await';
+
+// https://vitejs.dev/config/
+export default defineConfig({
+ server: {
+ open: true,
+ port: 5176,
+ origin: 'http://localhost:5176',
+ },
+ preview: {
+ port: 5176,
+ },
+ // base: 'http://localhost:5176',
+ experimental: {
+ renderBuiltUrl() {
+ return { relative: true };
+ },
+ },
+ plugins: [
+ react({ jsxImportSource: '@emotion/react' }),
+ federation({
+ name: '@namespace/viteViteRemote',
+ exposes: {
+ './App1': './src/App1',
+ './App2': './src/App2.jsx',
+ './AgGridDemo': './src/AgGridDemo.jsx',
+ './MuiDemo': './src/MuiDemo.jsx',
+ './StyledDemo': './src/StyledDemo.jsx',
+ './EmotionDemo': './src/EmotionDemo.jsx',
+ '.': './src/App.jsx',
+ },
+ filename: 'remoteEntry-[hash].js',
+ manifest: true,
+ shared: {
+ vue: {},
+ 'react/': {},
+ react: {
+ requiredVersion: '18',
+ },
+ 'react-dom/': {},
+ 'react-dom': {},
+ 'styled-components': { singleton: true },
+ 'ag-grid-community/': {},
+ 'ag-grid-react': {},
+ '@emotion/react': {},
+ '@emotion/styled': { singleton: true },
+ '@mui/material': {},
+ },
+ }),
+ // If you set build.target: "chrome89", you can remove this plugin
+ false && topLevelAwait(),
+ ],
+ build: {
+ target: 'chrome89',
+ rollupOptions: {
+ output: {
+ chunkFileNames: 'static/js/[name]-[hash].js',
+ entryFileNames: 'static/js/[name]-[hash].js',
+ assetFileNames: 'static/[ext]/[name]-[hash].[ext]',
+ },
+ },
+ },
+});
diff --git a/lib/index.cjs b/lib/index.cjs
new file mode 100644
index 0000000..e3fd316
--- /dev/null
+++ b/lib/index.cjs
@@ -0,0 +1,1262 @@
+var fs = require('fs');
+var path = require('pathe');
+var pluginutils = require('@rollup/pluginutils');
+var estreeWalker = require('estree-walker');
+var MagicString = require('magic-string');
+var defu = require('defu');
+
+function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
+
+function _interopNamespace(e) {
+ if (e && e.__esModule) return e;
+ var n = Object.create(null);
+ if (e) {
+ Object.keys(e).forEach(function (k) {
+ if (k !== 'default') {
+ var d = Object.getOwnPropertyDescriptor(e, k);
+ Object.defineProperty(n, k, d.get ? d : {
+ enumerable: true,
+ get: function () { return e[k]; }
+ });
+ }
+ });
+ }
+ n["default"] = e;
+ return n;
+}
+
+var fs__namespace = /*#__PURE__*/_interopNamespace(fs);
+var path__namespace = /*#__PURE__*/_interopNamespace(path);
+var path__default = /*#__PURE__*/_interopDefaultLegacy(path);
+var MagicString__default = /*#__PURE__*/_interopDefaultLegacy(MagicString);
+
+var addEntry = function addEntry(_ref) {
+ var entryName = _ref.entryName,
+ entryPath = _ref.entryPath,
+ fileName = _ref.fileName;
+ var devEntryPath = entryPath.startsWith("virtual:mf") ? "/@id/" + entryPath : entryPath;
+ var entryFiles = [];
+ var htmlFilePath;
+ var _command;
+ return [{
+ name: 'add-entry',
+ apply: "serve",
+ config: function config(_config, _ref2) {
+ var command = _ref2.command;
+ _command = command;
+ },
+ configureServer: function configureServer(server) {
+ var _server$httpServer;
+ (_server$httpServer = server.httpServer) == null || _server$httpServer.once == null || _server$httpServer.once('listening', function () {
+ var port = server.config.server.port;
+ fetch(path__namespace.join("http://localhost:" + port, "" + devEntryPath))["catch"](function (e) {});
+ });
+ server.middlewares.use(function (req, res, next) {
+ if (!fileName) {
+ next();
+ return;
+ }
+ if (req.url && req.url.startsWith(fileName.replace(/^\/?/, '/'))) {
+ req.url = devEntryPath;
+ }
+ next();
+ });
+ },
+ transformIndexHtml: function transformIndexHtml(c) {
+ return c.replace('', "");
+ }
+ }, {
+ name: "add-entry",
+ enforce: "post",
+ configResolved: function configResolved(config) {
+ var inputOptions = config.build.rollupOptions.input;
+ if (!inputOptions) {
+ htmlFilePath = path__namespace.resolve(config.root, 'index.html');
+ } else if (typeof inputOptions === 'string') {
+ entryFiles = [inputOptions];
+ htmlFilePath = path__namespace.resolve(config.root, inputOptions);
+ } else if (Array.isArray(inputOptions)) {
+ entryFiles = inputOptions;
+ htmlFilePath = path__namespace.resolve(config.root, inputOptions[0]);
+ } else if (typeof inputOptions === 'object') {
+ entryFiles = Object.values(inputOptions);
+ htmlFilePath = path__namespace.resolve(config.root, Object.values(inputOptions)[0]);
+ }
+ },
+ buildStart: function buildStart() {
+ var _this$emitFile;
+ if (_command === "serve") return;
+ var hasHash = fileName == null || fileName.includes == null ? void 0 : fileName.includes("[hash");
+ this.emitFile((_this$emitFile = {
+ name: entryName
+ }, _this$emitFile[hasHash ? "name" : "fileName"] = fileName, _this$emitFile.type = 'chunk', _this$emitFile.id = entryPath, _this$emitFile.preserveSignature = 'strict', _this$emitFile));
+ if (htmlFilePath) {
+ var htmlContent = fs__namespace.readFileSync(htmlFilePath, 'utf-8');
+ var scriptRegex = /");
+ }
+ }, {
+ name: "add-entry",
+ enforce: "post",
+ configResolved: function configResolved(config) {
+ var inputOptions = config.build.rollupOptions.input;
+ if (!inputOptions) {
+ htmlFilePath = path.resolve(config.root, 'index.html');
+ } else if (typeof inputOptions === 'string') {
+ entryFiles = [inputOptions];
+ htmlFilePath = path.resolve(config.root, inputOptions);
+ } else if (Array.isArray(inputOptions)) {
+ entryFiles = inputOptions;
+ htmlFilePath = path.resolve(config.root, inputOptions[0]);
+ } else if (typeof inputOptions === 'object') {
+ entryFiles = Object.values(inputOptions);
+ htmlFilePath = path.resolve(config.root, Object.values(inputOptions)[0]);
+ }
+ },
+ buildStart: function buildStart() {
+ var _this$emitFile;
+ if (_command === "serve") return;
+ var hasHash = fileName == null || fileName.includes == null ? void 0 : fileName.includes("[hash");
+ this.emitFile((_this$emitFile = {
+ name: entryName
+ }, _this$emitFile[hasHash ? "name" : "fileName"] = fileName, _this$emitFile.type = 'chunk', _this$emitFile.id = entryPath, _this$emitFile.preserveSignature = 'strict', _this$emitFile));
+ if (htmlFilePath) {
+ var htmlContent = fs.readFileSync(htmlFilePath, 'utf-8');
+ var scriptRegex = /`);
+ }
+ }, {
+ name: "add-entry",
+ enforce: "post",
+ configResolved(config) {
+ const inputOptions = config.build.rollupOptions.input;
+ if (!inputOptions) {
+ htmlFilePath = path.resolve(config.root, 'index.html');
+ } else if (typeof inputOptions === 'string') {
+ entryFiles = [inputOptions];
+ htmlFilePath = path.resolve(config.root, inputOptions);
+ } else if (Array.isArray(inputOptions)) {
+ entryFiles = inputOptions;
+ htmlFilePath = path.resolve(config.root, inputOptions[0]);
+ } else if (typeof inputOptions === 'object') {
+ entryFiles = Object.values(inputOptions);
+ htmlFilePath = path.resolve(config.root, Object.values(inputOptions)[0]);
+ }
+ },
+ buildStart() {
+ if (_command === "serve") return;
+ const hasHash = fileName == null || fileName.includes == null ? void 0 : fileName.includes("[hash");
+ this.emitFile({
+ name: entryName,
+ [hasHash ? "name" : "fileName"]: fileName,
+ type: 'chunk',
+ id: entryPath,
+ preserveSignature: 'strict'
+ });
+ if (htmlFilePath) {
+ const htmlContent = fs.readFileSync(htmlFilePath, 'utf-8');
+ const scriptRegex = /");
+ }
+ }, {
+ name: "add-entry",
+ enforce: "post",
+ configResolved: function configResolved(config) {
+ var inputOptions = config.build.rollupOptions.input;
+ if (!inputOptions) {
+ htmlFilePath = path__namespace.resolve(config.root, 'index.html');
+ } else if (typeof inputOptions === 'string') {
+ entryFiles = [inputOptions];
+ htmlFilePath = path__namespace.resolve(config.root, inputOptions);
+ } else if (Array.isArray(inputOptions)) {
+ entryFiles = inputOptions;
+ htmlFilePath = path__namespace.resolve(config.root, inputOptions[0]);
+ } else if (typeof inputOptions === 'object') {
+ entryFiles = Object.values(inputOptions);
+ htmlFilePath = path__namespace.resolve(config.root, Object.values(inputOptions)[0]);
+ }
+ },
+ buildStart: function buildStart() {
+ var _this$emitFile;
+ if (_command === "serve") return;
+ var hasHash = fileName == null || fileName.includes == null ? void 0 : fileName.includes("[hash");
+ this.emitFile((_this$emitFile = {
+ name: entryName
+ }, _this$emitFile[hasHash ? "name" : "fileName"] = fileName, _this$emitFile.type = 'chunk', _this$emitFile.id = entryPath, _this$emitFile.preserveSignature = 'strict', _this$emitFile));
+ if (htmlFilePath) {
+ var htmlContent = fs__namespace.readFileSync(htmlFilePath, 'utf-8');
+ var scriptRegex = /`
+ );
+ },
+ },
+ {
+ name: "add-entry",
+ enforce: "post",
+ configResolved(config) {
+ const inputOptions = config.build.rollupOptions.input;
+
+ if (!inputOptions) {
+ htmlFilePath = path.resolve(config.root, 'index.html');
+ } else if (typeof inputOptions === 'string') {
+ entryFiles = [inputOptions];
+ htmlFilePath = path.resolve(config.root, inputOptions);
+ } else if (Array.isArray(inputOptions)) {
+ entryFiles = inputOptions;
+ htmlFilePath = path.resolve(config.root, inputOptions[0]);
+ } else if (typeof inputOptions === 'object') {
+ entryFiles = Object.values(inputOptions);
+ htmlFilePath = path.resolve(config.root, Object.values(inputOptions)[0]);
+ }
+ },
+ buildStart() {
+ if (_command === "serve") return
+ const hasHash = fileName?.includes?.("[hash")
+ this.emitFile({
+ name: entryName,
+ [hasHash ? "name" : "fileName"]: fileName,
+ type: 'chunk',
+ id: entryPath,
+ preserveSignature: 'strict',
+ });
+ if (htmlFilePath) {
+ const htmlContent = fs.readFileSync(htmlFilePath, 'utf-8');
+ const scriptRegex = /