24. 前端-微前端-qiankun框架
Qiankun是蚂蚁金服基于single-spa开发的微前端框架,通过模块化架构将单体应用拆分为可独立开发、部署的小型应用。其核心特性包括基于路由的拆分、沙箱隔离机制和技术栈无关性,支持Angular、Vue等不同框架的应用集成。本文详细介绍了Qiankun的工作原理,并提供了主应用(Angular)与子应用(Vue)的具体集成方案,包括路由配置、生命周期管理和打包设置。
前言
微前端
Qiankun是一款由蚂蚁金服推出的微前端框架,它基于single-spa进行二次开发,旨在将Web应用由单一的单体应用转变为多个小型前端应用聚合为一的应用。
一、简介
1.1 什么是微前端
微前端是一种多个团队通过独立发布功能的方式来共同构建现代化 web 应用的技术手段及方法策略。
-
技术栈无关
主框架不限制接入应用的技术栈,微应用具备完全自主权 -
独立开发、独立部署
微应用仓库独立,前后端可独立开发,部署完成后主框架自动完成同步更新 -
增量升级
在面对各种复杂场景时,我们通常很难对一个已经存在的系统做全量的技术栈升级或重构,而微前端是一种非常好的实施渐进式重构的手段和策略 -
独立运行时
每个微应用之间状态隔离,运行时状态不共享
1.2 qiankun 的核心设计理念
🥄 简单
由于主应用微应用都能做到技术栈无关,qiankun 对于用户而言只是一个类似 jQuery 的库,你需要调用几个 qiankun 的 API 即可完成应用的微前端改造。同时由于 qiankun 的 HTML entry 及沙箱的设计,使得微应用的接入像使用 iframe 一样简单。
🍡 解耦/技术栈无关
微前端的核心目标是将巨石应用拆解成若干可以自治的松耦合微应用,而 qiankun 的诸多设计均是秉持这一原则,如 HTML entry、沙箱、应用间通信等。这样才能确保微应用真正具备 独立开发、独立运行 的能力。
1.3 qiankun 的优点/特点
1.HTML Entry
qiankun 通过 HTML Entry 的方式来解决 JS Entry 带来的问题,让你接入微应用像使用iframe 一样简单。
2.样式隔离
qiankun 实现了两种样式隔离
严格的样式隔离模式,为每个微应用的容器包裹上一个 shadow dom 节点,从而确保微应用的样式不会对全局造成影响
实验性的方式,通过动态改写 css 选择器来实现,可以理解为 css scoped 的方式。
3.运行时沙箱
qiankun 的运行时沙箱分为 JS 沙箱和 样式沙箱
JS 沙箱为每个微应用生成单独的 window proxy 对象,配合 HTML Entry 提供的 JS 脚本执行器 (execScripts) 来实现 JS 隔离;
样式沙箱 通过重写 DOM 操作方法,来劫持动态样式和 JS 脚本的添加,让样式和脚本添加到正确的地方,即主应用的插入到主应用模版内,微应用的插入到微应用模版,并且为劫持的动态样式做了 scoped css 的处理,为劫持的脚本做了 JS 隔离的处理,更加具体的内容可继续往下阅读或者直接阅读 qiankun 2.x 运行时沙箱 源码分析
4.资源预加载
qiankun 实现预加载的思路有两种,一种是当主应用执行 start 方法启动 qiankun 以后立即去预加载微应用的静态资源,另一种是在第一个微应用挂载以后预加载其它微应用的静态资源,这个是利用 single-spa 提供的 single-spa:first-mount 事件来实现的
5.应用间通信
qiankun 通过发布订阅模式来实现应用间通信,状态由框架来统一维护,每个应用在初始化时由框架生成一套通信方法,应用通过这些方法来更改全局状态和注册回调函数,全局状态发生改变时触发各个应用注册的回调函数执行,将新旧状态传递到所有应用。
1.4 为什么不是 iframe
iframe 最大的特性就是提供了浏览器原生的硬隔离方案,不论是样式隔离、js 隔离这类问题统统都能被完美解决。但他的最大问题也在于他的隔离性无法被突破,导致应用间上下文无法被共享,随之带来的开发体验、产品体验的问题。
- url 不同步。浏览器刷新 iframe url 状态丢失、后退前进按钮无法使用。
- UI 不同步,DOM 结构不共享。想象一下屏幕右下角 1/4 的 iframe 里来一个带遮罩层的弹框,同时我们要求这个弹框要浏览器居中显示,还要浏览器 resize 时自动居中…
- 全局上下文完全隔离,内存变量不共享。iframe 内外系统的通信、数据同步等需求,主应用的 cookie 要透传到根域名都不同的子应用中实现免登效果。
- 慢。每次子应用进入都是一次浏览器上下文重建、资源重新加载的过程
1. 核心思想
Qiankun借鉴了微服务的架构理念,将一个庞大的前端应用拆分为多个独立灵活的小型应用,每个应用都可以独立开发、独立运行、独立部署,再将这些小型应用联合为一个完整的应用。可以称为,前端的微服务框架。这种方式既可以将多个项目融合为一,又可以减少项目之间的耦合,提升项目扩展性。
2. 主要特性
- 模块化:将大型前端应用拆分为多个小型模块,每个模块都是一个独立的微应用。
- 独立开发:每个微应用可以由不同的团队独立开发,使用不同的技术栈。
- 独立运行:微应用可以独立运行,通过前端路由和页面嵌入等技术实现模块之间的相互调用和通信。
- 独立部署:微应用可以独立部署,无需整个应用重启即可更新单个微应用。
- 技术栈无关性:允许使用不同的编程语言和框架进行开发,提高开发团队的灵活性。

