微前端 Spa qiankun

devtools/2024/10/24 2:10:10/

简介

首先什么是微前端

他是一个软件架构模式。借鉴了后端的为服务架构思想,是将复杂单一的前端进行拆分成多个可以独立开发、部署、维护的小型应用。不同的应用关注不同的业务。最终将其集成到一个主框架里面。简单来说就是先分后合。

传统前端开发的痛点

有这么一个场景,你现在在实际工作当中维护了一个vue项目。这个项目里面现在有了业务A、业务B、业务C…,然后还有系统登录权限、公共配置等模块,就导致这个vue项目很大,尤其是对于vue2+webpack来说打包速度堪忧。这个时候微前端就有用武之地了。将每一个业务模块都拆分出来独立进行开发之后统一合并部署,大大的提升了维护,同时如果需要将其整体从vue2迁移到vue3同样也是如此逐渐迁移。

微前端实现方案

iframe

这个就比较简单,开发一个菜单然后主题内容就根据菜单的切换更换这个主体iframe包的url地址就好了。

为什么不用ifream

web Components

web组件:也就是基于原生来创建组件,像vue当中的组件也是这样实现的。

  • 自定义元素:定义元素及其行为
  • 影子Dom:将封装的“影子”DOM 树附加到元素并控制其关联的功能。使用这种方式保持元素的功能私有,不用担心与文档的其他部分发生冲突。
  • html 模板:<template><slot> 元素可以作为标记模板

无界微前端组件实现案例:

假设我有一个叫child.html的文件,里面对h1元素的样式进行了改变,现在我有一个父页面需要加载child.html当中的代码进来并且要实现样式隔离。

  • 创建class类继承HTMLElement。通过getAttribute可以获取到wu-jie标签当中的所有属性
  • 通过loadFile方法获取child的html代码,通过attachShadow创建一个影子DOM
  • 最后将这个影子DOM和child的代码合到一起加到主页面当中。
<span class="token doctype"><span class="token punctuation"><!span><span class="token doctype-tag">DOCTYPEspan> <span class="token name">htmlspan><span class="token punctuation">>span>span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><span>htmlspan> <span class="token attr-name">langspan><span class="token attr-value"><span class="token punctuation attr-equals">=span><span class="token punctuation">"span>en<span class="token punctuation">"span>span><span class="token punctuation">>span>span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><span>headspan><span class="token punctuation">>span>span><span class="token tag"><span class="token tag"><span class="token punctuation"><span>metaspan> <span class="token attr-name">charsetspan><span class="token attr-value"><span class="token punctuation attr-equals">=span><span class="token punctuation">"span>UTF-8<span class="token punctuation">"span>span><span class="token punctuation">>span>span><span class="token tag"><span class="token tag"><span class="token punctuation"><span>metaspan> <span class="token attr-name">namespan><span class="token attr-value"><span class="token punctuation attr-equals">=span><span class="token punctuation">"span>viewport<span class="token punctuation">"span>span> <span class="token attr-name">contentspan><span class="token attr-value"><span class="token punctuation attr-equals">=span><span class="token punctuation">"span>width=device-width, initial-scale=1.0<span class="token punctuation">"span>span><span class="token punctuation">>span>span><span class="token tag"><span class="token tag"><span class="token punctuation"><span>titlespan><span class="token punctuation">>span>span>PCM Player<span class="token tag"><span class="token tag"><span class="token punctuation"></span>titlespan><span class="token punctuation">>span>span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></span>headspan><span class="token punctuation">>span>span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><span>bodyspan><span class="token punctuation">>span>span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><span>h1span><span class="token punctuation">>span>span>我是一级标题<span class="token tag"><span class="token tag"><span class="token punctuation"></span>h1span><span class="token punctuation">>span>span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><span>wu-jiespan> <span class="token attr-name">srcspan><span class="token attr-value"><span class="token punctuation attr-equals">=span><span class="token punctuation">"span>http://localhost:63342/CimH5/src/views/home/child.html<span class="token punctuation">"span>span><span class="token punctuation">/>span>span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><span>scriptspan><span class="token punctuation">>span>span><span class="token script"><span class="token language-javascript"><span class="token keyword">constspan> <span class="token function-variable function">loadFilespan> <span class="token operator">=span> <span class="token keyword">asyncspan> <span class="token punctuation">(span><span class="token parameter">srcspan><span class="token punctuation">)span> <span class="token operator">=>span> <span class="token punctuation">{span><span class="token keyword">returnspan> <span class="token keyword">awaitspan> <span class="token function">fetchspan><span class="token punctuation">(span>src<span class="token punctuation">)span><span class="token punctuation">.span><span class="token function">thenspan><span class="token punctuation">(span><span class="token parameter">resspan> <span class="token operator">=>span> res<span class="token punctuation">.span><span class="token function">textspan><span class="token punctuation">(span><span class="token punctuation">)span><span class="token punctuation">)span><span class="token punctuation">;span><span class="token punctuation">}span><span class="token punctuation">;span><span class="token keyword">constspan> <span class="token function-variable function">injectHTMLspan> <span class="token operator">=span> <span class="token punctuation">(span><span class="token parameter">shadowRoot<span class="token punctuation">,span> htmlspan><span class="token punctuation">)span> <span class="token operator">=>span> <span class="token punctuation">{span><span class="token keyword">constspan> wrapper <span class="token operator">=span> document<span class="token punctuation">.span><span class="token function">createElementspan><span class="token punctuation">(span><span class="token string">'div'span><span class="token punctuation">)span><span class="token punctuation">;span>wrapper<span class="token punctuation">.span>innerHTML <span class="token operator">=span> html<span class="token punctuation">;span>shadowRoot<span class="token punctuation">.span><span class="token function">appendChildspan><span class="token punctuation">(span>wrapper<span class="token punctuation">)span><span class="token punctuation">;span><span class="token punctuation">}span><span class="token punctuation">;span><span class="token keyword">classspan> <span class="token class-name">WUJIEspan> <span class="token keyword">extendsspan> <span class="token class-name">HTMLElementspan> <span class="token punctuation">{span><span class="token function">constructorspan><span class="token punctuation">(span><span class="token punctuation">)span> <span class="token punctuation">{span><span class="token keyword">superspan><span class="token punctuation">(span><span class="token punctuation">)span><span class="token punctuation">;span><span class="token keyword">thisspan><span class="token punctuation">.span>src <span class="token operator">=span> <span class="token keyword">thisspan><span class="token punctuation">.span><span class="token function">getAttributespan><span class="token punctuation">(span><span class="token string">'src'span><span class="token punctuation">)span><span class="token punctuation">;span><span class="token punctuation">}span><span class="token keyword">asyncspan> <span class="token function">connectedCallbackspan><span class="token punctuation">(span><span class="token punctuation">)span> <span class="token punctuation">{span><span class="token keyword">constspan> html <span class="token operator">=span> <span class="token keyword">awaitspan> <span class="token function">loadFilespan><span class="token punctuation">(span><span class="token keyword">thisspan><span class="token punctuation">.span>src<span class="token punctuation">)span><span class="token punctuation">;span><span class="token keyword">constspan> shadowRoot <span class="token operator">=span> <span class="token keyword">thisspan><span class="token punctuation">.span><span class="token function">attachShadowspan><span class="token punctuation">(span><span class="token punctuation">{span>mode<span class="token operator">:span> <span class="token string">'open'span><span class="token punctuation">}span><span class="token punctuation">)span><span class="token punctuation">;span><span class="token function">injectHTMLspan><span class="token punctuation">(span>shadowRoot<span class="token punctuation">,span> html<span class="token punctuation">)span><span class="token punctuation">;span>console<span class="token punctuation">.span><span class="token function">logspan><span class="token punctuation">(span><span class="token string">'得到子应用的代码 ====='span><span class="token punctuation">,span> html<span class="token punctuation">)span><span class="token punctuation">;span><span class="token punctuation">}span><span class="token punctuation">}span>window<span class="token punctuation">.span>customElements<span class="token punctuation">.span><span class="token function">definespan><span class="token punctuation">(span><span class="token string">'wu-jie'span><span class="token punctuation">,span> <span class="token constant">WUJIEspan><span class="token punctuation">)span><span class="token punctuation">;span>
span>span><span class="token tag"><span class="token tag"><span class="token punctuation"></span>scriptspan><span class="token punctuation">>span>span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></span>bodyspan><span class="token punctuation">>span>span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></span>htmlspan><span class="token punctuation">>span>span>

