位置: IT常识 - 正文

微前端 - qiankun(微前端Qiankun)

编辑:rootadmin
微前端 - qiankun 前言

推荐整理分享微前端 - qiankun(微前端Qiankun),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:微前端Qiankun介绍,微前端Qiankun 作者,微前端Qiankun作用,微前端Qiankun作用,微前端Qiankun 子应用css后加载问题,微前端Qiankun 子应用css后加载导致页面闪动,微前端Qiankun,微前端Qiankun,内容如对您有帮助,希望把文章链接给更多的朋友!

qiankun 是一个基于 single-spa 的微前端实现库,旨在帮助大家能更简单、无痛的构建一个生产可用微前端架构系统。

本文主要记录下如何接入 qiankun 微前端。主应用使用 vue2,子应用使用 vue3、react。

一、主应用

主应用不限技术栈,只需要提供一个容器 DOM,然后注册微应用并 start 即可。

1⃣️、创建项目

// @vue/cli 5.0.4npm install @vue/cli -gvue create main-vue

主应用选择 vue2.x 版本。 具体创建步骤,便不在此一一叙述。

项目创建之后,配置路由,页面布局等。整体效果如下图。

2⃣️、安装 qiankun

npm i qiankun -S

3⃣️、 注册微应用并启动

新建微应用子列表文件 micros/app.js

// src/micros/app.js// 子应用列表const apps = [ { name: 'vue2-app', // 子应用app name 推荐与子应用的package的name一致 entry: '//localhost:8081/', // 子应用的入口地址,就是你子应用运行起来的地址 container: '#micro-container', // 挂载子应用内容的dom节点 `# + dom id`【见上面app.vue】 activeRule: '/vue2App' // 子应用的路由前缀 }, { name: 'vue3-app', entry: '//localhost:8082/', container: '#micro-container', activeRule: '/vue3App' }, { name: 'react-app', entry: '//localhost:8083/', container: '#micro-container', activeRule: '/react' }]export default apps

注册微应用

// src/micros/index.jsimport { addGlobalUncaughtErrorHandler, registerMicroApps, start} from 'qiankun'// 微应用的信息import apps from './app'/** * 注册微应用 * 第一个参数 - 微应用的注册信息 * 第二个参数 - 全局生命周期钩子 */registerMicroApps(apps, { // qiankun 生命周期钩子 - 微应用加载前 beforeLoad: (app) => { // 加载微应用前,加载进度条 console.log('before load=====', app.name) return Promise.resolve() }, // qiankun 生命周期钩子 - 微应用挂载后 afterMount: (app) => { // 加载微应用前,进度条加载完成 console.log('after mount=====', app.name) return Promise.resolve() }})/** * 添加全局的未捕获异常处理器 */addGlobalUncaughtErrorHandler((event) => { console.error(event) const { message: msg } = event if (msg && msg.includes('died in status LOADING_SOURCE_CODE')) { console.error('微应用加载失败,请检查应用是否可运行') }})// 导出 qiankun 的启动函数export default start

配置主应用路由

// src/router/index.jsimport Vue from 'vue'import VueRouter from 'vue-router'Vue.use(VueRouter)const routes = [ { path: '/', name: 'home', component: () => import('@/components/Home.vue'), children: [{ path: '/', name: 'hello', component: () => import('@/views/HomeView.vue') },{ path: '/vue2App', name: 'vue2App' }, { path: '/vue3App', name: 'vue3App' }, { path: '/vue3App/list', name: 'vueAppList' }, { path: '/react', name: 'react' }] }]const router = new VueRouter({ mode: 'history', base: process.env.BASE_URL, routes})export default router

页面设置子应用的挂载节点

<template> <div class="wrapper"> <MyHeader></MyHeader> <el-container class="content"> <el-aside width="200px"> <MySider></MySider> </el-aside> <el-main> <router-view></router-view> <!-- 挂载子应用节点 --> <div id="micro-container"></div> </el-main> </el-container> </div></template><script> import MyHeader from './Header.vue' import MySider from './Sider.vue' export default { name: 'MyHome', components: { MyHeader, MySider }, data() { return { } } }</script><style lang="less"> .content { height: calc(100% - 50px); }</style>

在 main.js 中引入并启动 qiankun

// src/main.jsimport Vue from 'vue'import App from './App.vue'import router from './router'import store from './store'import '../src/assets/style/reset.less'import './plugins/element.js'import start from '@/micros'// 启动start()Vue.config.productionTip = falsenew Vue({ router, store, render: h => h(App)}).$mount('#app')二、微应用

