最近有个需求要将项目作为一个模块集成到另一个系统中,那边采用wujie的方式对接我们这些接入的系统,我们作为wujie的子应用,也需要进行相应的改造。经过多天的改造以及联调,问题终于都解决了,现在就将碰到的问题记录一下,方便以后再碰到时查阅。
项目使用的模块:
模块 | 版本 |
React | 18.2 |
Antd | 5.13.1 |
react-router-dom | 6.18.0 |
node | v18.19. |
typescript | 4.9.5 |
@craco/craco | 5.9.0 |
wujie的地址:无界 | 极致的微前端框架
问题一:运行模式选择了单例模式,但是菜单切换时,路由不能正常跳转到对应的组件
描述:集成到wujie主应用后,菜单是统一在主应用进行管理的,在切换菜单时,浏览器上地址发生了变化,但是子应用的路由就是不能正常跳转到对应的组件,经过多次测试验证,怀疑是单例模式的生命周期改造那一块代码出了问题,但是wujie官网上只有集成React17的案例,而React升级到18后组件的挂载和卸载方式都发生了变化。
React17wujie子应用的生命周期改造如下:
if (window.__POWERED_BY_WUJIE__) {
window.__WUJIE_MOUNT = () => {
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById("root")
);
};
window.__WUJIE_UNMOUNT = () => {
ReactDOM.unmountComponentAtNode(document.getElementById("root"));
};
} else {
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById("root")
);
}
而React18之后,组件挂载方式发生了变化:
// React17
const root = document.getElementById("root");
ReactDOM.render(
<App />,
root
);
// React18
const container = document.getElementById("root") as HTMLElement;
const root = ReactDOM.createRoot(container);
root.render(
<App />
);
组件卸载:
// React17
ReactDOM.unmountComponentAtNode(document.getElementById("root"))
// React18
root.unmount()
所以根据这些变化,写了React18的配合wujie生命周期的改造代码如下:
if (window.__POWERED_BY_WUJIE__) {
const container = document.getElementById("root") as HTMLElement;
const root = ReactDOM.createRoot(container);
window.__WUJIE_MOUNT = () => {
root.render(
<App />
);
};
window.__WUJIE_UNMOUNT = () => {
root.unmount();
};
} else {
const container = document.getElementById("root") as HTMLElement;
const root = ReactDOM.createRoot(container);
root.render(
<App />
);
}
本来以为很顺利,但是切换菜单时,就是不能路由匹配对应的组件,但是有一个很奇怪的现象是,刷新浏览器,路由就会正常跳转。被这个问题折腾了好久,主应用那边毕竟是别人开发,也没有时间帮忙排查,就让我自己一点点找。但是我自己测试验证,路由配置也没有问题。然后我打印useLocation(),发现点击菜单时,该值还是上一个菜单的值,和浏览器中的值不一样,刷新浏览器之后useLocation()打印的值就和浏览器一致了,所以怀疑是不是生命周期改造那块组件卸载有问题,组件没有正确卸载吗? 由于时间紧,就没有继续深入研究这个问题,而是换一种运行模式,改为了重建模式,发现切换菜单能正常匹配路由了,后面就改用这种运行模式了。
问题二:antd组件库Table组件的列筛选功能,鼠标点击输入框之后立马消失
描述:点击列上的检索图表,弹出输入框之后,鼠标点击输入框输入内容,正常是可以输入内容的,但是集成wujie之后,鼠标点击,输入框立刻消失,后来排查发现是wujie的通用问题,如下:
就是这个e.target的指向问题,后面在git上找到了解决方案,实际上wujie官网上也列举了,在左下角:
wujie-polyfill文档地址:无界 Polyfill | 极致的微前端Polyfill
在该文档中,插件里面有一个EvnetTargetPlugin插件就是解决这个问题的:
具体改造是在主应用进行改造的:
// 安装依赖包
npm i wujie-polyfill -S
// 下面这三种方式选一种即可
import { startApp } from 'wujie'
import { EventTargetPlugin } from "wujie-polyfill";
// 无框架
setupApp({
name: '唯一id',
url: '子应用地址',
exec: true,
el: '容器',
sync: true
plugins: [EventTargetPlugin()]
})
// vue
<WujieVue
width="100%"
height="100%"
name="xxx"
:url="xxx"
:plugins=“[EventTargetPlugin()]”
></WujieVue>
// react
<WujieReact
width="100%"
height="100%"
name="xxx"
url="{xxx}"
plugins="{[EventTargetPlugin()]}"
></WujieReact>
主应用改造之后,上述问题就完美解决了。
问题三:子应用使用window.innerHeight获取的浏览器视口高度变成了主应用的iframe的高度,而且随着浏览器高度缩放,该值不发生变化
描述:window.innerHeight的值需要跟随浏览器高度的缩放而改变,但是接入wujie之后,子应用打印的该值不会发生变化
但是我没有使用上面的方案,用的是document?.documentElement?.clientHeight来替代,具体代码如下:
import { useEventListener } from "ahooks";
// 初始高度,可以根据实际情况调整
const [tableHeight, setTableHeight] = useState(window.innerHeight - 123);
// 监听窗口大小变化,更新表格高度
const handleResize = () => {
setTableHeight(document?.documentElement?.clientHeight - 123);
};
useEventListener("resize", handleResize);
上面就是集成wujie碰到的问题以及采用的解决方案,如果各位有更好的解决方法,可以留言告知,不甚感谢!