微前端qiankun踩坑

主应用的某个页面使用手动加载微应用的方式:

xml 复制代码
<template>    <div id="container"></div></template>​<script setup lang="ts">​import { loadMicroApp } from 'qiankun';import { onBeforeUnmount, onMounted } from 'vue';​let app: any = null;onMounted(() => {    app = loadMicroApp({        name: 'my-app',        entry: '//localhost:3000',        container: '#container'    })​})​onBeforeUnmount(() => {    app.unmount()})</script>

注意:要在主应用页面卸载的时候将微应用卸载掉,否则再次进入该页面时页面空白。

子应用导出生命周期钩子

子应用是一个create-react-app项目,修改子应用的根目录的index.js文件如下:

lua 复制代码
import './public-path'import React from 'react';import ReactDOM from 'react-dom/client';import './index.css';import App from './App';​// import reportWebVitals from './reportWebVitals';let root;function render(props) {  const { container } = props;  root = ReactDOM.createRoot(container ? container.querySelector('#root') : document.querySelector('#root'));  root.render(    <React.StrictMode>      <App />    </React.StrictMode>  );}​export async function bootstrap() {  console.log('react app bootstraped');}​export async function mount(props) {  console.log('react mount')  render(props)}​export async function unmount(props) {​  root.unmount()}​if (!window.__POWERED_BY_QIANKUN__) {  render()}​// 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-vitals// function sendToAnalytics(metric) {//   console.log(metric)// }// reportWebVitals(sendToAnalytics);​

Uncaught (in promise) Error: [qiankun]: You need to export lifecycle functions in my-app entry

接入的子应用是一个create-react-app项目,需要在config/webpack.config.js文件的output选项中配置如下内容