微应用分为有 webpack 构建和无 webpack 构建项目,有 webpack 的微应用(主要是指 Vue、React、Angular)需要做的事情有:

新增 public-path.js 文件,用于修改运行时的 publicPath。微应用建议使用 history 模式的路由,需要设置路由 base,值和它的 activeRule 是一样的。在入口文件最顶部引入 public-path.js,修改并导出三个生命周期函数。修改 webpack 打包,允许开发环境跨域和 umd 打包。

无 webpack 构建的微应用直接将 lifecycles 挂载到 window 上即可。

微应用无需安装 qiankun。

三、vue2-app 微应用

 1⃣️、创建项目

// vue-cli 2.9.6npm install vue-cli -gnpm install webpack-cli -gnpm init webpack vue-app

2⃣️、在 src 目录新增 public-path.js

// src/public-path.jsif(window.__POWERED_BY_QIANKUN__) { __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;}微前端 - qiankun(微前端Qiankun)

修改路由文件,建议使用history 模式的路由,并设置路由 base,值和它的 activeRule 是一样的。

// src/router/index.jsimport Vue from 'vue'import Router from 'vue-router'import HelloWorld from '@/components/HelloWorld'Vue.use(Router)export default new Router({ mode: 'history', base: window.__POWERED_BY_QIANKUN__ ? "/vue2App" : "/", routes: [ { path: '/', name: 'HelloWorld', component: HelloWorld } ]})

入口文件 main.js 修改,为了避免根 id #app 与其他的 DOM 冲突,需要限制查找范围。并导出三个生命周期函数。

// src/main.jsimport Vue from 'vue'import App from './App'import router from './router'import "./public-path";Vue.config.productionTip = false// 定义一个Vue实例let instance = null// 渲染方法function render(props = {}) { const { container } = props instance = new Vue({ router, render: (h) => h(App) }).$mount(container ? container.querySelector('#app'): '#app')}// 独立运行时if(!window.__POWERED_BY_QIANKUN__) { render()}//暴露主应用生命周期钩子/** * bootstrap : 在微应用初始化的时候调用一次,之后的生命周期里不再调用 */export async function bootstrap() { console.log('vue2-app bootstraped');}/** * mount : 在应用每次进入时调用 */export async function mount(props) { console.log('vue2-app mount', props); render(props);}/** * unmount :应用每次 切出/卸载 均会调用 */export async function unmount() { console.log("vue2-app unmount") instance.$destroy(); instance.$el.innerHTML = ''; instance = null;}

修改 webpack 打包,允许开发环境跨域和 umd 打包。

// build/webpack.base.conf.js'use strict'const config = require('../config')const APP_NAME = require('../package.json').namemodule.exports = { output: { path: config.build.assetsRoot, filename: '[name].js', publicPath: process.env.NODE_ENV === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath, // 微应用的包名,这里与主应用中注册的微应用名称一致 library: APP_NAME, // 将你的 library 暴露为所有的模块定义下都可运行的方式 libraryTarget: "umd", // 按需加载相关,设置为 webpackJsonp_VueMicroApp 即可 jsonpFunction: `webpackJsonp_${APP_NAME}`, }, ...}// build/webpack.dev.conf.jsconst devWebpackConfig = merge(baseWebpackConfig, { ... devServer: { ... // 关闭主机检查,使微应用可以被 fetch disableHostCheck: true, // 配置跨域请求头,解决开发环境的跨域问题 headers: { "Access-Control-Allow-Origin": "*", } }})

运行效果如下:

四、vue3-app 微应用

1⃣️、创建项目

// @vue/cli 5.0.4npm install @vue/cli -gvue create vue3-app

 2⃣️、在 src 目录新增 public-path.ts

// src/public-path.tsif ((window as any).__POWERED_BY_QIANKUN__) { __webpack_public_path__ = (window as any).__INJECTED_PUBLIC_PATH_BY_QIANKUN__;}

修改路由文件。

// src/router/index.tsimport { createRouter, createWebHistory, RouteRecordRaw } from "vue-router";const routes: Array<RouteRecordRaw> = [ { path: "/", name: "home", component: () => import("@/components/Home.vue"), children: [ { path: "/", name: "index", component: () => import("../views/HomeView.vue"), }, { path: "/list", name: "list", component: () => import("../views/AboutView.vue"), }, ], },];const router = createRouter({ history: createWebHistory( window.__POWERED_BY_QIANKUN__ ? "/vue3App" : process.env.BASE_URL ), routes,});export default router;

 入口文件 main.ts 修改