这样也就完成了组件之间的样式隔离(也就是经常听到的沙箱)

沙箱:是一种用于隔离正在运行程序的安全机制,通常用于执行未经测试或者不受信任的程序或代码,它会为待执行的程序创建一个独立的执行环境,内部程序的执行不会影响到外部程序的运行。也就是不同应用之间虽然同时运行在同一个html当中但是js、css不会混淆到一起,互不影响。

在这里插入图片描述

spa_83">single-spa(单页面)

通过路由劫持实现应用加载(采用systemjs)

  • 优:基于props主子应用通信
  • 缺:无沙箱

module federation

通过模块联邦将组件打包导出使用

  • 优:共享模块的方式进行通信
  • 缺:无沙箱,需要使用webpack5

spa_97">single-spa

简介

spa(single page application)是一个将多个单页面应用聚合为一个整体应用的 js 微前端框架

single-spa会在基座应用中维护一个路由注册表,每个路由对应一个子应用。基座应用启动以后,当我们切换路由时,如果是一个新的子应用,会动态获取子应用的 js 脚本,然后执行脚本并渲染出相应的页面;如果是一个已经访问过的子应用,那么就会从缓存中获取已经缓存的子应用,激活子应用并渲染出对应的页面

实战

spa_107">安装spa&初始化应用

全局安装脚手架

npm install --global create-single-spa

创建一个基座应用,在通过脚手架创建应用的时候会有这几个选项,可以看一下,分别就是用来创建子应用、基座、公共模块三个大类的

'single-spa-application / parcel':微前端架构中的微应用,可以使用 vue、react、angular 等框架。
'single-spa root config':创建微前端容器应用。
'utility modules':公共模块应用,非渲染组件,用于跨应用共享 javascript 逻辑的微应用
C:\Users\modify>create-single-spa base
? Select type to generate single-spa root config
? Which package manager do you want to use? npm
? Will this project use Typescript? No
? Would you like to use single-spa Layout Engine No
? Organization name (can use letters, numbers, dash or underscore) QmQ
Initialized empty Git repository in C:/Users/modify/base/.git/

创建子应用,这里创建一个vue和react的项目。下面演示一下创建react项目的,vue项目也是一样

D:\mygit\spa>create-single-spa react-app
? Select type to generate single-spa application / parcel
? Which framework do you want to use? react
? Which package manager do you want to use? npm
? Will this project use Typescript? No
? Organization name (can use letters, numbers, dash or underscore) modify
? Project name (can use letters, numbers, dash or underscore) react-app
Initialized empty Git repository in D:/mygit/spa/react-app/.git/

spa_146">spa代码说明

base基座

在src下的index.ejs当中可以直接找到下面这个代码,这个代码就是用来给基座和子应用进行关联的。

    <span class="token operator"><span><span class="token operator">%span> <span class="token keyword">ifspan> <span class="token punctuation">(span>isLocal<span class="token punctuation">)span> <span class="token punctuation">{span> <span class="token operator">%span><span class="token operator">>span><span class="token operator"><span>script type<span class="token operator">=span><span class="token string">"systemjs-importmap"span><span class="token operator">>span><span class="token punctuation">{span><span class="token string">"imports"span><span class="token operator">:span> <span class="token punctuation">{span><span class="token string">"@modify/root-config"span><span class="token operator">:span> <span class="token string">"//localhost:9000/modify-root-config.js"span><span class="token punctuation">,span><span class="token punctuation">}span><span class="token punctuation">}span><span class="token operator"><span><span class="token operator">/span>script<span class="token operator">>span><span class="token operator"><span><span class="token operator">%span> <span class="token punctuation">}span> <span class="token operator">%span><span class="token operator">>span>

然后看同样的src下的modify-root-config.js这个名字适合创建的时候设置的Organization name有关的,所以文件名是有区别的

<span class="token keyword">importspan> <span class="token punctuation">{span>registerApplication<span class="token punctuation">,span> start<span class="token punctuation">}span> <span class="token keyword">fromspan> <span class="token string">'single-spa'span><span class="token punctuation">;span><span class="token comment">// 服务注册span>
<span class="token comment">// 这里用到的name属性也就一个标识,然后通过SystemJs导入一个外部jsspan>
<span class="token function">registerApplicationspan><span class="token punctuation">(span><span class="token punctuation">{span>name<span class="token operator">:span> <span class="token string">'@single-spa/welcome'span><span class="token punctuation">,span><span class="token function-variable function">appspan><span class="token operator">:span> <span class="token punctuation">(span><span class="token punctuation">)span> <span class="token operator">=>span>System<span class="token punctuation">.span><span class="token function">importspan><span class="token punctuation">(span><span class="token string">'https://unpkg.com/single-spa-welcome/dist/single-spa-welcome.js'span><span class="token punctuation">)span><span class="token punctuation">,span><span class="token comment">// 这里表示路由,因为生成的路由是["/"]这个表示以/开头的都会走这个规则也就是访问上面那个js,所以这里进行了调整span><span class="token function-variable function">activeWhenspan><span class="token operator">:span> <span class="token parameter">locationspan> <span class="token operator">=>span> location<span class="token punctuation">.span>pathname <span class="token operator">===span> <span class="token string">'/'span>
<span class="token punctuation">}span><span class="token punctuation">)span><span class="token punctuation">;span><span class="token comment">// 启动span>
<span class="token function">startspan><span class="token punctuation">(span><span class="token punctuation">{span>urlRerouteOnly<span class="token operator">:span> <span class="token boolean">truespan>
<span class="token punctuation">}span><span class="token punctuation">)span><span class="token punctuation">;span>
vue项目

