微前端架构将大型前端应用拆分为多个独立子应用,各子应用可独立开发、部署和运行。在业务复杂度持续增长的场景下,微前端解决了单页应用体积膈胀、团队协作冲突、技术栈锁定等问题。目前主流方案有基于路由的qiankun和基于Webpack 5 Module Federation两大路线,二者在隔离机制、通信方式、构建工具依赖上各有差异。
微前端架构模式与隔离机制对比
qiankun基于single-spa,通过HTML entry方式加载子应用,运行时将子应用的JS/CSS注入主应用。其核心隔离机制是JS沙箱和CSS隔离:
class ProxySandbox {
constructor() {
const fakeWindow = Object.create(null);
this.proxy = new Proxy(fakeWindow, {
get(target, key) {
if (target[key]) return target[key];
const value = window[key];
if (typeof value === 'function') {
return value.bind(window);
}
return value;
},
set(target, key, value) {
target[key] = value;
return true;
}
});
}
}
Module Federation是Webpack 5原生功能,编译时将模块暴露为远程入口,运行时动态加载远程模块。不依赖额外框架,但要求所有子应用使用Webpack 5。
qiankun主应用与子应用集成
主应用注册子应用:
import { registerMicroApps, start } from 'qiankun';
registerMicroApps([
{
name: 'app-vue',
entry: '//localhost:7101',
container: '#sub-app-container',
activeRule: '/vue-app',
props: { routerBase: '/vue-app', mainStore: window.mainStore }
},
{
name: 'app-react',
entry: '//localhost:7102',
container: '#sub-app-container',
activeRule: '/react-app'
}
]);
start({ prefetch: true, sandbox: { experimentalStyleIsolation: true } });
Vue 3子应用接入qiankun:
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';
let app = null;
function render(props = {}) {
const { container } = props;
app = createApp(App);
app.use(router);
app.mount(container ? container.querySelector('#app') : '#app');
}
export async function bootstrap() {}
export async function mount(props) { render(props); }
export async function unmount(props) { app.unmount(); app = null; }
if (!window.__POWERED_BY_QIANKUN__) { render(); }
Module Federation远程模块加载
宿主应用配置(Host):
const { ModuleFederationPlugin } = require('webpack').container;
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: 'host',
remotes: {
remoteVue: 'remoteVue@http://localhost:7102/remoteEntry.js',
remoteReact: 'remoteReact@http://localhost:7103/remoteEntry.js'
},
shared: { vue: { singleton: true }, react: { singleton: true } }
})
]
}
远程应用配置(Remote),暴露组件:
new ModuleFederationPlugin({
name: 'remoteVue',
filename: 'remoteEntry.js',
exposes: {
'./Button': './src/components/Button.vue',
'./Dashboard': './src/views/Dashboard.vue'
},
shared: { vue: { singleton: true, eager: false } }
})
在宿主应用中动态加载远程组件:
import { defineAsyncComponent } from 'vue';
const RemoteButton = defineAsyncComponent(() => import('remoteVue/Button'));
const RemoteDashboard = defineAsyncComponent(() => import('remoteVue/Dashboard'));
跨应用通信与状态共享
qiankun使用自定义事件通信:
import { initGlobalState } from 'qiankun';
const actions = initGlobalState({ user: null, theme: 'light' });
actions.onGlobalStateChange((state) => { console.log('收到', state); });
actions.setGlobalState({ user: { name: 'admin', role: 'super' } });
// 子应用接收
export async function mount(props) {
props.onGlobalStateChange((state) => { console.log(state); });
props.setGlobalState({ theme: 'dark' });
}
方案选型决策矩阵
| 维度 | qiankun | Module Federation |
|---|---|---|
| 隔离机制 | JS沙箱+CSS隔离 | 共享依赖,无JS沙箱 |
| 技术栈 | 任意技术栈 | 需Webpack 5+ |
| 通信 | globalState API | 共享模块/事件总线 |
| 部署 | 子应用独立部署 | 需暴露remoteEntry |
| 调试 | 子应用独立运行 | 依赖宿主容器 |
| 体积 | 重复加载依赖 | 共享依赖减包体 |
选型建议:技术栈异构(如Vue+React+Angular混用)选qiankun,其JS沙箱和CSS隔离能避免子应用互相污染。技术栈统一且使用Webpack 5的团队选Module Federation,共享依赖减少重复打包体积,编译时类型检查更安全。已有single-spa基础设施的团队迁移qiankun成本低,全新项目可优先考虑Module Federation的原生集成体验。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/wei-qian-duan-jia-gou-luo-di-shi-zhan-qiankun-yu/