// src/main.tsimport Vue, { createApp } from "vue";import App from "./App.vue";import router from "./router";import store from "./store";import "./public-path.ts";// 定义一个Vue实例let instance: Vue.App<Element>;// 需要定义该接口,否则`/src/router/index.ts`无法使用`Window.__POWERED_BY_QIANKUN__`declare global { interface Window { __POWERED_BY_QIANKUN__?: string; }}interface IRenderProps { container: Element | string;}// 渲染方法function render(props: IRenderProps) { const { container } = props; instance = createApp(App); instance .use(store) .use(router) .mount( container instanceof Element ? (container.querySelector("#app") as Element) : (container as string) );}// 独立运行时if (!window.__POWERED_BY_QIANKUN__) { render({ container: "#app" });}//暴露主应用生命周期钩子/** * bootstrap : 在微应用初始化的时候调用一次,之后的生命周期里不再调用 */export async function bootstrap() { console.log("vue3-app bootstraped");}/** * mount : 在应用每次进入时调用 */export async function mount(props: any) { console.log("mount vue3-app", props); render(props);}/** * unmount :应用每次 切出/卸载 均会调用 */export async function unmount() { console.log("unmount vue3-app app"); instance.unmount();}

 修改 webpack 打包,允许开发环境跨域和 umd 打包。

注意:webpack5 中 jsonpFunction 修改为 chunkLoadingGlobal

// vue.config.jsconst path = require("path");const APP_NAME = require("./package.json").name;function resolve(dir) { return path.join(__dirname, dir);}module.exports = { outputDir: "dist", assetsDir: "static", filenameHashing: true, devServer: { host: "localhost", hot: true, port: 8082, client: { overlay: { errors: true, warnings: false, }, }, // 配置跨域请求头,解决开发环境的跨域问题 headers: { "Access-Control-Allow-Origin": "*", }, }, // 自定义webpack配置 configureWebpack: { resolve: { alias: { "@": resolve("src"), }, }, output: { // 把子应用打包成 umd 库格式 // // 微应用的包名,这里与主应用中注册的微应用名称一致 library: APP_NAME, // 将你的 library 暴露为所有的模块定义下都可运行的方式 libraryTarget: "umd", // 按需加载相关,设置为 webpackJsonp_微应用名称 即可 chunkLoadingGlobal: `webpackJsonp_${APP_NAME}`, }, },};

运行效果如下:

五、react-app 微应用

1⃣️、创建项目,以 create-react-app 生成的 react 17 项目为例,搭配 react-router-dom 6.x。

npx create-react-app react-app --template typescriptnpm i react-router-dom

在根目录下添加 .env 文件,设置项目监听的端口

// react-app/.envPORT=8083BROWSER=none

2⃣️、新建 public-path.ts

// src/public-path.tsif ((window as any).__POWERED_BY_QIANKUN__) { __webpack_public_path__ = (window as any).__INJECTED_PUBLIC_PATH_BY_QIANKUN__;}

如上面代码报错,可以通过补充定义进行修复。以下代码最好放到全局引入的 TypeScript 定义文件中。

interface Window { __POWERED_BY_QIANKUN__?: string __INJECTED_PUBLIC_PATH_BY_QIANKUN__?: string}declare let __webpack_public_path__: string | undefined

设置 history 模式路由的 base

// src/App.tsximport React from 'react';import { Routes, Route, BrowserRouter} from 'react-router-dom'import './App.css';import Home from './components/home';function App() { return ( <div> {/* 设置路由命名空间 */} <BrowserRouter basename={window.__POWERED_BY_QIANKUN__ ? '/react' : '/'}> <Routes> <Route path="/" element={<Home />} /> </Routes> </BrowserRouter> </div> );}export default App;

修改入口文件 index.tsx

// src/index.tsximport React from 'react';import ReactDOM from 'react-dom';import './index.css';import App from './App';import reportWebVitals from './reportWebVitals';import './types.d.ts'import "./public-path";/** * bootstrap 只会在微应用初始化的时候调用一次,下次微应用重新进入时会直接调用 mount 钩子,不会再重复触发 bootstrap。 * 通常我们可以在这里做一些全局变量的初始化,比如不会在 unmount 阶段被销毁的应用级别的缓存等。 */export async function bootstrap() { console.log('react-app bootstraped');}/** * 应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法 */export async function mount(props: any) { console.log('react-app mount'); ReactDOM.render(<App />, props.container ? props.container.querySelector('#root') : document.getElementById('root'));}/** * 应用每次 切出/卸载 会调用的方法,通常在这里我们会卸载微应用的应用实例 */export async function unmount(props: any) { console.log('react-app unmount'); ReactDOM.unmountComponentAtNode(props.container ? props.container.querySelector('#root') : document.getElementById('root'));}/** * 可选生命周期钩子,仅使用 loadMicroApp 方式加载微应用时生效 */export async function update(props: any) { console.log('react-app update props', props);}ReactDOM.render( <React.StrictMode> <App /> </React.StrictMode>, document.getElementById('root'));// If you want to start measuring performance in your app, pass a function// to log results (for example: reportWebVitals(console.log))// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitalsreportWebVitals();

