diff --git a/examples/vite-webpack-rspack/dynamic-remote/src/SpecialPromo.jsx b/examples/vite-webpack-rspack/dynamic-remote/src/SpecialPromo.jsx
index 8ba3969..19a71ea 100644
--- a/examples/vite-webpack-rspack/dynamic-remote/src/SpecialPromo.jsx
+++ b/examples/vite-webpack-rspack/dynamic-remote/src/SpecialPromo.jsx
@@ -1,8 +1,11 @@
+import _ from 'lodash';
+
const SpecialPromo = () => {
return (
Up to 50% off!
+
Shared lodash v{_.VERSION}
Only for a limited time.

diff --git a/examples/vite-webpack-rspack/dynamic-remote/vite.config.js b/examples/vite-webpack-rspack/dynamic-remote/vite.config.js
index f9ab454..3fe2b4a 100644
--- a/examples/vite-webpack-rspack/dynamic-remote/vite.config.js
+++ b/examples/vite-webpack-rspack/dynamic-remote/vite.config.js
@@ -14,7 +14,11 @@ export default defineConfig({
'./SignUpBanner': './src/SignUpBanner.jsx',
'./SpecialPromo': './src/SpecialPromo.jsx',
},
- shared: ['react', 'react-dom'],
+ shared: {
+ react: { singleton: true },
+ 'react-dom': { singleton: true },
+ lodash: { singleton: true, import: false },
+ },
}),
],
server: {
diff --git a/examples/vite-webpack-rspack/host/package.json b/examples/vite-webpack-rspack/host/package.json
index 91949cf..ae818a4 100644
--- a/examples/vite-webpack-rspack/host/package.json
+++ b/examples/vite-webpack-rspack/host/package.json
@@ -11,6 +11,7 @@
},
"dependencies": {
"@module-federation/vite": "workspace:*",
+ "lodash": "^4.17.21",
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
diff --git a/examples/vite-webpack-rspack/host/src/App.tsx b/examples/vite-webpack-rspack/host/src/App.tsx
index 525fe7e..76b2ac8 100644
--- a/examples/vite-webpack-rspack/host/src/App.tsx
+++ b/examples/vite-webpack-rspack/host/src/App.tsx
@@ -7,6 +7,9 @@ import { Toggle } from './components/Toggle';
import { useDynamicImport } from './hooks/useDynamicImport';
import './index.css';
+import _ from 'lodash';
+_.VERSION;
+
const RemoteProduct = lazy(
() =>
// @ts-ignore
diff --git a/examples/vite-webpack-rspack/host/vite.config.js b/examples/vite-webpack-rspack/host/vite.config.js
index 3b2c265..99b63ee 100644
--- a/examples/vite-webpack-rspack/host/vite.config.js
+++ b/examples/vite-webpack-rspack/host/vite.config.js
@@ -22,7 +22,7 @@ const mfConfig = {
type: 'module',
},
},
- shared: ['react', 'react-dom'],
+ shared: ['react', 'react-dom', 'lodash'],
};
// https://vitejs.dev/config/
@@ -38,5 +38,6 @@ export default defineConfig({
],
build: {
target: 'chrome89',
+ minify: false,
},
});
diff --git a/package.json b/package.json
index 43eca39..849117c 100644
--- a/package.json
+++ b/package.json
@@ -46,7 +46,8 @@
"homepage": "https://github.com/module-federation/vite#readme",
"packageManager": "pnpm@9.1.3",
"dependencies": {
- "@module-federation/runtime": "^0.17.1",
+ "@module-federation/runtime": "^0.18.3",
+ "@module-federation/sdk": "^0.18.3",
"@rollup/pluginutils": "^5.1.0",
"defu": "^6.1.4",
"estree-walker": "^2",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index f1fa349..8b9e007 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -8,8 +8,11 @@ importers:
.:
dependencies:
'@module-federation/runtime':
- specifier: ^0.17.1
- version: 0.17.1
+ specifier: ^0.18.3
+ version: 0.18.4
+ '@module-federation/sdk':
+ specifier: ^0.18.3
+ version: 0.18.3
'@rollup/pluginutils':
specifier: ^5.1.0
version: 5.1.0(rollup@4.47.1)
@@ -269,6 +272,9 @@ importers:
'@module-federation/vite':
specifier: workspace:*
version: link:../../..
+ lodash:
+ specifier: ^4.17.21
+ version: 4.17.21
react:
specifier: ^18.3.1
version: 18.3.1
@@ -303,6 +309,9 @@ importers:
'@module-federation/vite':
specifier: workspace:*
version: link:../../..
+ lodash:
+ specifier: ^4.17.21
+ version: 4.17.21
react:
specifier: ^18.3.1
version: 18.3.1
@@ -2613,10 +2622,10 @@ packages:
webpack:
optional: true
- '@module-federation/error-codes@0.17.1':
+ '@module-federation/error-codes@0.18.4':
resolution:
{
- integrity: sha512-n6Elm4qKSjwAPxLUGtwnl7qt4y1dxB8OpSgVvXBIzqI9p27a3ZXshLPLnumlpPg1Qudaj8sLnSnFtt9yGpt5yQ==,
+ integrity: sha512-cpLsqL8du9CfTTCKvXbRg93ALF+lklqHnuPryhbwVEQg2eYo6CMoMQ6Eb7kJhLigUABIDujbHD01SvBbASGkeQ==,
}
'@module-federation/managers@0.2.5':
@@ -2637,10 +2646,10 @@ packages:
integrity: sha512-Rvk4KTPn9KqM84ub3N8Ze1uC7oSJejlC4SG9JxUrr1yvkJh1Ej3SGWpeHyS7trBVWeJItCFqXAlAD2RnFIcjXQ==,
}
- '@module-federation/runtime-core@0.17.1':
+ '@module-federation/runtime-core@0.18.4':
resolution:
{
- integrity: sha512-LCtIFuKgWPQ3E+13OyrVpuTPOWBMI/Ggwsq1Q874YeT8Px28b8tJRCj09DjyRFyhpSPyV/uG80T6iXPAUoLIfQ==,
+ integrity: sha512-LGGlFXlNeTbIGBFDiOvg0zz4jBWCGPqQatXdKx7mylXhDij7YmwbuW19oenX+P1fGhmoBUBM5WndmR87U66qWA==,
}
'@module-federation/runtime-tools@0.1.6':
@@ -2667,10 +2676,10 @@ packages:
integrity: sha512-nj6a+yJ+QxmcE89qmrTl4lphBIoAds0PFPVGnqLRWflwAP88jrCcrrTqRhARegkFDL+wE9AE04+h6jzlbIfMKg==,
}
- '@module-federation/runtime@0.17.1':
+ '@module-federation/runtime@0.18.4':
resolution:
{
- integrity: sha512-vKEN32MvUbpeuB/s6UXfkHDZ9N5jFyDDJnj83UTJ8n4N1jHIJu9VZ6Yi4/Ac8cfdvU8UIK9bIbfVXWbUYZUDsw==,
+ integrity: sha512-2et6p7pjGRHzpmrW425jt/BiAU7QHgkZtbQB7pj01eQ8qx6SloFEBk9ODnV8/ztSm9H2T3d8GxXA6/9xVOslmQ==,
}
'@module-federation/runtime@0.2.5':
@@ -2691,10 +2700,16 @@ packages:
integrity: sha512-qifXpyYLM7abUeEOIfv0oTkguZgRZuwh89YOAYIZJlkP6QbRG7DJMQvtM8X2yHXm9PTk0IYNnOJH0vNQCo6auQ==,
}
- '@module-federation/sdk@0.17.1':
+ '@module-federation/sdk@0.18.3':
resolution:
{
- integrity: sha512-nlUcN6UTEi+3HWF+k8wPy7gH0yUOmCT+xNatihkIVR9REAnr7BUvHFGlPJmx7WEbLPL46+zJUbtQHvLzXwFhng==,
+ integrity: sha512-tlBgF5pKXoiZ5hGRgafOpsktt0iafdjoH2O85ywPqvDGVK0DzfP8hs4qdUBJlKulP5PZoBtgTe7UiqyTbKJ7YQ==,
+ }
+
+ '@module-federation/sdk@0.18.4':
+ resolution:
+ {
+ integrity: sha512-dErzOlX+E3HS2Sg1m12Hi9nCnfvQPuIvlq9N47KxrbT2TIU3KKYc9q/Ua+QWqxfTyMVFpbNDwFMJ1R/w/gYf4A==,
}
'@module-federation/sdk@0.2.5':
@@ -14965,7 +14980,7 @@ snapshots:
- supports-color
- utf-8-validate
- '@module-federation/error-codes@0.17.1': {}
+ '@module-federation/error-codes@0.18.4': {}
'@module-federation/managers@0.2.5':
dependencies:
@@ -15004,10 +15019,10 @@ snapshots:
- utf-8-validate
- vue-tsc
- '@module-federation/runtime-core@0.17.1':
+ '@module-federation/runtime-core@0.18.4':
dependencies:
- '@module-federation/error-codes': 0.17.1
- '@module-federation/sdk': 0.17.1
+ '@module-federation/error-codes': 0.18.4
+ '@module-federation/sdk': 0.18.4
'@module-federation/runtime-tools@0.1.6':
dependencies:
@@ -15028,11 +15043,11 @@ snapshots:
dependencies:
'@module-federation/sdk': 0.1.6
- '@module-federation/runtime@0.17.1':
+ '@module-federation/runtime@0.18.4':
dependencies:
- '@module-federation/error-codes': 0.17.1
- '@module-federation/runtime-core': 0.17.1
- '@module-federation/sdk': 0.17.1
+ '@module-federation/error-codes': 0.18.4
+ '@module-federation/runtime-core': 0.18.4
+ '@module-federation/sdk': 0.18.4
'@module-federation/runtime@0.2.5':
dependencies:
@@ -15044,7 +15059,9 @@ snapshots:
'@module-federation/sdk@0.1.6': {}
- '@module-federation/sdk@0.17.1': {}
+ '@module-federation/sdk@0.18.3': {}
+
+ '@module-federation/sdk@0.18.4': {}
'@module-federation/sdk@0.2.5': {}
diff --git a/src/utils/normalizeModuleFederationOptions.ts b/src/utils/normalizeModuleFederationOptions.ts
index 929da7a..b36c082 100644
--- a/src/utils/normalizeModuleFederationOptions.ts
+++ b/src/utils/normalizeModuleFederationOptions.ts
@@ -1,4 +1,5 @@
import { SharedConfig, ShareStrategy } from '@module-federation/runtime/types';
+import type { sharePlugin } from '@module-federation/sdk';
export type RemoteEntryType =
| 'var'
@@ -104,7 +105,7 @@ export interface ShareItem {
version: string | undefined;
scope: string;
from: string;
- shareConfig: SharedConfig;
+ shareConfig: SharedConfig & sharePlugin.SharedConfig;
}
function removePathFromNpmPackage(packageString: string): string {
@@ -157,6 +158,7 @@ function normalizeShareItem(
| string
| {
name: string;
+ import: sharePlugin.SharedConfig['import'];
version?: string;
shareScope?: string;
singleton?: boolean;
@@ -192,6 +194,7 @@ function normalizeShareItem(
scope: 'default',
from: '',
shareConfig: {
+ import: undefined,
singleton: false,
requiredVersion: version ? `^${version}` : '*',
},
@@ -203,6 +206,7 @@ function normalizeShareItem(
version: shareItem.version || version,
scope: shareItem.shareScope || 'default',
shareConfig: {
+ import: typeof shareItem === 'object' ? shareItem.import : undefined,
singleton: shareItem.singleton || false,
requiredVersion: shareItem.requiredVersion || (version ? `^${version}` : '*'),
strictVersion: !!shareItem.strictVersion,
@@ -289,6 +293,7 @@ export type ModuleFederationOptions = {
singleton?: boolean;
requiredVersion?: string;
strictVersion?: boolean;
+ import?: sharePlugin.SharedConfig['import'];
}
>
| undefined;
diff --git a/src/virtualModules/virtualRemoteEntry.ts b/src/virtualModules/virtualRemoteEntry.ts
index affd661..ef4e712 100644
--- a/src/virtualModules/virtualRemoteEntry.ts
+++ b/src/virtualModules/virtualRemoteEntry.ts
@@ -38,17 +38,23 @@ export function writeLocalSharedImportMap() {
export function generateLocalSharedImportMap() {
const options = getNormalizeModuleFederationOptions();
return `
+ import {loadShare} from "@module-federation/runtime";
const importMap = {
${Array.from(getUsedShares())
.sort()
- .map(
- (pkg) => `
+ .map((pkg) => {
+ const shareItem = getNormalizeShareItem(pkg);
+ return `
${JSON.stringify(pkg)}: async () => {
- let pkg = await import("${getPreBuildLibImportId(pkg)}")
- return pkg
+ ${
+ shareItem?.shareConfig.import === false
+ ? `throw new Error(\`Shared module '\${${JSON.stringify(pkg)}}' must be provided by host\`);`
+ : `let pkg = await import("${getPreBuildLibImportId(pkg)}");
+ return pkg;`
+ }
}
- `
- )
+ `;
+ })
.join(',')}
}
const usedShared = {
@@ -65,8 +71,11 @@ export function generateLocalSharedImportMap() {
loaded: false,
from: ${JSON.stringify(options.name)},
async get () {
+ if (${shareItem.shareConfig.import === false}) {
+ throw new Error(\`Shared module '\${${JSON.stringify(key)}}' must be provided by host\`);
+ }
usedShared[${JSON.stringify(key)}].loaded = true
- const {${JSON.stringify(key)}: pkgDynamicImport} = importMap
+ const {${JSON.stringify(key)}: pkgDynamicImport} = importMap
const res = await pkgDynamicImport()
const exportModule = {...res}
// All npm packages pre-built by vite will be converted to esm
@@ -80,7 +89,8 @@ export function generateLocalSharedImportMap() {
},
shareConfig: {
singleton: ${shareItem.shareConfig.singleton},
- requiredVersion: ${JSON.stringify(shareItem.shareConfig.requiredVersion)}
+ requiredVersion: ${JSON.stringify(shareItem.shareConfig.requiredVersion)},
+ ${shareItem.shareConfig.import === false ? 'import: false,' : ''}
}
}
`;
@@ -178,7 +188,7 @@ const hostAutoInitModule = new VirtualModule('hostAutoInit', HOST_AUTO_INIT_TAG)
export function writeHostAutoInit() {
hostAutoInitModule.writeSync(`
const remoteEntryPromise = import("${REMOTE_ENTRY_ID}")
- // __tla only serves as a hack for vite-plugin-top-level-await.
+ // __tla only serves as a hack for vite-plugin-top-level-await.
Promise.resolve(remoteEntryPromise)
.then(remoteEntry => {
return Promise.resolve(remoteEntry.__tla)