这里的vue3项目当中会有两个启动命令,一个serve一个serve:standalone。区别在于是否serve是基于微前端spa启动的,而standalone是独立启动,和平常我们使用的vue项目启动是一样的。

在使用命令serve:standalone进行启动报错:

single-spa.dev.js:155 Uncaught TypeError: application '@modify/vue-app' died in status LOADING_SOURCE_CODE: Cannot read properties of undefined (reading 'meta')xxxx

解决方案:修改vue.config.js文件,GitHub issues

<span class="token keyword">constspan> <span class="token punctuation">{span>defineConfig<span class="token punctuation">}span> <span class="token operator">=span> <span class="token function">requirespan><span class="token punctuation">(span><span class="token string">'@vue/cli-service'span><span class="token punctuation">)span><span class="token punctuation">;span>
module<span class="token punctuation">.span>exports <span class="token operator">=span> <span class="token function">defineConfigspan><span class="token punctuation">(span><span class="token punctuation">{span>transpileDependencies<span class="token operator">:span> <span class="token boolean">truespan><span class="token punctuation">,span>devServer<span class="token operator">:span> <span class="token punctuation">{span>port<span class="token operator">:span> <span class="token number">3000span><span class="token punctuation">}span><span class="token punctuation">,span>configureWebpack<span class="token operator">:span> <span class="token punctuation">{span>output<span class="token operator">:span> <span class="token punctuation">{span>libraryTarget<span class="token operator">:span> <span class="token string">'system'span><span class="token punctuation">}span><span class="token punctuation">}span>
<span class="token punctuation">}span><span class="token punctuation">)span><span class="token punctuation">;span>

项目关联

关联vue项目

看了这些,那怎么把vue项目和基座项目关联起来呢?首先这里我的vue项目名是@modify/vue-app(看package.json的name属性)之后再base基座项目当中的modify-root-config.js添加配置,表示将vue项目注册到基座当中

<span class="token function">registerApplicationspan><span class="token punctuation">(span><span class="token punctuation">{span><span class="token comment">// vue项目名称span>name<span class="token operator">:span> <span class="token string">'@modify/vue-app'span><span class="token punctuation">,span><span class="token function-variable function">appspan><span class="token operator">:span> <span class="token punctuation">(span><span class="token punctuation">)span> <span class="token operator">=>span><span class="token comment">// 导入模块span>System<span class="token punctuation">.span><span class="token function">importspan><span class="token punctuation">(span><span class="token string">'@modify/vue-app'span><span class="token punctuation">)span><span class="token punctuation">,span><span class="token comment">// 指定访问路径span><span class="token function-variable function">activeWhenspan><span class="token operator">:span> <span class="token parameter">locationspan> <span class="token operator">=>span> location<span class="token punctuation">.span>pathname <span class="token operator">===span> <span class="token string">'/vue'span>
<span class="token punctuation">}span><span class="token punctuation">)span><span class="token punctuation">;span>