修改 webpack 配置,安装插件 react-app-rewired

npm install react-app-rewired -D

修改 package.json

// react-app/package.json"scripts": { "start": "react-app-rewired start", "build": "react-app-rewired build", "test": "react-app-rewired test", "eject": "react-app-rewired eject"}

在 react-app-rewired 配置完成后,新建 config-overrides.js 文件来配置 webpack。

// react-app/config-overrides.jsconst path = require("path");const APP_NAME = require("./package.json").name;module.exports = { webpack: (config) => { // 微应用的包名,这里与主应用中注册的微应用名称一致 config.output.library = APP_NAME; // 将你的 library 暴露为所有的模块定义下都可运行的方式 config.output.libraryTarget = "umd"; // 按需加载相关,设置为 webpackJsonp_VueMicroApp 即可 config.output.chunkLoadingGlobal = `webpackJsonp_${APP_NAME}`; config.output.globalObject = 'window'; config.output.publicPath = `//localhost:${process.env.PORT}/`; config.resolve.alias = { ...config.resolve.alias, "@": path.resolve(__dirname, "src"), }; return config; }, devServer: function (configFunction) { return function (proxy, allowedHost) { const config = configFunction(proxy, allowedHost); // 关闭主机检查,使微应用可以被 fetch // config.disableHostCheck = true; config.allowedHosts = "all"; // 配置跨域请求头,解决开发环境的跨域问题 config.headers = { "Access-Control-Allow-Origin": "*", }; // 配置 history 模式 config.historyApiFallback = true; return config; }; },};

3⃣️、运行效果如下

本文链接地址:https://www.jiuchutong.com/zhishi/294478.html 转载请保留说明!

上一篇:ElementUI中Tree组件使用(element-ui tree)