css 复制代码
const { packageName } = require('../package.json')​output: {  ```  library: `${packageName}-[name]`,  libraryTarget: 'umd',}​

output.library

输出一个库, 为你的入口做导出

javascript 复制代码
 __webpack_require__.d(__webpack_exports__, {   bootstrap: () => (/* binding */ bootstrap),   mount: () => (/* binding */ mount),   unmount: () => (/* binding */ unmount) });
javascript 复制代码
async function bootstrap() {  console.log('react app bootstraped');}async function mount() {  const root = react_dom_client__WEBPACK_IMPORTED_MODULE_1__.createRoot(document.getElementById('root'));}async function unmount(props) {  react_dom_client__WEBPACK_IMPORTED_MODULE_1__.unmountComponentAtNode(props.container ? props.container.querySelector('#root') : document.getElementById('root'));}​

子应用静态资源 404 Not Modified

参考:qiankun.umijs.org/zh/faq#%E4%...

  1. 在create-react-app子应用的src文件下,新增文件public-path.js
ini 复制代码
if (window.__POWERED_BY_QIANKUN__) {    __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;}
  1. 在该应用的入口文件index.js中顶部加上下面语句
arduino 复制代码
import './public-path'

Uncaught (in promise) TypeError: parcel 'my-app' died in status UNMOUNTING: react_dom_client__WEBPACK_IMPORTED_MODULE_2__.unmountComponentAtNode is not a function

上述报错出现在子应用的卸载狗子上,

提示说没有unmountComponentAtNode这个方法

javascript 复制代码
export async function unmount(props) {  ReactDOM.unmountComponentAtNode(    props.container ? props.container.querySelector('#root') : document.getElementById('root'),  );}

在React的官方文档中找到这样的说明 "在 React 18, unmountComponentAtNode 已被 root.unmount() 取代" 。而这个子应用使用的React确实是React 18。故子应用的unmount生命周期钩子内容修改如下:

javascript 复制代码
export async function unmount(props) {  root.unmount()}

主应用和子应用之间的样式污染

首先我在主应用页面编写如下html和css脚步

xml 复制代码
<template>    <div class="father">        <div class="title">我是主应用</div>    </div>    <div id="container" class="son">​    </div></template>​<style>  .title {      font-size: 20px;  }</style>

其次,我在create-react-app子应用的App.js文件中新增一行html脚本如下

ini 复制代码
 <div className='title'>我是React子应用</div>

再次,我在create-react-app子应用的App.css文件中新增样式脚本如下

css 复制代码
.title {  font-size: 11px;}

结果,相同title的class名称,主应用的字体大小被子应用覆盖,如下图所示:

qiankun提供的两种样式隔离方案shadow dom和 scoped css,

方案1: shadow dom的配置方式如下

参考官方链接:qiankun.umijs.org/zh/api#load...

php 复制代码
onMounted(() => {    app = loadMicroApp({        name: 'my-app',        entry: '//localhost:3000',        container: '#container'    }, {        sandbox: {            strictStyleIsolation: true        },    })​})

该方式的存在的问题:

参考:
juejin.cn/post/718441...

该方式存在的问题是默认挂在document.body上的子应用弹框,样式失效了。因为在shadow dom里面的样式无法作用到document.body下的html。

以下截图是子应用单独访问时的弹框样式

以下上嵌入在主应用时访问的弹框样式:

方案2: scoped css,配置方式如下:

php 复制代码
 loadMicroApp({        name: 'my-app',        entry: '//localhost:3000',        container: '#container'    }, {        sandbox: {            experimentalStyleIsolation: true        },    }  )

当 experimentalStyleIsolation 被设置为 true 时,qiankun 会改写子应用所添加的样式为所有样式规则增加一个特殊的选择器规则来限定其影响范围。

该方式默认挂在document.body上的子应用弹框样式问题依旧无法解决。

因为所有的样式都加了 data-qiankun 的限制,那就影响不了子应用外部了,所以挂在 body 的弹窗还是加不了样式。

那我们该如何解决这个问题呢?

如果子应用是Vue项目,则使用scoped css

scoped css 是 vue loader 实现的组件级样式隔离方案,用起来只要给单文件组件的 style 加一个 scoped 属性:

xml 复制代码
<style scoped></style>

如果子应用是React项目,可以使用css modules

css modules详解参考:

zhuanlan.zhihu.com/p/595325418

www.ruanyifeng.com/blog/2016/0...

首先,修改App.css文件名为App.module.css。

当前子应用是create-react-app项目,在config/webback.config.js配置文件中,默认配置了**.module.css文件的css modules为局部模式。对于需要使用局部模式的css文件,将名称命名为**.module.css就可以开启局部模式。

yaml 复制代码
{              test: cssModuleRegex,              use: getStyleLoaders({                importLoaders: 1,                sourceMap: isEnvProduction                  ? shouldUseSourceMap                  : isEnvDevelopment,                modules: {                  mode: 'local',                  getLocalIdent: getCSSModuleLocalIdent,                },              }),            },
  1. 修改App.module.css为App.module.scss , 我们使用scss的方式,scss支持嵌套选择器,方便我们将子元素上的样式都嵌套在根元素的样式内。
  1. 修改app.js,修改内容如下:

最终呈现,根节点的class值编译成局部唯一的字符串,子节点上的class值不变,但因为被根节点上的class包裹,所以不会被外部样式作用到,同样,也不会作用外部节点。

因为没有用qiankun的样式隔离,挂在document.body上的子应用弹框样式失效的问题也就解决了。

应用之间的通信

blog.csdn.net/weixin_4397...

相关推荐
上趣工作室10 分钟前
vue2在el-dialog打开的时候使该el-dialog中的某个输入框获得焦点方法总结
前端·javascript·vue.js
家里有只小肥猫11 分钟前
el-tree 父节点隐藏
前端·javascript·vue.js
fkalis12 分钟前
【海外SRC漏洞挖掘】谷歌语法发现XSS+Waf Bypass
前端·xss
陈随易1 小时前
农村程序员-关于小孩教育的思考
前端·后端·程序员
云深时现月1 小时前
jenkins使用cli发行uni-app到h5
前端·uni-app·jenkins
昨天今天明天好多天1 小时前
【Node.js]
前端·node.js
2401_857610032 小时前
深入探索React合成事件(SyntheticEvent):跨浏览器的事件处理利器
前端·javascript·react.js
雾散声声慢2 小时前
前端开发中怎么把链接转为二维码并展示?
前端
熊的猫2 小时前
DOM 规范 — MutationObserver 接口
前端·javascript·chrome·webpack·前端框架·node.js·ecmascript
天农学子2 小时前
Easyui ComboBox 数据加载完成之后过滤数据
前端·javascript·easyui