在index.ejs代码当中添加导入关联配置

    <span class="token operator"><span><span class="token operator">%span> <span class="token keyword">ifspan> <span class="token punctuation">(span>isLocal<span class="token punctuation">)span> <span class="token punctuation">{span> <span class="token operator">%span><span class="token operator">>span><span class="token operator"><span>script type<span class="token operator">=span><span class="token string">"systemjs-importmap"span><span class="token operator">>span><span class="token punctuation">{span><span class="token string">"imports"span><span class="token operator">:span> <span class="token punctuation">{span><span class="token string">"@modify/root-config"span><span class="token operator">:span> <span class="token string">"//localhost:9000/modify-root-config.js"span><span class="token punctuation">,span><span class="token comment">// 和上面System.import导入的名称一致。span><span class="token string">"@modify/vue-app"span><span class="token operator">:span> <span class="token string">"//localhost:3000/js/app.js"span><span class="token punctuation">}span><span class="token punctuation">}span><span class="token operator"><span><span class="token operator">/span>script<span class="token operator">>span><span class="token operator"><span><span class="token operator">%span> <span class="token punctuation">}span> <span class="token operator">%span><span class="token operator">>span>

这里就可能会有问题了,你指定了vue项目的端口是3000我知道,那你是怎么知道后面加/js/app.js这个路径呢?这个时候我们通过serve去启动vue项目,访问3000可以看到下面这个样子,简单翻译一下就懂了。最后访问基座项目加到对应路由也就是:localhost:9000/vue也是能访问这个vue项目的,就说明配置关联成功了。

在这里插入图片描述

关联react项目

这个和vue项目是一样的,还是先添加注册的规则,然后启动react项目看微前端的react指向的地址,然后添加配置即可,也就是这样

    <span class="token operator"><span><span class="token operator">%span> <span class="token keyword">ifspan> <span class="token punctuation">(span>isLocal<span class="token punctuation">)span> <span class="token punctuation">{span> <span class="token operator">%span><span class="token operator">>span><span class="token operator"><span>script type<span class="token operator">=span><span class="token string">"systemjs-importmap"span><span class="token operator">>span><span class="token punctuation">{span><span class="token string">"imports"span><span class="token operator">:span> <span class="token punctuation">{span><span class="token string">"@modify/root-config"span><span class="token operator">:span> <span class="token string">"//localhost:9000/modify-root-config.js"span><span class="token punctuation">,span><span class="token string">"@modify/vue-app"span><span class="token operator">:span> <span class="token string">"//localhost:3000/js/app.js"span><span class="token punctuation">,span><span class="token string">"@modify/react-app"span><span class="token operator">:span> <span class="token string">"//localhost:4000/modify-react-app.js"span><span class="token punctuation">}span><span class="token punctuation">}span><span class="token operator"><span><span class="token operator">/span>script<span class="token operator">>span><span class="token operator"><span><span class="token operator">%span> <span class="token punctuation">}span> <span class="token operator">%span><span class="token operator">>span>
基座与vue项目传参

还是在基座路由规则这添加一个customProps表示传递过去的数据,传的是一个对象。

<span class="token function">registerApplicationspan><span class="token punctuation">(span><span class="token punctuation">{span>name<span class="token operator">:span> <span class="token string">'@modify/vue-app'span><span class="token punctuation">,span><span class="token function-variable function">appspan><span class="token operator">:span> <span class="token punctuation">(span><span class="token punctuation">)span> <span class="token operator">=>span>System<span class="token punctuation">.span><span class="token function">importspan><span class="token punctuation">(span><span class="token string">'@modify/vue-app'span><span class="token punctuation">)span><span class="token punctuation">,span><span class="token function-variable function">activeWhenspan><span class="token operator">:span> <span class="token parameter">locationspan> <span class="token operator">=>span> location<span class="token punctuation">.span>pathname <span class="token operator">===span> <span class="token string">'/vue'span><span class="token punctuation">,span>customProps<span class="token operator">:span> <span class="token punctuation">{span>a<span class="token operator">:span> <span class="token number">1span><span class="token punctuation">}span><span class="token punctuation">,span>
<span class="token punctuation">}span><span class="token punctuation">)span><span class="token punctuation">;span>

在vue项目当中的main.js文件当中可以进行接收,在这里可以通过this拿到a的值,之后在vue文件当中就可以通过defineProps拿到这个a了。

<span class="token keyword">constspan> vueLifecycles <span class="token operator">=span> <span class="token function">singleSpaVuespan><span class="token punctuation">(span><span class="token punctuation">{span>createApp<span class="token punctuation">,span>appOptions<span class="token operator">:span> <span class="token punctuation">{span><span class="token function">renderspan><span class="token punctuation">(span><span class="token punctuation">)span> <span class="token punctuation">{span><span class="token keyword">returnspan> <span class="token function">hspan><span class="token punctuation">(span>App<span class="token punctuation">,span> <span class="token punctuation">{span>a<span class="token operator">:span> <span class="token keyword">thisspan><span class="token punctuation">.span>a<span class="token punctuation">}span><span class="token punctuation">)span><span class="token punctuation">;span><span class="token punctuation">}span><span class="token punctuation">}span>
<span class="token punctuation">}span><span class="token punctuation">)span><span class="token punctuation">;span>

乾坤

乾坤demo地址:https://github.com/lizuoqun/spa/tree/master/qiankun-base

基座(主应用)

先构建一个vue3的前端项目,之后安装一下qiankun。用vue3项目当做一个主应用基座

npm create vite@latest qiankun-base
cd qiankun-base
npm install
npm i qiankun -S
npm run dev

入口改造

在这里简单说明一下,注册了一个react应用,react应用访问的地址是3000端口+react-app,这个在下面创建react主应用可以看到,然后配置了qiankun的生命周期。

<span class="token keyword">importspan> <span class="token punctuation">{span>createApp<span class="token punctuation">}span> <span class="token keyword">fromspan> <span class="token string">'vue'span><span class="token punctuation">;span>
<span class="token keyword">importspan> <span class="token string">'./style.css'span><span class="token punctuation">;span>
<span class="token keyword">importspan> App <span class="token keyword">fromspan> <span class="token string">'./App.vue'span><span class="token punctuation">;span>
<span class="token keyword">importspan> <span class="token punctuation">{span>registerMicroApps<span class="token punctuation">,span> start<span class="token punctuation">}span> <span class="token keyword">fromspan> <span class="token string">'qiankun'span><span class="token punctuation">;span><span class="token comment">// 注册的所有子应用span>
<span class="token keyword">constspan> <span class="token constant">QIANKUN_APPSspan> <span class="token operator">=span> <span class="token punctuation">[span><span class="token punctuation">{span>name<span class="token operator">:span> <span class="token string">'react app'span><span class="token punctuation">,span> <span class="token comment">// 子应用名称span>entry<span class="token operator">:span> <span class="token string">'//localhost:3000'span><span class="token punctuation">,span> <span class="token comment">// 子应用的IP端口span>container<span class="token operator">:span> <span class="token string">'#reactAppContainer'span><span class="token punctuation">,span> <span class="token comment">// 子应用渲染到哪个容器当中span>activeRule<span class="token operator">:span> <span class="token string">'/react-app'span> <span class="token comment">// 子应用访问的路径span><span class="token punctuation">}span>
<span class="token punctuation">]span><span class="token punctuation">;span>
<span class="token comment">// qiankun生命周期span>
<span class="token keyword">constspan> <span class="token constant">QIANKUN_LIFECYCLEspan> <span class="token operator">=span> <span class="token punctuation">{span>beforeLoad<span class="token operator">:span> <span class="token punctuation">[span><span class="token keyword">asyncspan> <span class="token punctuation">(span><span class="token parameter">app<span class="token operator">:span> anyspan><span class="token punctuation">)span> <span class="token operator">=>span> <span class="token punctuation">{span>console<span class="token punctuation">.span><span class="token function">logspan><span class="token punctuation">(span><span class="token string">'before load ====='span><span class="token punctuation">,span> app<span class="token punctuation">.span>name<span class="token punctuation">)span><span class="token punctuation">;span><span class="token punctuation">}span><span class="token punctuation">]span><span class="token punctuation">,span>beforeMount<span class="token operator">:span> <span class="token punctuation">[span><span class="token keyword">asyncspan> <span class="token punctuation">(span><span class="token parameter">app<span class="token operator">:span> anyspan><span class="token punctuation">)span> <span class="token operator">=>span> <span class="token punctuation">{span>console<span class="token punctuation">.span><span class="token function">logspan><span class="token punctuation">(span><span class="token string">'before mount ====='span><span class="token punctuation">,span> app<span class="token punctuation">.span>name<span class="token punctuation">)span><span class="token punctuation">;span><span class="token punctuation">}span><span class="token punctuation">]span><span class="token punctuation">,span>afterUnmount<span class="token operator">:span> <span class="token punctuation">[span><span class="token keyword">asyncspan> <span class="token punctuation">(span><span class="token parameter">app<span class="token operator">:span> anyspan><span class="token punctuation">)span> <span class="token operator">=>span> <span class="token punctuation">{span>console<span class="token punctuation">.span><span class="token function">logspan><span class="token punctuation">(span><span class="token string">'after unmount ====='span><span class="token punctuation">,span> app<span class="token punctuation">.span>name<span class="token punctuation">)span><span class="token punctuation">;span><span class="token punctuation">}span><span class="token punctuation">]span>
<span class="token punctuation">}span><span class="token punctuation">;span>
<span class="token function">registerMicroAppsspan><span class="token punctuation">(span><span class="token constant">QIANKUN_APPSspan><span class="token punctuation">,span> <span class="token constant">QIANKUN_LIFECYCLEspan><span class="token punctuation">)span><span class="token punctuation">;span><span class="token function">startspan><span class="token punctuation">(span><span class="token punctuation">)span><span class="token punctuation">;span>
<span class="token function">createAppspan><span class="token punctuation">(span>App<span class="token punctuation">)span><span class="token punctuation">.span><span class="token function">mountspan><span class="token punctuation">(span><span class="token string">'#app'span><span class="token punctuation">)span><span class="token punctuation">;span>

React子应用

项目初始化

通过命令创建一个react项目

<span class="token function">npmspan> <span class="token function">installspan> -g create-react-app
create-react-app react-app

这里有可能创建之后启动项目会出现报错,直接全局搜索把引入这个web-vitals的代码注释掉即可。

Module not found: Error: Can<span class="token string">'t resolve 'span>web-vitals'

入口改造

修改index.js入口文件。

<span class="token keyword">importspan> React <span class="token keyword">fromspan> <span class="token string">'react'span><span class="token punctuation">;span>
<span class="token keyword">importspan> ReactDOM <span class="token keyword">fromspan> <span class="token string">'react-dom/client'span><span class="token punctuation">;span>
<span class="token keyword">importspan> <span class="token string">'./index.css'span><span class="token punctuation">;span>
<span class="token keyword">importspan> App <span class="token keyword">fromspan> <span class="token string">'./App'span><span class="token punctuation">;span>
<span class="token keyword">importspan> reportWebVitals <span class="token keyword">fromspan> <span class="token string">'./reportWebVitals'span><span class="token punctuation">;span>
<span class="token keyword">importspan> <span class="token punctuation">{span>createRoot<span class="token punctuation">}span> <span class="token keyword">fromspan> <span class="token string">'react-dom/client'span><span class="token punctuation">;span>
<span class="token comment">// 安装下 npm i react-router-domspan>
<span class="token keyword">importspan> <span class="token punctuation">{span>BrowserRouter<span class="token punctuation">}span> <span class="token keyword">fromspan> <span class="token string">'react-router-dom'span><span class="token punctuation">;span>
<span class="token keyword">importspan> <span class="token string">'./public-path.js'span><span class="token keyword">letspan> root<span class="token punctuation">;span><span class="token keyword">functionspan> <span class="token function">renderspan><span class="token punctuation">(span><span class="token parameter">propsspan><span class="token punctuation">)span> <span class="token punctuation">{span><span class="token comment">// 判断子应用加载的时机(是嵌套在主应用下的还是直接单独运行加载的)span><span class="token keyword">constspan> <span class="token punctuation">{span>container<span class="token punctuation">}span> <span class="token operator">=span> props<span class="token punctuation">;span><span class="token keyword">constspan> dom <span class="token operator">=span> container <span class="token operator">?span> container<span class="token punctuation">.span><span class="token function">querySelectorspan><span class="token punctuation">(span><span class="token string">'#root'span><span class="token punctuation">)span> <span class="token operator">:span> document<span class="token punctuation">.span><span class="token function">querySelectorspan><span class="token punctuation">(span><span class="token string">'#root'span><span class="token punctuation">)span><span class="token punctuation">;span>root <span class="token operator">=span> <span class="token function">createRootspan><span class="token punctuation">(span>dom<span class="token punctuation">)span><span class="token punctuation">;span>root<span class="token punctuation">.span><span class="token function">renderspan><span class="token punctuation">(span><span class="token comment">// 默认路由span><span class="token operator"><span>BrowserRouter basename<span class="token operator">=span><span class="token string">"/react-app"span><span class="token operator">>span><span class="token operator"><span>App<span class="token operator">/span><span class="token operator">>span><span class="token operator"><span><span class="token operator">/span>BrowserRouter<span class="token operator">>span><span class="token punctuation">)span><span class="token punctuation">;span>
<span class="token punctuation">}span><span class="token function">reportWebVitalsspan><span class="token punctuation">(span><span class="token punctuation">)span><span class="token punctuation">;span><span class="token comment">// 判断是否在 qiankun 环境下运行span>
<span class="token keyword">ifspan> <span class="token punctuation">(span><span class="token operator">!span>window<span class="token punctuation">.span>__POWERED_BY_QIANKUN__<span class="token punctuation">)span> <span class="token punctuation">{span><span class="token function">renderspan><span class="token punctuation">(span><span class="token punctuation">{span><span class="token punctuation">}span><span class="token punctuation">)span><span class="token punctuation">;span>
<span class="token punctuation">}span><span class="token comment">// 生命周期。span>
<span class="token comment">// 1. bootstrap: 在主应用加载子应用之前,子应用的生命周期将被调用。span>
<span class="token comment">// 2. mount: 在主应用加载子应用之后,子应用的生命周期将被调用。span>
<span class="token comment">// 3. unmount: 当子应用被卸载时,子应用的生命周期将被调用。span><span class="token keyword">exportspan> <span class="token keyword">asyncspan> <span class="token keyword">functionspan> <span class="token function">bootstrapspan><span class="token punctuation">(span><span class="token punctuation">)span> <span class="token punctuation">{span>console<span class="token punctuation">.span><span class="token function">logspan><span class="token punctuation">(span><span class="token string">'[react16] react app bootstraped'span><span class="token punctuation">)span><span class="token punctuation">;span>
<span class="token punctuation">}span><span class="token keyword">exportspan> <span class="token keyword">asyncspan> <span class="token keyword">functionspan> <span class="token function">mountspan><span class="token punctuation">(span><span class="token parameter">propsspan><span class="token punctuation">)span> <span class="token punctuation">{span>console<span class="token punctuation">.span><span class="token function">logspan><span class="token punctuation">(span><span class="token string">'[react16] props from main framework'span><span class="token punctuation">,span> props<span class="token punctuation">)span><span class="token punctuation">;span><span class="token function">renderspan><span class="token punctuation">(span>props<span class="token punctuation">)span><span class="token punctuation">;span>
<span class="token punctuation">}span><span class="token keyword">exportspan> <span class="token keyword">asyncspan> <span class="token keyword">functionspan> <span class="token function">unmountspan><span class="token punctuation">(span><span class="token parameter">propsspan><span class="token punctuation">)span> <span class="token punctuation">{span><span class="token keyword">constspan> <span class="token punctuation">{span>container<span class="token punctuation">}span> <span class="token operator">=span> props<span class="token punctuation">;span>ReactDOM<span class="token punctuation">.span><span class="token function">unmountComponentAtNodespan><span class="token punctuation">(span>container <span class="token operator">?span> container<span class="token punctuation">.span><span class="token function">querySelectorspan><span class="token punctuation">(span><span class="token string">'#root'span><span class="token punctuation">)span> <span class="token operator">:span> document<span class="token punctuation">.span><span class="token function">querySelectorspan><span class="token punctuation">(span><span class="token string">'#root'span><span class="token punctuation">)span><span class="token punctuation">)span><span class="token punctuation">;span>
<span class="token punctuation">}span>

添加public-path.js

qiankun文档上面是没有eslint注释的代码,会导致项目运行出错,可以看 Github上看到的解决方案

<span class="token keyword">ifspan> <span class="token punctuation">(span>window<span class="token punctuation">.span>__POWERED_BY_QIANKUN__<span class="token punctuation">)span> <span class="token punctuation">{span><span class="token comment">// eslint-disable-next-line no-undefspan>__webpack_public_path__ <span class="token operator">=span> window<span class="token punctuation">.span>__INJECTED_PUBLIC_PATH_BY_QIANKUN__<span class="token punctuation">;span>
<span class="token punctuation">}span>

修改webpack配置

安装插件 @rescripts/cli,当然也可以选择其他的插件,例如 react-app-rewired

<span class="token function">npmspan> i -D @rescripts/cli

根目录新增 .rescriptsrc.js

<span class="token keyword">constspan> <span class="token punctuation">{span>name<span class="token punctuation">}span> <span class="token operator">=span> <span class="token function">requirespan><span class="token punctuation">(span><span class="token string">'./package'span><span class="token punctuation">)span><span class="token punctuation">;span>module<span class="token punctuation">.span>exports <span class="token operator">=span> <span class="token punctuation">{span><span class="token function-variable function">webpackspan><span class="token operator">:span> <span class="token punctuation">(span><span class="token parameter">configspan><span class="token punctuation">)span> <span class="token operator">=>span> <span class="token punctuation">{span>config<span class="token punctuation">.span>output<span class="token punctuation">.span>library <span class="token operator">=span> <span class="token template-string"><span class="token template-punctuation string">`span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${span>name<span class="token interpolation-punctuation punctuation">}span>span><span class="token string">-[name]span><span class="token template-punctuation string">`span>span><span class="token punctuation">;span>config<span class="token punctuation">.span>output<span class="token punctuation">.span>libraryTarget <span class="token operator">=span> <span class="token string">'umd'span><span class="token punctuation">;span><span class="token comment">// webpack 5 需要把 jsonpFunction 替换成 chunkLoadingGlobalspan>config<span class="token punctuation">.span>output<span class="token punctuation">.span>chunkLoadingGlobal <span class="token operator">=span> <span class="token template-string"><span class="token template-punctuation string">`span><span class="token string">webpackJsonp_span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${span>name<span class="token interpolation-punctuation punctuation">}span>span><span class="token template-punctuation string">`span>span><span class="token punctuation">;span>config<span class="token punctuation">.span>output<span class="token punctuation">.span>globalObject <span class="token operator">=span> <span class="token string">'window'span><span class="token punctuation">;span><span class="token keyword">returnspan> config<span class="token punctuation">;span><span class="token punctuation">}span><span class="token punctuation">,span><span class="token function-variable function">devServerspan><span class="token operator">:span> <span class="token punctuation">(span><span class="token parameter">_span><span class="token punctuation">)span> <span class="token operator">=>span> <span class="token punctuation">{span><span class="token keyword">constspan> config <span class="token operator">=span> _<span class="token punctuation">;span>config<span class="token punctuation">.span>headers <span class="token operator">=span> <span class="token punctuation">{span><span class="token string">'Access-Control-Allow-Origin'span><span class="token operator">:span> <span class="token string">'*'span><span class="token punctuation">}span><span class="token punctuation">;span>config<span class="token punctuation">.span>historyApiFallback <span class="token operator">=span> <span class="token boolean">truespan><span class="token punctuation">;span>config<span class="token punctuation">.span>hot <span class="token operator">=span> <span class="token boolean">falsespan><span class="token punctuation">;span><span class="token comment">// webpack5里面也没有这个watchContentBase配置了,索性也直接注释好了span><span class="token comment">// config.watchContentBase = false;span>config<span class="token punctuation">.span>liveReload <span class="token operator">=span> <span class="token boolean">falsespan><span class="token punctuation">;span><span class="token keyword">returnspan> config<span class="token punctuation">;span><span class="token punctuation">}span>
<span class="token punctuation">}span><span class="token punctuation">;span>

到这一步就完成了子应用的改造,启动项目访问 http://localhost:3000/react-app

在这里插入图片描述

Vue3子应用

项目初始化

npm create vite@latest vue-app
cd vue-app
npm i
npm install vue-plugin-qiankun

修改vite配置

关于 vite-plugin-qiankun 插件

<span class="token keyword">importspan> <span class="token punctuation">{span>defineConfig<span class="token punctuation">}span> <span class="token keyword">fromspan> <span class="token string">'vite'span><span class="token punctuation">;span>
<span class="token keyword">importspan> vue <span class="token keyword">fromspan> <span class="token string">'@vitejs/plugin-vue'span><span class="token punctuation">;span>
<span class="token keyword">importspan> qiankun <span class="token keyword">fromspan> <span class="token string">'vite-plugin-qiankun'span><span class="token punctuation">;span><span class="token comment">// https://vitejs.dev/config/span>
<span class="token keyword">exportspan> <span class="token keyword">defaultspan> <span class="token function">defineConfigspan><span class="token punctuation">(span><span class="token punctuation">{span>base<span class="token operator">:span> <span class="token string">'./vue-app'span><span class="token punctuation">,span>plugins<span class="token operator">:span> <span class="token punctuation">[span><span class="token function">vuespan><span class="token punctuation">(span><span class="token punctuation">)span><span class="token punctuation">,span> <span class="token function">qiankunspan><span class="token punctuation">(span><span class="token string">'vue-app'span><span class="token punctuation">,span> <span class="token punctuation">{span>useDevMode<span class="token operator">:span> <span class="token boolean">truespan><span class="token punctuation">}span><span class="token punctuation">)span><span class="token punctuation">]span><span class="token punctuation">,span>server<span class="token operator">:span> <span class="token punctuation">{span>port<span class="token operator">:span> <span class="token number">3001span><span class="token punctuation">,span>cors<span class="token operator">:span> <span class="token boolean">truespan><span class="token punctuation">,span>origin<span class="token operator">:span> <span class="token string">'http://localhost:3001'span><span class="token punctuation">}span>
<span class="token punctuation">}span><span class="token punctuation">)span><span class="token punctuation">;span>

入口改造

这里要注意:在引入了其他的库之后在if判断和else当中的createApp当中都要use一下对应的库。完成了这一步然后再基座应用当中和加react子应用一样把vue子应用加进去这就完成了微前端

<span class="token keyword">importspan> <span class="token punctuation">{span>createApp<span class="token punctuation">}span> <span class="token keyword">fromspan> <span class="token string">'vue'span><span class="token punctuation">;span>
<span class="token keyword">importspan> <span class="token string">'./style.css'span><span class="token punctuation">;span>
<span class="token keyword">importspan> App <span class="token keyword">fromspan> <span class="token string">'./App.vue'span><span class="token punctuation">;span>
<span class="token keyword">importspan> router <span class="token keyword">fromspan> <span class="token string">'./router'span><span class="token punctuation">;span>
<span class="token keyword">importspan> ElementPlus <span class="token keyword">fromspan> <span class="token string">'element-plus'span><span class="token punctuation">;span>
<span class="token keyword">importspan> <span class="token string">'element-plus/dist/index.css'span><span class="token punctuation">;span>
<span class="token keyword">importspan> <span class="token punctuation">{span>renderWithQiankun<span class="token punctuation">,span> qiankunWindow<span class="token punctuation">}span> <span class="token keyword">fromspan> <span class="token string">'vite-plugin-qiankun/dist/helper'span><span class="token punctuation">;span><span class="token keyword">letspan> app<span class="token operator">:span> any<span class="token punctuation">;span>
<span class="token keyword">ifspan> <span class="token punctuation">(span><span class="token operator">!span>qiankunWindow<span class="token punctuation">.span>__POWERED_BY_QIANKUN__<span class="token punctuation">)span> <span class="token punctuation">{span><span class="token function">createAppspan><span class="token punctuation">(span>App<span class="token punctuation">)span><span class="token punctuation">.span><span class="token function">usespan><span class="token punctuation">(span>router<span class="token punctuation">)span><span class="token punctuation">.span><span class="token function">usespan><span class="token punctuation">(span>ElementPlus<span class="token punctuation">)span><span class="token punctuation">.span><span class="token function">mountspan><span class="token punctuation">(span><span class="token string">'#app'span><span class="token punctuation">)span><span class="token punctuation">;span>
<span class="token punctuation">}span> <span class="token keyword">elsespan> <span class="token punctuation">{span><span class="token function">renderWithQiankunspan><span class="token punctuation">(span><span class="token punctuation">{span><span class="token function">mountspan><span class="token punctuation">(span><span class="token parameter">propsspan><span class="token punctuation">)span> <span class="token punctuation">{span>app <span class="token operator">=span> <span class="token function">createAppspan><span class="token punctuation">(span>App<span class="token punctuation">)span><span class="token punctuation">.span><span class="token function">usespan><span class="token punctuation">(span>router<span class="token punctuation">)span><span class="token punctuation">.span><span class="token function">usespan><span class="token punctuation">(span>ElementPlus<span class="token punctuation">)span><span class="token punctuation">;span>app<span class="token punctuation">.span><span class="token function">mountspan><span class="token punctuation">(span>props<span class="token punctuation">.span>container<span class="token operator">?.span><span class="token function">querySelectorspan><span class="token punctuation">(span><span class="token string">'#app'span><span class="token punctuation">)span><span class="token punctuation">)span><span class="token punctuation">;span><span class="token punctuation">}span><span class="token punctuation">,span><span class="token function">bootstrapspan><span class="token punctuation">(span><span class="token punctuation">)span> <span class="token punctuation">{span>console<span class="token punctuation">.span><span class="token function">logspan><span class="token punctuation">(span><span class="token string">'vue app bootstrap'span><span class="token punctuation">)span><span class="token punctuation">;span><span class="token punctuation">}span><span class="token punctuation">,span><span class="token function">updatespan><span class="token punctuation">(span><span class="token punctuation">)span> <span class="token punctuation">{span>console<span class="token punctuation">.span><span class="token function">logspan><span class="token punctuation">(span><span class="token string">'vue app update'span><span class="token punctuation">)span><span class="token punctuation">;span><span class="token punctuation">}span><span class="token punctuation">,span><span class="token function">unmountspan><span class="token punctuation">(span><span class="token parameter">propsspan><span class="token punctuation">)span> <span class="token punctuation">{span>console<span class="token punctuation">.span><span class="token function">logspan><span class="token punctuation">(span><span class="token string">'vue app unmount'span><span class="token punctuation">,span> props<span class="token punctuation">)span><span class="token punctuation">;span>app<span class="token punctuation">.span><span class="token function">unmountspan><span class="token punctuation">(span><span class="token punctuation">)span><span class="token punctuation">;span><span class="token punctuation">}span><span class="token punctuation">}span><span class="token punctuation">)span><span class="token punctuation">;span>
<span class="token punctuation">}span>

子应用间跳转

vue跳react

这里安装vue-router和配置router路由就不说明了,主要看一下跳转代码。这里跳转到vue子应用当中的路由都是可以的,但是react子应用是跳转不过去的。

<script setup lang="ts">
import {ref} from 'vue';
import router from '@/router/index';const activeName = ref('list');const handleClick = (tab: any) => {router.push({name: tab.paneName});
};
</script><template><div class="vue__app__title">这是一个vue3子应用</div><el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick"><el-tab-pane label="List" name="list"></el-tab-pane><el-tab-pane label="Detail" name="detail"></el-tab-pane><el-tab-pane label="Go React" name="react-app"></el-tab-pane></el-tabs><router-view/>
</template>
方案一:直接重定向
window<span class="token punctuation">.span>location<span class="token punctuation">.span>href <span class="token operator">=span> <span class="token string">'/react-app'span><span class="token punctuation">;span>
方案二:pushState

语法

history<span class="token punctuation">.span><span class="token function">pushStatespan><span class="token punctuation">(span>stateObject<span class="token punctuation">,span> title<span class="token punctuation">,span> url<span class="token punctuation">)span><span class="token punctuation">;span>

参数

参数描述
stateObject传入的状态对象。当前进(后退)到某一新的状态时,会触发popstate事件。此事件对象event.state存储的就是这个stateObject的值。
title新状态的标题。(目前,大多数浏览器并不支持该参数,建议传null值)
url状态对应的历史记录的地址。

调整一下vue当中跳转的代码,重新匹配一下路由通过window.history.pushState跳到react子应用当中

<span class="token keyword">constspan> <span class="token function-variable function">handleClickspan> <span class="token operator">=span> <span class="token punctuation">(span><span class="token parameter">tab<span class="token operator">:span> anyspan><span class="token punctuation">)span> <span class="token operator">=>span> <span class="token punctuation">{span><span class="token keyword">ifspan> <span class="token punctuation">(span>tab<span class="token punctuation">.span>paneName <span class="token operator">===span> <span class="token string">'react-app'span><span class="token punctuation">)span> <span class="token punctuation">{span>window<span class="token punctuation">.span>history<span class="token punctuation">.span><span class="token function">pushStatespan><span class="token punctuation">(span><span class="token punctuation">{span><span class="token punctuation">}span><span class="token punctuation">,span> <span class="token string">''span><span class="token punctuation">,span> <span class="token string">'/react-app'span><span class="token punctuation">)span><span class="token punctuation">;span><span class="token punctuation">}span> <span class="token keyword">elsespan> <span class="token punctuation">{span>router<span class="token punctuation">.span><span class="token function">pushspan><span class="token punctuation">(span><span class="token punctuation">{span>name<span class="token operator">:span> tab<span class="token punctuation">.span>paneName<span class="token punctuation">}span><span class="token punctuation">)span><span class="token punctuation">;span><span class="token punctuation">}span>
<span class="token punctuation">}span><span class="token punctuation">;span>

同样的在主应用当中我们可以拦截到这个pushState,并且在主应用里面进行一些相对应的处理:改一下基座的入口,添加以下代码

注意一下咯:这里通过apply重新设置值的时候使用的普通函数,要是使用箭头函数的话会改变this指向导致报错

<span class="token comment">// 重写history的pushState方法,触发自定义事件,并返回原方法的返回值span>
<span class="token keyword">constspan> <span class="token function-variable function">writespan> <span class="token operator">=span> <span class="token punctuation">(span><span class="token keyword">typespan><span class="token operator">:span> <span class="token builtin">stringspan><span class="token punctuation">)span> <span class="token operator">=>span> <span class="token punctuation">{span><span class="token keyword">constspan> orig <span class="token operator">=span> <span class="token punctuation">(span>window <span class="token keyword">asspan> <span class="token builtin">anyspan><span class="token punctuation">)span><span class="token punctuation">.span>history<span class="token punctuation">[span><span class="token keyword">typespan><span class="token punctuation">]span><span class="token punctuation">;span><span class="token keyword">returnspan> <span class="token keyword">functionspan> <span class="token punctuation">(span><span class="token punctuation">)span> <span class="token punctuation">{span><span class="token keyword">constspan> rv <span class="token operator">=span> <span class="token function">origspan><span class="token punctuation">.span><span class="token function">applyspan><span class="token punctuation">(span><span class="token keyword">thisspan><span class="token punctuation">,span> arguments<span class="token punctuation">)span><span class="token punctuation">;span><span class="token keyword">constspan> e<span class="token operator">:span> <span class="token builtin">anyspan> <span class="token operator">=span> <span class="token keyword">newspan> <span class="token class-name">Eventspan><span class="token punctuation">(span><span class="token keyword">typespan><span class="token punctuation">)span><span class="token punctuation">;span>e<span class="token punctuation">.span>arguments <span class="token operator">=span> arguments<span class="token punctuation">;span>window<span class="token punctuation">.span><span class="token function">dispatchEventspan><span class="token punctuation">(span>e<span class="token punctuation">)span><span class="token punctuation">;span><span class="token keyword">returnspan> rv<span class="token punctuation">;span><span class="token punctuation">}span><span class="token punctuation">;span>
<span class="token punctuation">}span><span class="token punctuation">;span>window<span class="token punctuation">.span>history<span class="token punctuation">.span>pushState <span class="token operator">=span> <span class="token function">writespan><span class="token punctuation">(span><span class="token string">'pushState'span><span class="token punctuation">)span><span class="token punctuation">;span>window<span class="token punctuation">.span><span class="token function">addEventListenerspan><span class="token punctuation">(span><span class="token string">'pushState'span><span class="token punctuation">,span> <span class="token punctuation">(span><span class="token punctuation">)span> <span class="token operator">=>span> <span class="token punctuation">{span><span class="token builtin">consolespan><span class="token punctuation">.span><span class="token function">logspan><span class="token punctuation">(span><span class="token string">'base 基座监听到了pushState事件====='span><span class="token punctuation">)span><span class="token punctuation">;span>
<span class="token punctuation">}span><span class="token punctuation">)span><span class="token punctuation">;span>

问题

react卸载报错

在从vue项目跳转到react当中,再从react返回到vue,会出现以下报错,就是react入口文件当中配置了卸载unmountComponentAtNode的时候出现了问题。

application <span class="token string">'react app'span> died <span class="token keyword">inspan> status UNMOUNTING: react_dom_client__WEBPACK_IMPORTED_MODULE_1__.unmountComponentAtNode is not a <span class="token keyword">functionspan>
TypeError: react_dom_client__WEBPACK_IMPORTED_MODULE_1__.unmountComponentAtNode is not a <span class="token keyword">functionspan>

这是因为在 React 18, unmountComponentAtNode 已被 root.unmount() 取代。那么在react项目当中改一下入口当中的卸载钩子

<span class="token comment">// 删掉这个span>
<span class="token comment">// export async function unmount(props) {span>
<span class="token comment">//   const {container} = props;span>
<span class="token comment">//   ReactDOM.unmountComponentAtNode(container ? container.querySelector('#root') : document.querySelector('#root'));span>
<span class="token comment">// }span><span class="token keyword">exportspan> <span class="token keyword">asyncspan> <span class="token keyword">functionspan> <span class="token function">unmountspan><span class="token punctuation">(span><span class="token parameter">propsspan><span class="token punctuation">)span> <span class="token punctuation">{span>root<span class="token punctuation">.span><span class="token function">unmountspan><span class="token punctuation">(span><span class="token punctuation">)span><span class="token punctuation">;span>
<span class="token punctuation">}span>

公共依赖加载

在开发过程中,不同的子应用还是会使用到很多相同的第三方库的依赖,比方说:axios、dayjs、lodash等。而微前端是统一加载的,这个时候我们可以将这些公共依赖只加载一次,而不是切换个子应用又加载一次。


http://www.ppmy.cn/devtools/128334.html

相关文章

其他-自己手动更换汽车电磁进排气阀0.9.2

其他-自己手动更换汽车电磁进排气阀0.9.0 背景本次工具流程注意参考 2024年10月18日08:57:00—0.9.2 背景 昨天手动更换了电磁阀&#xff0c;记录下过程和注意事项&#xff0c;简单总结了一下 本次工具 10号套筒和工具老虎钳锤子一字改刀新的进排气电磁阀 流程 打开引擎盖…

计算机网络——传输层服务

传输层会给段加上目标ip和目标端口号 应用层去识别报文的开始和结束

R数据科学 16.5.3练习题

(1) 编写代码以使用一种映射函数完成以下任务。 a. 计算 mtcars 数据集中每列的均值。 b. 确定 nycflights13::flights 数据集中每列的类型。 c. 计算 iris 数据集中每列唯一值的数量。 d. 分别使用 μ -10、0、10 和 100 的正态分布生成 10 个随机数。 library(purrr) # 计算…

Cadence元件A属性和B属性相互覆盖

最近在使用第三方插件集成到Cadence,协助导出BOM到平台上&#xff0c;方便对BOM进行管理和修改&#xff0c;结果因为属性A和属性B不相同&#xff0c;导致导出的BOM错误。如下图&#xff1a; ​​ 本来我们需要导出Q12&#xff0c;结果给我们导出了Q13&#xff0c;或者反之&…

在Ubuntu 20.04 上安装 CoppeliaSim

在 Ubuntu 20.04 上安装 CoppeliaSim Edu V4.6.0 rev18 的步骤如下&#xff1a; 1. 下载安装文件: 首先&#xff0c;确保您已经下载了 CoppeliaSim_Edu_V4_6_0_rev18_Ubuntu20_04.tar.xz 文件。您可以从 Coppelia Robotics 的官方网站下载。 2. 解压缩文件: 打开终端&#…

TensorFlow:强大的机器学习框架

在当今的人工智能和机器学习领域&#xff0c;TensorFlow 无疑是一颗璀璨的明星。它是一个由 Google 开发的开源机器学习框架&#xff0c;广泛应用于各种领域&#xff0c;从图像识别到自然语言处理&#xff0c;从医疗保健到金融分析&#xff0c;都能看到 TensorFlow 的身影。 一…

解决:Ubuntu跑slam,遇到rviz闪退

在使用ros运行slam算法的时候&#xff0c;运行roslaunch aloam_velodyne aloam_velodyne_VLP_16.launch和rosbag play nsh_indoor_outdoor.bag中的某一条指令的时候&#xff0c;发现rviz启动后&#xff0c;里面没有内容&#xff0c;并且闪退。 我尝试关闭vmware中的3D加速&…

Pytorch复习(三)

一、CNN 卷积神经网络是近年发展起来&#xff0c;并广泛应用于图像处理&#xff0c;NLP等领域的一种多层神经网络 传统BP处理图像时的问题&#xff1a; 1、权值太多&#xff0c;计算量较大 2、权值太多&#xff0c;需要大量样本进行训练 CNN通过局部感受野和权值共享减少了…