下一篇:CCNA-应试教育-思科网院-CCNAv7: Switching, Routing, and Wireless Essentials 交换、路由和无线基础。(ccna 试题)

  • 如何安装appsync补丁(如何安装appsync)(如何安装打印机驱动程序到电脑)

    如何安装appsync补丁(如何安装appsync)(如何安装打印机驱动程序到电脑)

  • 笔记本网卡在哪里办理(笔记本网卡在哪里买)

    笔记本网卡在哪里办理(笔记本网卡在哪里买)

  • ie浏览器下载的文件在哪里查看(ie浏览器下载的文件不见了怎么办)

    ie浏览器下载的文件在哪里查看(ie浏览器下载的文件不见了怎么办)

  • 重新下载微信怎么恢复聊天记录(重新下载微信怎么没有聊天记录了)

    重新下载微信怎么恢复聊天记录(重新下载微信怎么没有聊天记录了)

  • 腾讯会议导入文档失败是什么原因(腾讯会议导入文档自己能看别人能看吗)

    腾讯会议导入文档失败是什么原因(腾讯会议导入文档自己能看别人能看吗)

  • 掌上电脑和平板电脑的区别(掌上电脑和平板电脑一样吗)

    掌上电脑和平板电脑的区别(掌上电脑和平板电脑一样吗)

  • k3是什么手机(手机k3是多大尺寸)

    k3是什么手机(手机k3是多大尺寸)

  • iphone6怎么隐藏软件(iphone6怎么隐藏游戏)

    iphone6怎么隐藏软件(iphone6怎么隐藏游戏)

  • 茄子视频为什么下载不了了(茄子视频为什么越往里越有轻)

    茄子视频为什么下载不了了(茄子视频为什么越往里越有轻)

  • 手机怎么进入网络设置(手机怎么进入网桥设置)

    手机怎么进入网络设置(手机怎么进入网桥设置)

  • 无线网拒绝接入是什么原因(无线网拒绝接入是什么问题)

    无线网拒绝接入是什么原因(无线网拒绝接入是什么问题)

  • 苹果x和6plus谁尺寸大(苹果x和苹果6p对比)

    苹果x和6plus谁尺寸大(苹果x和苹果6p对比)

  • 苹果手机无法激活需要更新(苹果手机无法激活要连接mac)

    苹果手机无法激活需要更新(苹果手机无法激活要连接mac)

  • 屏幕切换快捷键是什么(屏幕切换快捷键是什么 双屏)

    屏幕切换快捷键是什么(屏幕切换快捷键是什么 双屏)

  • sim卡能识别但是无服务(sim卡能识别但是无服务打不出电话)

    sim卡能识别但是无服务(sim卡能识别但是无服务打不出电话)

  • 京东退货要卖家地址吗(京东退货卖家不同意怎么办)

    京东退货要卖家地址吗(京东退货卖家不同意怎么办)

  • 手机支付宝怎么领红包(手机支付宝怎么查余额)

    手机支付宝怎么领红包(手机支付宝怎么查余额)

  • 手机qq怎么自定义名片(手机qq怎么自定义背景)

    手机qq怎么自定义名片(手机qq怎么自定义背景)

  • 饿了吗发票怎么拿(饿了吗发票怎么打印)

    饿了吗发票怎么拿(饿了吗发票怎么打印)

  • vivo手机关闭sos(VIVO手机关闭密码解锁)

    vivo手机关闭sos(VIVO手机关闭密码解锁)

  • 如何创建百度百科(如何创建百度百家号)

    如何创建百度百科(如何创建百度百家号)

  • 理光gr1和gr2差别(理光gr1s和gr1v区别)

    理光gr1和gr2差别(理光gr1s和gr1v区别)

  • 怎样设置页脚(怎样设置页脚日期的格式)

    怎样设置页脚(怎样设置页脚日期的格式)

  • iphone如何屏蔽号码段(iphone如何屏蔽号码段短信)

    iphone如何屏蔽号码段(iphone如何屏蔽号码段短信)

  • 纯外贸出口企业出售固定
  • 分公司预缴企业所得税怎么算
  • 押金收不回来没钱怎么办
  • 计提坏账准备怎么理解
  • 在建工程账务处理流程
  • 哪些补贴可以不交个税
  • 保教费免征增值税政策
  • 营业外支出计入
  • 银行和保险公司是什么关系
  • 缴纳印花税税会计分录怎么做
  • 外币结算方式有哪几种
  • 可供出售债券投资
  • 企业所得税汇算清缴退税账务处理
  • 外省工程需要什么手续
  • 增值税交完之后还要交什么税
  • 借方和贷方是什么意思银行存款
  • 资源税纳税期限按月还是按季
  • 汽车厂家金融贴息 是贴利息的还是贴车价
  • 残联备案还能补申报吗
  • 如何关闭edge浏览器下载保护
  • 苹果系统更新在哪里找
  • 新版edge浏览器兼容模式怎么设置
  • 桌面图标变成了一张纸
  • 利润是如何转化成平均利润的
  • 个税手续费返还属于政府补助吗
  • 旅客购买电子客票
  • 旅游费用账务处理
  • 暂估入库入库单范本
  • 票据权利消灭是啥意思
  • 物业公司成本结转方案
  • php面向对象是什么意思
  • php类的作用
  • 股份支付有哪些基本类型
  • 会计科目怎么调账
  • 什么是分红型保险?
  • vue treegrid
  • import vue from vue报错
  • 图像分割csdn
  • 增资扩股税务处罚标准
  • 税负率一般控制什么
  • 工程公司收到工程款会计分录
  • 哪些发票可以抵企业所得税
  • 分公司非独立核算企业所得税处理
  • mysql一对多关系如何一次性查出来
  • 公对公二手车交易税
  • mysql @参数
  • 帝国cms批量excel导入文章
  • 代扣车船税手续费按多少返还
  • 同一控制下企业合并发生的审计费用计入
  • 企业需要购买两种保险吗
  • mysql和mongo的区别
  • 增值税发票真假怎么查询
  • 如何理解当期损益
  • 小规模减免附加税会计分录怎么做
  • 小规模纳税人的税率是多少
  • 减免残保金相关政策
  • 将购进的材料用于自制生产用设备
  • 营业外支出的性质
  • 销售一批产品给丙公司,该批产品标价200万yuan
  • 出纳需要遵循的原则
  • mysql could not be resolved: Name or service not known
  • sql server怎么复制表
  • mysql 数据修改
  • win8搜索程序和文件在哪里
  • linux 更新系统
  • ubuntu debian centos
  • windows8蓝牙设置在哪里
  • Win10控制面板打不开
  • Extjs Label的 fieldLabel和html属性值对齐的方法
  • linuxparted命令
  • python数据可视化课后题答案
  • 事件传播路径
  • Unity同时接入ShareSdk和微派支付sdk(二)
  • shell 执行sh
  • php常用函数200个
  • 理解JavaScript事件对象
  • 容易混淆的词汇
  • jquery.browser
  • css实现3d效果
  • 交17000办的保险是什么保险
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设