3. 关键技术
- 基于路由的拆分:主应用根据路由的变化来加载和卸载不同的微应用。
- Web Components:利用Web Components技术封装微应用,实现组件级别的隔离和复用。但需要注意的是,Web Components的兼容性可能因浏览器而异。
- iframe:通过iframe嵌入微应用,实现简单的隔离和加载。但iframe的隔离性较强,可能导致样式和脚本的冲突。
- 沙箱运行环境:Qiankun提供了沙箱机制,确保微应用之间的全局变量和事件不冲突。沙箱技术通过拦截和修改微应用对全局作用域(如window对象)的访问,实现微应用之间的隔离。
4. 应用
Qiankun适用于以下场景:
- 大型前端应用需要拆分为多个小型应用,以提高开发效率和可维护性。
- 不同技术栈、不同团队需要独立开发、独立部署的应用。
- 需要实现应用间的增量升级和局部更新。
- Qiankun应用

- Qiankun融合流程模型

- Qiankun路由流程

- Qiankun项目框架模型

- Qiankun项目开发模式

5. 使用示例
- 开发示例

以下是一个使用Qiankun搭建Vue微前端应用的简单示例:
- 创建主应用:使用Vue或其他框架创建一个主应用,作为基座项目。在主应用中配置路由、权限等。
- 注册微应用:在主应用中注册需要加载的微应用信息,包括微应用名称、入口地址、挂载节点、激活规则等。
- 启动Qiankun:在主应用的入口文件中引入Qiankun,并调用其提供的API来启动微前端框架。
- 配置微应用:在每个微应用中配置公共路径(public-path),以确保微应用能够正确加载资源。
- 启动应用:分别启动主应用和各个微应用。
- 部署方案

