English | 简体中文
A Vite plugin which support Module Federation. Inspired by Webpack Module Federation
Using npm:
npm install @originjs/vite-plugin-federation --save-dev
The main steps in using federation are:
- for a Vite project, in
vite.config.js
:
import { defineConfig } from 'vite'
import federation from "@originjs/vite-plugin-federation";
export default defineConfig({
plugins: [
federation({
name: 'module-name',
filename: 'remoteEntry.js',
exposes: {
'./Button': './src/Button.vue',
},
remotes:{
foo: 'remote_foo'
},
shared: ['vue']
})
],
})
- for a Rollup project, in
rollup.config.js
:
import federation from '@originjs/vite-plugin-federation'
export default {
input: 'src/index.js',
output: {
format: 'esm',
dir: 'dist'
},
plugins: [
federation({
filename: 'remoteEntry.js',
exposes: {
'./Button': './src/button'
},
shared: ['react']
})
]
}
Vue2, for example
<script>
export default {
name: 'App',
components: {
RemoteButtonScoped: () => import('remote-simple/remote-simple-button-scoped'),
}
}
</script>
Vue2, for example
<template>
<div>
<RemoteButtonScoped />
</div>
</template>
Federation currently relies on browsers to support the Top-level await, so you need to set build.target
in the configuration file to next
or a similar value. See browser compatibility
Required as the module name of the remote module.
As the entry file of the remote module, not required, default is remoteEntry.js
As the remote module, the list of components exposed to the public, required for the remote module.
exposes: {
// 'externally exposed component name': 'externally exposed component address'
'. /remote-simple-button': '. /src/components/Button.vue',
'. /remote-simple-section': '. /src/components/Section.vue'
},
The remote module entry file referenced as a local module
configuration information
remote module address, e.g. https://localhost:5011/remoteEntry.js You can simply configure it as follows
remotes: {
// 'remote module name': 'remote module entry file address'
'remote-simple': 'http://localhost:5011/remoteEntry.js',
}
Or do a slightly more complex configuration, if you need to use other fields
remotes: {
remote-simple: {
external: 'http://localhost:5011/remoteEntry.js',
format: 'var',
}
}
default: 'url'
set the type of external
If you want to use a dynamic url address, you can set the external
as promise
, but please note that you need to set the externalType
as 'promise' at the same time, and please ensure that the code of the promise
part is correct, otherwise the package may fail,here is a simple example.
remotes: {
home: {
external: `Promise.resolve('your url')`,
externalType: 'promise'
},
},
// or from networke
remotes: {
remote-simple: {
external: `fetch('your url').then(response=>response.json()).then(data=>data.url)`,
externalType: 'promise'
}
}
default:'esm'
Specify the format of the remote component, this is more effective when the host and the remote use different packaging formats, for example the host uses vite + esm and the remote uses webpack + var, in which case you need to specify type
: 'var'
default : 'vite'
Specify the source of the remote component, from vite-plugin-federation
select vite
, from webpack
select webpack
Dependencies shared by local and remote modules. Local modules need to configure the dependencies of all used remote modules; remote modules need to configure the dependencies of externally provided components.
configuration information
default: true
The default is true
, whether to add shared to the module, only for the remote
side, remote
will reduce some of the packaging time when this configuration is turned on, because there is no need to package some of the shared
, but once there is no shared
module available on the host
side, it will report an error directly, because there is no fallback module available
default: 'default'
Default is defualt
, the shared domain name, just keep the remote
and host
sides the same
Only works on host
side, the version of the shared module provided is version
of the package.json
file in the shared package by default, you need to configure it manually only if you can't get version
by this method
Only for the remote
side, it specifies the required version of the host shared
used, when the version of the host
side does not meet the requiredVersion
requirement, it will use its own shared
module, provided that it is not configured with import=false
, which is not enabled by default
- basic-host-remote
- simple-react-esm
- simple-react-systemjs
- vue3-demo-esm
- vue3-demo-systemjs
- vue3-demo-webpack-esm-esm
- vue3-demo-webpack-esm-var
- vue3-demo-webpack-systemjs
- vue3-advanced-demo
vite-plugin-federation dependencies are required during the development and build process, and global installation is recommended.
- rollup
- vite
Part of example requires dependencies, recommended for global installation.
- lerna
- rimraf
Github CI build, not engineering required:
- playwright-chromium
Since Vite is esbuild-based in development mode, we provide separate support for the development mode to leverage Vite’s high-performance development capabilities in the case of remote module deployment. And note that only Host supports the dev mode and Remote supports only build mode
React
projects (e.g. vite
using webpack
components or vice versa), because there is no guarantee that vite/rollup
and webpack
will convert export
consistent chunk
when packaging the commonjs
framework, which is a prerequisite for using shared
is a prerequisite for using
Now you can use federation
without the restrictions of vite
and webpack
, that is, you can choose to use the vit-plugin-federation
component in webpack
or the webpack-module- federation
in vite
, but you need to pay attention to the configuration in remotes
, for different frameworks you need to specify remotes.from
and remotes.format
to make them work better, the currently supported format pairings are as follows.
host | remote | demo |
---|---|---|
rollup/vite +esm |
rollup/vite +esm |
simple-react-esm |
rollup/vite +systemjs |
rollup/vite +systemjs |
vue3-demo-esm |
rollup/vite +systemjs |
webpack +systemjs |
vue3-demo-systemjs |
rollup/vite +esm |
webpack +var |
vue3-demo-webpack-esm-var |
rollup/vite +esm |
webpack +esm |
vue3-demo-webpack-esm-esm |
vite
is relatively easy to use with webpack
components, but vite-plugin-federation
components are better in esm
format when webpack
uses vite
components, because other formats temporarily lack test cases to complete the test
Static import is supported at this stage. The following shows the difference between the two methods. You can see examples
of dynamic import and static import in each project in examples, and here is a simple example.
- Vue
// dynamic import
const myButton = defineAsyncComponent(() => import('remote/myButton'));
app.component('my-button' , myButton);
// or
export default {
name: 'App',
components: {
myButton: () => import('remote/myButton'),
}
}
// static import
import myButton from 'remote/myButton';
app.component('my-button' , myButton);
// or
export default {
name: 'App',
components: {
myButton: myButton
}
- React
// dynamic import
const myButton = React.lazy(() => import('remote/myButton'))
// static import
import myButton from 'remote/myButton'
The solution is to set build.target
to esnext
, which you can find at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await to see the support for this feature in each browser.
build: {
target: "esnext"
}
Please check if you have started the project in dev
mode with vite
, currently only the fully pure host side can use dev
mode, the remote
side must use build
mode to make the plugin take effect.
It is recommended to check this Issue, which contains most of the React
related issues
The remote module failed to load the share of the local module, for examplelocalhost/:1 Uncaught (in promise) TypeError: Failed to fetch dynamically imported module: http://your url
Reason: Vite has auto fetch logic for IP
and Port when starting the service, no full fetch logic has been found in the Plugin
, and in some cases a fetch failure may occur.
Solutions:
Explicitly declaring IP, Port, cacheDir
in the local module ensures that our Plugin
can correctly fetch and pass the dependent addresses.
Local module's vite.config.ts
export default defineConfig({
server:{
https: "http",
host: "192.168.56.1",
port: 5100,
},
cacheDir: "node_modules/.cacheDir",
}