diff --git a/README.md b/README.md
index 824959c..cb35c43 100644
--- a/README.md
+++ b/README.md
@@ -64,8 +64,6 @@ export default defineConfig({
## roadmap
-- fix: vitePluginAddEntry.ts This plugin may need to support the case where base in vite.config.js is not configured as "/"
-- fix: remoteEntry and hostInit file names support hash generation
- feat: generate mf-manifest.json
- feat: support chrome plugin
diff --git a/examples/rust/rsbuild.config.ts b/examples/rust/rsbuild.config.ts
index e0a1590..83b7151 100644
--- a/examples/rust/rsbuild.config.ts
+++ b/examples/rust/rsbuild.config.ts
@@ -1,6 +1,6 @@
+import { ModuleFederationPlugin } from '@module-federation/enhanced/rspack';
import { defineConfig } from '@rsbuild/core';
import { pluginReact } from '@rsbuild/plugin-react';
-import { ModuleFederationPlugin } from '@module-federation/enhanced/rspack';
export default defineConfig({
server: {
diff --git a/examples/rust/src/App.tsx b/examples/rust/src/App.tsx
index 0435f29..37d47fb 100644
--- a/examples/rust/src/App.tsx
+++ b/examples/rust/src/App.tsx
@@ -1,13 +1,11 @@
-import { applyVueInReact } from 'veaury';
-import App from 'viteRemote/App';
-const AppComponent = App.default;
+import ViteApp from 'viteRemote/App';
export default function Button() {
return (
);
}
diff --git a/examples/vite/package.json b/examples/vite/package.json
index 3974f2d..dd7b9e1 100644
--- a/examples/vite/package.json
+++ b/examples/vite/package.json
@@ -11,13 +11,12 @@
"@module-federation/vite": "workspace:*",
"react": "^18.3.1",
"react-dom": "^18.2.0",
- "vue": "^3.4.29",
+ "vue": "^3.4.35",
"vue-router": "^4.4.0"
},
"devDependencies": {
"@swc/core": "~1.6.0",
"@vitejs/plugin-react": "^4.3.1",
- "@vitejs/plugin-vue": "^5.0.5",
"vite": "^5.3.1",
"vite-plugin-top-level-await": "^1.4.1"
}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 4019f0a..58989cb 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -91,7 +91,7 @@ importers:
specifier: ^18.2.0
version: 18.3.1(react@18.3.1)
vue:
- specifier: ^3.4.29
+ specifier: ^3.4.35
version: 3.4.35(typescript@5.5.3)
vue-router:
specifier: ^4.4.0
@@ -103,9 +103,6 @@ importers:
'@vitejs/plugin-react':
specifier: ^4.3.1
version: 4.3.1(vite@5.3.5(@types/node@22.0.2)(terser@5.20.0))
- '@vitejs/plugin-vue':
- specifier: ^5.0.5
- version: 5.1.2(vite@5.3.5(@types/node@22.0.2)(terser@5.20.0))(vue@3.4.35(typescript@5.5.3))
vite:
specifier: ^5.3.1
version: 5.3.5(@types/node@22.0.2)(terser@5.20.0)
@@ -2616,16 +2613,6 @@ packages:
peerDependencies:
vite: ^4.2.0 || ^5.0.0
- '@vitejs/plugin-vue@5.1.2':
- resolution:
- {
- integrity: sha512-nY9IwH12qeiJqumTCLJLE7IiNx7HZ39cbHaysEUd+Myvbz9KAqd2yq+U01Kab1R/H1BmiyM2ShTYlNH32Fzo3A==,
- }
- engines: { node: ^18.0.0 || >=20.0.0 }
- peerDependencies:
- vite: ^5.0.0
- vue: ^3.2.25
-
'@vue/compiler-core@3.4.35':
resolution:
{
@@ -8289,11 +8276,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@vitejs/plugin-vue@5.1.2(vite@5.3.5(@types/node@22.0.2)(terser@5.20.0))(vue@3.4.35(typescript@5.5.3))':
- dependencies:
- vite: 5.3.5(@types/node@22.0.2)(terser@5.20.0)
- vue: 3.4.35(typescript@5.5.3)
-
'@vue/compiler-core@3.4.35':
dependencies:
'@babel/parser': 7.25.3
diff --git a/src/index.ts b/src/index.ts
index c415d38..fe29634 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -43,7 +43,16 @@ function generateRemoteEntry(options: NormalizedModuleFederationOptions): string
${Object.keys(options.exposes)
.map((key) => {
return `
- ${JSON.stringify(key)}: () => import(${JSON.stringify(options.exposes[key].import)})
+ ${JSON.stringify(key)}: async () => {
+ const importModule = await import(${JSON.stringify(options.exposes[key].import)})
+ const exportModule = {}
+ Object.assign(exportModule, importModule)
+ Object.defineProperty(exportModule, "__esModule", {
+ value: true,
+ enumerable: false
+ })
+ return exportModule
+ }
`;
})
.join(',')}
@@ -76,7 +85,7 @@ function generateRemoteEntry(options: NormalizedModuleFederationOptions): string
})
.join(',')}
}
- const initRes = await runtimeInit({
+ const initRes = runtimeInit({
name: ${JSON.stringify(options.name)},
remotes: [${Object.keys(options.remotes)
.map((key) => {
@@ -124,10 +133,10 @@ function wrapShare(
strictVersion: ${JSON.stringify(shareConfig.strictVersion)},
requiredVersion: ${JSON.stringify(shareConfig.requiredVersion)}
}}})
- export ${command !== 'build' ? 'default' : 'const dynamicExport = '} res()
+ export default res()
`,
map: null,
- syntheticNamedExports: 'dynamicExport',
+ syntheticNamedExports: 'default',
};
}
@@ -184,15 +193,14 @@ function federation(mfUserOptions: ModuleFederationOptions): Plugin[] {
aliasToArrayPlugin,
normalizeOptimizeDepsPlugin,
normalizeBuildPlugin([...Object.keys(shared), "@module-federation/runtime"]),
- addEntry({
+ ...addEntry({
entryName: 'remoteEntry',
entryPath: emptyPath + '?__mf__wrapRemoteEntry__',
fileName: filename,
}),
- addEntry({
+ ...addEntry({
entryName: 'hostInit',
entryPath: emptyPath + '?__mf__isHostInit',
- fileName: 'hostInit.js',
}),
overrideModule({
override: Object.keys(shared),
diff --git a/src/utils/normalizeModuleFederationOptions.ts b/src/utils/normalizeModuleFederationOptions.ts
index 5873765..934095e 100644
--- a/src/utils/normalizeModuleFederationOptions.ts
+++ b/src/utils/normalizeModuleFederationOptions.ts
@@ -142,7 +142,7 @@ function normalizeShareItem(
from: '',
shareConfig: {
singleton: false,
- requiredVersion: version || '*',
+ requiredVersion: `^${version}` || '*',
},
};
}
@@ -153,7 +153,7 @@ function normalizeShareItem(
scope: shareItem.shareScope || 'default',
shareConfig: {
singleton: shareItem.singleton || false,
- requiredVersion: shareItem.requiredVersion || version || '*',
+ requiredVersion: shareItem.requiredVersion || `^${version}` || '*',
strictVersion: !!shareItem.strictVersion,
},
};
@@ -262,7 +262,7 @@ export function normalizeModuleFederationOptions(
): NormalizedModuleFederationOptions {
return {
exposes: normalizeExposes(options.exposes),
- filename: options.filename || 'remoteEntry.js',
+ filename: options.filename || 'remoteEntry-[hash]',
library: normalizeLibrary(options.library),
name: options.name,
// remoteType: options.remoteType,
diff --git a/src/utils/vitePluginAddEntry.ts b/src/utils/vitePluginAddEntry.ts
index 42888a6..1f3d8b2 100644
--- a/src/utils/vitePluginAddEntry.ts
+++ b/src/utils/vitePluginAddEntry.ts
@@ -1,48 +1,94 @@
+import * as fs from 'fs';
+import * as path from 'path';
import { Plugin } from 'vite';
interface AddEntryOptions {
entryName: string;
entryPath: string;
- fileName: string;
+ fileName?: string;
}
-const addEntry = ({ entryName, entryPath, fileName }: AddEntryOptions): Plugin => {
- let command: string;
+const addEntry = ({ entryName, entryPath, fileName }: AddEntryOptions): Plugin[] => {
+ let entryFiles: string[] = [];
+ let htmlFilePath: string;
- return {
- name: 'add-entry',
- configureServer(server) {
- server.middlewares.use((req, res, next) => {
- if (req.url && req.url.startsWith(fileName.replace(/^\/?/, '/'))) {
- req.url = entryPath;
- }
- next();
- });
- },
- config(config, { command: _command }) {
- command = _command;
- },
- buildStart() {
- if (command !== 'build') return;
- // if we don't expose any modules, there is no need to emit file
- this.emitFile({
- fileName: `${fileName}`,
- type: 'chunk',
- id: entryPath,
- preserveSignature: 'strict',
- });
- },
- transformIndexHtml(c) {
- if (command !== 'build')
+ return [
+ {
+ name: 'add-entry',
+ apply: "serve",
+ configureServer(server) {
+ server.httpServer?.once?.('listening', () => {
+ const { port } = server.config.server;
+ fetch(`http://localhost:${port}${entryPath}`)
+ });
+ server.middlewares.use((req, res, next) => {
+ if (!fileName) {
+ next()
+ return
+ }
+ if (req.url && req.url.startsWith(fileName.replace(/^\/?/, '/'))) {
+ req.url = entryPath;
+ }
+ next();
+ });
+ },
+ transformIndexHtml(c) {
return c.replace(
'',
``
);
- return c.replace('', ``);
+ },
},
- };
+ {
+ name: "add-entry",
+ enforce: "post",
+ apply: "build",
+ 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() {
+ const hasHash = fileName?.includes?.("[hash")
+ this.emitFile({
+ [hasHash ? "name" : "fileName"]: fileName,
+ type: 'chunk',
+ id: entryPath,
+ preserveSignature: 'strict',
+ });
+ if (htmlFilePath) {
+ const htmlContent = fs.readFileSync(htmlFilePath, 'utf-8');
+ const scriptRegex = /