6. 优势与劣势
-
优势
- 技术兼容性好:各个子应用可以基于不同的技术架构。
- 接入方式简单:像使用iframe一样接入微应用。
- 耦合性低:各个团队可以独立开发,互不干扰。
- 可维护性和扩展性好:便于局部升级和增量升级。
-
劣势
- 无法支持多实例场景。
- 对Vite等现代前端构建工具的支持不够友好,需要改动较多的代码。
- 子应用间的资源共享能力较差,可能导致项目总体积变大。
- 开发人员需要处理分布式系统的复杂性。
7. 总结
Qiankun是一款功能强大的微前端框架,它通过将大型前端应用拆分为多个小型应用,提高了开发效率和可维护性。同时,Qiankun提供了沙箱机制,确保了微应用之间的隔离性。然而,Qiankun也存在一些局限性,如不支持多实例场景、对Vite等构建工具的支持不够友好等。因此,在选择是否使用Qiankun时,需要根据具体项目的需求和团队的技术栈进行综合考虑。
二、快速上手
2.1 创建主应用
1.安装 qiankun
$ yarn add qiankun # 或者 npm i qiankun -S
2.在主应用中注册微应用
import { registerMicroApps, start } from 'qiankun'
// 根据路由配置
registerMicroApps([
{
name: 'vue-app', // 必须与微应用注册名字相同
entry: 'http://localhost:8081', // 入口路径,开发时为微应用所启本地服务,上线时为微应用线上路径
container: '#vue-app-container', // 微应用挂载的节点
activeRule: '/micro-vue', // 当访问路由为 /micro-vue 时加载微应用
props: {
msg: "我是来自主应用的值-vue" // 主应用向微应用传递参数
}
},
{
name: 'react-app',
entry: 'http://localhost:8082',
container: '#react-app-container',
activeRule: '/micro-react',
props: {
msg: "我是来自主应用的值-react"
}
}
])
start()
当微应用信息注册完之后,一旦浏览器的 url 发生变化,便会自动触发 qiankun 的匹配逻辑,所有 activeRule 规则匹配上的微应用就会被插入到指定的 container 中,同时依次调用微应用暴露出的生命周期钩子。
如果微应用不是直接跟路由关联的时候,你也可以选择手动加载微应用的方式:
import { loadMicroApp } from 'qiankun';
loadMicroApp({
name: 'app',
entry: '//localhost:7100',
container: '#yourContainer',
});
2.2 微应用
微应用分为有 webpack 构建和无 webpack 构建项目,有 webpack 的微应用(主要是指 Vue、React、Angular)需要做的事情有:
- 新增
public-path.js文件,用于修改运行时的publicPath。
注意:运行时的 publicPath 和构建时的 publicPath 是不同的,两者不能等价替代。
- 微应用建议使用
history模式的路由,需要设置路由base,值和它的activeRule是一样的。 - 在入口文件最顶部引入
public-path.js,修改并导出三个生命周期函数。 - 修改
webpack打包,允许开发环境跨域和umd打包。
主要的修改就是以上四个,可能会根据项目的不同情况而改变。例如,你的项目是 index.html 和其他的所有文件分开部署的,说明你们已经将构建时的 publicPath 设置为了完整路径,则不用修改运行时的 publicPath (第一步操作可省)。
无 webpack 构建的微应用直接将 lifecycles 挂载到 window 上即可。
React 微应用
1.在 src 目录新增 public-path.js:
if (window.__POWERED_BY_QIANKUN__) {
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
2.设置 history 模式路由的 base:
<BrowserRouter basename={window.__POWERED_BY_QIANKUN__ ? '/app-react' : '/'}>
3.入口文件 index.js 修改,为了避免根 id #root 与其他的 DOM 冲突,需要限制查找范围。
import './public-path';
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
function render(props) {
const { container } = props;
ReactDOM.render(<App />, container ? container.querySelector('#root') : document.querySelector('#root'));
}
if (!window.__POWERED_BY_QIANKUN__) {
render({});
}
export async function bootstrap() {
console.log('[react16] react app bootstraped');
}
export async function mount(props) {
console.log('[react16] props from main framework', props);
render(props);
}
export async function unmount(props) {
const { container } = props;
ReactDOM.unmountComponentAtNode(container ? container.querySelector('#root') : document.querySelector('#root'));
}
// 定义全局状态,并返回两个通信方法
const { onGlobalStateChange, setGlobalState } = initGlobalState({
user: 'qiankun',
});
// 监听全局状态的更改,当状态发生改变时执行回调函数
onGlobalStateChange((value, prev) => console.log('[onGlobalStateChange - master]:', value, prev));
// 设置新的全局状态,只能设置一级属性,微应用只能修改已存在的一级属性
setGlobalState({
ignore: 'master',
user: {
name: 'master',
},
});
// 设置默认进入的子应用,当主应用启动以后默认进入指定微应用
setDefaultMountApp('/react16');
// 启动应用
start();
// 当第一个微应用挂载以后,执行回调函数,在这里可以做一些特殊的事情,比如开启一监控或者买点脚本
runAfterFirstMounted(() => {
console.log('[MainApp] first app mounted');
});
4.修改 webpack 配置
安装插件 @rescripts/cli,当然也可以选择其他的插件,例如 react-app-rewired。
根目录新增 .rescriptsrc.js:
const { name } = require('./package');
module.exports = {
webpack: (config) => {
config.output.library = `${name}-[name]`;
config.output.libraryTarget = 'umd';
// webpack 5 需要把 jsonpFunction 替换成 chunkLoadingGlobal
config.output.jsonpFunction = `webpackJsonp_${name}`;
config.output.globalObject = 'window';
return config;
},
devServer: (_) => {
const config = _;
config.headers = {
'Access-Control-Allow-Origin': '*', // 允许开发环境跨域
};
config.historyApiFallback = true;
config.hot = false;
config.watchContentBase = false;
config.liveReload = false;
return config;
},
};
修改 package.json:
- "start": "react-scripts start",
+ "start": "rescripts start",
- "build": "react-scripts build",
+ "build": "rescripts build",
- "test": "react-scripts test",
+ "test": "rescripts test",
- "eject": "react-scripts eject"
Vue 微应用
1.在 src 目录新增 public-path.js
if (window.__POWERED_BY_QIANKUN__) {
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
2.入口文件 main.js 修改,为了避免根 id #app 与其他的 DOM 冲突,需要限制查找范围。
import './public-path';
import Vue from 'vue';
import VueRouter from 'vue-router';
import App from './App.vue';
import routes from './router';
import store from './store';
Vue.config.productionTip = false;
let router = null;
let instance = null;
function render(props = {}) {
const { container } = props;
router = new VueRouter({
base: window.__POWERED_BY_QIANKUN__ ? '/app-vue/' : '/',
mode: 'history',
routes,
});
instance = new Vue({
router,
store,
render: (h) => h(App),
}).$mount(container ? container.querySelector('#app') : '#app');
}
// 独立运行时
if (!window.__POWERED_BY_QIANKUN__) {
render();
}
export async function bootstrap() {
console.log('[vue] vue app bootstraped');
}
export async function mount(props) {
storeTest(props);
console.log('[vue] props from main framework', props);
render(props);
}
export async function unmount() {
instance.$destroy();
instance.$el.innerHTML = '';
instance = null;
router = null;
}
/**
* 从 props 中获取通信方法,监听全局状态的更改和设置全局状态,只能操作一级属性
* @param {*} props
*/
function storeTest(props) {
props.onGlobalStateChange &&
props.onGlobalStateChange(
(value, prev) => console.log(`[onGlobalStateChange - ${props.name}]:`, value, prev),
true,
);
props.setGlobalState &&
props.setGlobalState({
ignore: props.name,
user: {
name: props.name,
},
});
}
3.打包配置修改(vue.config.js):
const { name } = require('./package');
module.exports = {
devServer: {
headers: {
'Access-Control-Allow-Origin': '*', // 允许开发环境跨域
},
},
configureWebpack: {
output: {
library: `${name}-[name]`,
libraryTarget: 'umd', // 把微应用打包成 umd 库格式
jsonpFunction: `webpackJsonp_${name}`, // webpack 5 需要把 jsonpFunction 替换成 chunkLoadingGlobal
},
},
};
2.3 jQuery 微应用
这是一个使用了 jQuery 的项目,在 examples/purehtml 目录下,展示了如何接入使用 jQuery 开发的应用
package.json
为了达到演示效果,使用 http-server 在起了一个本地服务器,并且支持跨域
{
...
"scripts": {
"start": "cross-env PORT=7104 http-server . --cors",
"test": "echo \"Error: no test specified\" && exit 1"
},
...
}
entry.js
// 渲染函数
const render = $ => {
$('#purehtml-container').html('Hello, render with jQuery');
return Promise.resolve();
};
// 在全局对象上导出三个生命周期函数
(global => {
global['purehtml'] = {
bootstrap: () => {
console.log('purehtml bootstrap');
return Promise.resolve();
},
mount: () => {
console.log('purehtml mount');
// 调用渲染函数
return render($);
},
unmount: () => {
console.log('purehtml unmount');
return Promise.resolve();
},
};
})(window);
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Purehtml Example</title>
<script src="//cdn.bootcss.com/jquery/3.4.1/jquery.min.js">
</script>
</head>
<body>
<div style="display: flex; justify-content: center; align-items: center; height: 200px;">
Purehtml Example
</div>
<div id="purehtml-container" style="text-align:center"></div>
<!-- 引入 entry.js,相当于 vue 项目的 publicPath 配置 -->
<script src="//localhost:7104/entry.js" entry></script>
</body>
</html>
2.4 主应用与微应用通信
initGlobalState(state) 定义全局状态,并返回通信方法,建议在主应用使用,微应用通过 props 获取通信方法。
-
onGlobalStateChange: (callback: OnGlobalStateChangeCallback, fireImmediately?: boolean) => void, 在当前应用监听全局状态,有变更触发 callback,fireImmediately = true 立即触发 callback
-
setGlobalState: (state: Record<string, any>) => boolean, 按一级属性设置全局状态,微应用中只能修改已存在的一级属性
-
offGlobalStateChange: () => boolean,移除当前应用的状态监听,微应用 umount 时会默认调用
主应用:
import { initGlobalState, MicroAppStateActions } from 'qiankun';
// 初始化 state
const actions: MicroAppStateActions = initGlobalState(state);
actions.onGlobalStateChange((state, prev) => {
// state: 变更后的状态; prev 变更前的状态
console.log(state, prev);
});
actions.setGlobalState(state);
actions.offGlobalStateChange();
微应用:
// 从生命周期 mount 中获取通信方法,使用方式和 master 一致
export function mount(props) {
props.onGlobalStateChange((state, prev) => {
// state: 变更后的状态; prev 变更前的状态
console.log(state, prev);
// store.count = res.count
});
// 修改全局状态
props.setGlobalState(state);
}
2.5 UmiJS 配置qiankun
2.6 vue3 vite 微应用
1.安装插件
qiankun目前是不支持vite的,需要vite-plugin-qiankun
npm install vite-plugin-qiankun
2.修改vite.config.ts
import { defineConfig, loadEnv } from 'vite'
import vue from '@vitejs/plugin-vue'
import qiankun from 'vite-plugin-qiankun'
// useDevMode 开启时与热更新插件冲突
const useDevMode = true // 如果是在主应用中加载子应用vite,必须打开这个,否则vite加载不成功, 单独运行没影响
export default defineConfig(({ mode }) => {
const root = process.cwd() // process.cwd()返回当前工作目录
const env = loadEnv(mode, root)
let config = {
base: env.VITE_BASE_API,
plugins: [
vue(),
qiankun('vue-app', { // 微应用名字,与主应用注册的微应用名字保持一致
{ useDevMode }
})
],
resolve: {
alias: {
'@': _resolve('src')
}
},
server: {
host: 'x.x.x.x', // 暴露内网ip
port: 8000,
cors: true,
origin: mode === 'development' ? env.VITE_ORIGIN_DEV : env.VITE_BASE_API
},
output: {
// 把子应用打包成 umd 库格式
library: `${子应用名}-[name]`,
libraryTarget: 'umd',
jsonpFunction: `webpackJsonp_${子应用名}`
},
}
return config
})
3.修改main.ts
import { createApp } from 'vue'
import App from './App.vue'
import { createRouter, createWebHashHistory } from 'vue-router'
import {
renderWithQiankun,
qiankunWindow
} from 'vite-plugin-qiankun/dist/helper'
let router = null
let instance = null
let history = null
instance = createApp(App)
declare global {
interface Window {
__POWERED_BY_QIANKUN__: any
__INJECTED_PUBLIC_PATH_BY_QIANKUN__: any
}
}
function render(props = {}) {
const { container } = props as any
history = createWebHashHistory(
qiankunWindow.__POWERED_BY_QIANKUN__ ? '/calendar-mobile' : '/'
)
router = createRouter({
history,
routes
})
instance.use(router)
// instance.use(store);
instance.mount(
container ? container.querySelector('#app') : document.getElementById('app')
)
if (qiankunWindow.__POWERED_BY_QIANKUN__) {
console.log('我正在作为子应用运行')
}
}
// some code
renderWithQiankun({
mount(props) {
console.log('viteapp mount')
render(props)
},
bootstrap() {
console.log('bootstrap')
},
unmount(props) {
console.log('vite被卸载了')
instance.unmount()
instance._container.innerHTML = ''
history.destroy() // 不卸载 router 会导致其他应用路由失败
router = null
instance = null
}
})
if (!qiankunWindow.__POWERED_BY_QIANKUN__) {
render({})
}
二、使用
以下是一个完整的例子,用于说明qiankun微前端框架的使用。在这个例子中,我们将创建一个主应用(Angular CLI项目)和一个子应用(Vue CLI项目),并将它们集成在一起。
1. 创建主应用(Angular CLI项目)
- 安装Angular CLI并创建项目
npm install -g @angular/cli
ng new angular-app
cd angular-app
- 安装Qiankun
npm i qiankun --save
- 创建挂载子应用的页面并配置路由:
- 在Angular项目中创建一个新的组件用于挂载子应用,并配置路由以指向该组件。
ng g component views/vue-page
- 配置路由(
app-routing.module.ts):
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { VuePageComponent } from './views/vue-page/vue-page.component';
const routes: Routes = [
{ path: 'home', component: VuePageComponent }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
- 在
VuePageComponent的HTML模板中添加一个容器元素用于挂载子应用:
<div id="container"></div>
- 在主应用中注册子应用:
- 在
main.ts中导入qiankun并注册子应用:
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { registerMicroApps, start } from 'qiankun';
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err));
registerMicroApps([
{
name: 'vueChildOne',
entry: '//localhost:8080', // 子应用的请求地址
container: '#container', // 挂载到主应用的哪个元素下
activeRule: '/vue-app', // 路由地址为/vue-app时,加载该子应用
}
]);
start();
2. 创建子应用(Vue CLI项目)
- 安装Vue CLI并创建项目
npm install -g @vue/cli
vue create vue-app
cd vue-app
- 安装qiankun
npm i qiankun --save
- 在子项目中添加
public-path.js
在src目录下创建一个public-path.js文件,并添加以下代码:
if (window.__POWERED_BY_QIANKUN__) {
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
- 修改Vue项目的入口文件:
在main.js中导出生命周期钩子,并处理路由和渲染逻辑:
import './public-path';
import Vue from 'vue';
import VueRouter from 'vue-router';
import App from './App.vue';
import routes from './router';
Vue.config.productionTip = false;
let router = null;
let instance = null;
function render(props = {}) {
const { container } = props;
router = new VueRouter({
base: window.__POWERED_BY_QIANKUN__ ? '/vue-app' : '/',
mode: 'history',
routes,
});
instance = new Vue({
router,
render: h => h(App),
}).$mount(container ? container.querySelector('#app') : '#app');
}
// 独立运行时
if (!window.__POWERED_BY_QIANKUN__) {
render();
}
export async function bootstrap() {
console.log('[vue] vue app bootstraped');
}
export async function mount(props) {
console.log('[vue] props from main framework', props);
render(props);
}
export async function unmount() {
instance.$destroy();
instance.$el.innerHTML = '';
instance = null;
router = null;
}
-
配置路由
-
在
src/router/index.js中配置路由:
import Vue from 'vue';
import Router from 'vue-router';
import Home from '@/views/Home.vue';
Vue.use(Router);
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
// 其他路由配置...
];
const router = new Router({
base: process.env.BASE_URL,
mode: 'history',
routes
});
export default router;
- 配置微应用的打包工具:
在vue.config.js中添加以下配置,以便主应用能够正确加载子应用的资源:
module.exports = {
configureWebpack: {
output: {
library: `${name}-[name]`,
libraryTarget: 'umd',
jsonpFunction: `webpackJsonp_${name}`,
},
},
};
3. 启动并测试
- 启动子应用
npm run serve
确保子应用在localhost:8080上运行(或根据你的配置调整端口)。
- 启动主应用
ng serve
- 访问主应用
在浏览器中访问http://localhost:4200/home(或根据Angular项目配置调整端口和路径)。就会看到主应用的页面,并且当路由匹配到/vue-app时,会加载并展示Vue子应用。
通过以上步骤,就可以成功地使用qiankun将一个Angular主应用和一个Vue子应用集成在了一起。
这只是一个简单的例子,qiankun还支持更多高级功能,如应用间通信、样式隔离等,你可以根据需要进行进一步的配置和开发。
三、使用场景
微前端框架qiankun的使用场景主要包括以下几个方面:
1. 大型前端应用的拆分与整合
-
巨石应用的拆分
- 在大型前端应用中,随着业务的发展和功能的增加,应用可能会变得非常庞大和复杂,难以维护和扩展。
- 使用qiankun可以将这些大型应用拆分为多个小型、独立的微应用,每个微应用都可以独立开发、部署和迭代,从而提高开发效率和应用的可维护性。
-
多技术栈的整合
- 在大型项目中,可能会使用多种不同的前端技术栈,如React、Vue、Angular等。
- qiankun支持任意技术栈的应用接入,使得不同技术栈的微应用可以在同一个主应用中协同工作,实现技术的多样性和灵活性。
2. 独立开发与部署
-
独立开发
- 不同的微应用可以由不同的团队独立开发,每个团队都可以使用自己熟悉的技术栈和工具链。
- 这种独立开发的方式可以提高开发效率,减少团队之间的依赖和冲突。
-
独立部署
- 每个微应用都可以独立部署和更新,无需整个应用重启即可更新单个微应用。
- 这种独立部署的方式可以减少更新对整个应用的影响,提高系统的稳定性和可靠性。
3. 增量升级与局部更新
-
增量升级
- 在面对各种复杂场景时,我们通常很难对一个已经存在的系统做全量的技术栈升级或重构。
- 使用qiankun可以实现微应用的增量升级,即只更新需要升级的微应用部分,而不需要对整个系统进行重构或升级。
-
局部更新
- 当某个微应用需要更新时,只需要更新该微应用的代码和资源,而不需要更新整个应用。
- 这种局部更新的方式可以减少更新带来的风险和成本,提高系统的可维护性和可扩展性。
4. 应用间的通信与共享
-
应用间通信
- qiankun提供了多种应用间通信的方式,如全局状态管理、事件总线等。
- 这些通信方式可以使得不同的微应用之间能够方便地传递数据和事件,实现应用间的协同工作。
-
资源共享
- 在微前端架构中,不同的微应用可能需要共享一些公共的资源或组件。
- qiankun支持在主应用中定义和共享这些公共资源和组件,使得不同的微应用能够方便地复用这些资源和组件。
5. 跨域与安全性
-
跨域问题
- 在微前端架构中,不同的微应用可能部署在不同的域名下,这可能会导致跨域问题。
- qiankun提供了一些解决方案来处理跨域问题,如使用CORS(跨来源资源共享)策略、JSONP等。
-
安全性
- 微前端架构可能会增加一些安全性问题,如跨站脚本攻击(XSS)、点击劫持等。
- qiankun提供了一些安全措施来防范这些攻击,如使用沙箱机制、内容安全策略(CSP)等。
6. 总结
综上所述,qiankun微前端框架的使用场景非常广泛,适用于大型前端应用的拆分与整合、独立开发与部署、增量升级与局部更新以及应用间的通信与共享等场景。同时,qiankun也提供了一些解决方案来处理跨域问题和安全性问题。
四、Web Components简介
Web Components是一套技术规范,由一系列不同的Web平台特性组成,允许开发者创建可复用的自定义元素(custom elements)和组件。
1. 概念与特点
-
概念
- Web Components是浏览器环境提供的一套API和模板,支持原生实现组件化。
- 开发者可以方便地创建可重用的定制元素,这些元素具有封装好的结构、样式和脚本。
-
特点
- 组件化:可以将复杂的UI组件封装成一个可重用的单元,有助于提高开发效率和代码复用性。
- 跨平台:Web Components可以跨浏览器、跨框架使用,不受特定技术栈的限制。
- 隔离性:通过Shadow DOM可以避免组件的样式和行为受到外部影响,提供了良好的隔离性。
- 封装性:提供了一种封装和保护组件内部结构和样式的机制,使得组件的样式和行为不会受到外部的影响。
2. 核心组成部分
Web Components实际上是一系列技术的组合,主要包含以下三部分:
-
自定义元素(Custom Elements)
- 在HTML基础标签外扩展自定义标签元素,即平时使用的框架组件。
- 通过customElements.define()方法注册自定义元素。
-
Shadow DOM
- 主要用于将Shadow DOM的内容与外层document DOM隔离。
- 可以理解为在document中的一个子容器,放置各种组件。
- 使用Element.attachShadow()方法将一个Shadow DOM附加到自定义元素上。
-
HTML模板(HTML Templates)
- 使用来定义组件模板。
- 标签内部的内容在初始时不会渲染到页面上,但可以通过JavaScript动态地插入到DOM中。
- 使用作为插槽,允许外部内容插入到模板中的指定位置。
3. 使用场景
-
创建自定义UI元素
- Web Components允许开发者定义自己的HTML元素,这些元素具有封装好的结构、样式和脚本。
- 可以像标准HTML元素一样在DOM中使用。
-
构建组件化应用
- 通过Web Components,开发者可以构建组件化的应用,提高代码的复用性和可维护性。
- 每个组件都是独立的,可以单独开发、测试和部署。
-
跨框架开发
- Web Components是浏览器原生支持的API,因此它们可以在不同的前端框架(如React、Vue)中被无缝集成和使用。
- 这有助于解决不同框架之间的兼容性问题,实现跨框架的组件复用。
4. 优势与挑战
-
优势
- 技术栈无关性:允许使用不同的编程语言和框架进行开发。
- 样式隔离:通过Shadow DOM实现组件样式的隔离,避免样式冲突。
- 性能优化:由于组件的独立性,可以实现对特定组件的缓存和懒加载,提高页面性能。
-
挑战
- 浏览器兼容性:虽然Web Components已经在现代浏览器中得到了较好的支持,但在一些老旧浏览器中可能仍然存在问题。
- 学习成本:Web Components涉及到多个技术点,需要较高的技术水平和学习成本。
- 性能问题:在某些情况下,Web Components可能会增加网页的加载时间和渲染时间,需要进行优化和测试。
5. 未来发展
随着Web Components的不断发展,W3C正在推进Web Components的标准化工作。未来,它将成为Web开发的一个标准特性,得到更广泛的支持和应用。同时,越来越多的组件库和工具链会涌现出来,为Web Components的开发和使用提供更多的支持和便利。
6. 总结
综上所述,Web Components是一种强大的技术,它允许开发者以统一的方式封装自定义的UI组件,并在任何网页上使用。通过充分利用其组件化、跨平台、隔离性和封装性等特性,开发者可以构建出高效、可维护和可扩展的Web应用。
本文的引用仅限自我学习如有侵权,请联系作者删除。
参考知识
【前端知识】微前端框架qiankun
更多推荐



所有评论(0)