引子
不出意外的话,这应该是微前端系列的最后一章了,主要包括我们在样式和线上环境部署时遇到的一些坑。
样式
子应用间样式隔离
开启沙箱的情况下qiankun将会自动隔离子应用之间的样式。当我们使用单实例子应用时,可以将样式隔离的实现都交给qiankun完成。
在主应用注册子应用:
start({
……
sandbox: true //开启沙箱
})
主、子应用间样式隔离
默认情况下沙箱可以确保单实例场景子应用之间的样式隔离。但是无法确保主应用跟子应用,或者多实例场景的子应用样式隔离。在qiankun@2.0中提供了严格隔离模式sandbox: { strictStyleIsolation: true },这种模式下qiankun会为每个微应用的容器包裹上一个shadow dom节点,从而确保微应用的样式不会对全局造成影响。
但这种方案会导致许多意料之外的问题,比如:子应用无法访问到根节点html或body,进而无法使用注册在根节点上的svg。
所以我们最后决定采用工程约定的方式来完成样式隔离,该方式并不是绝对可靠的,但却是我们团队目前能先到的最好方法了。
- 主应用所有样式都加入前缀MainApp-
- 子应用中的样式不得以MainApp-开头
- 主子应用尽量避免全局样式
- 主子应用所有页面都应该尽可能使用scoped约束样式
特殊样式修改
在我们的项目中,主应用提供Main部分作为子应用的渲染容器:
但子应用中的特殊样式可能会超出此范围,比如position:fixed或者width:100vw等。对此并没有太好的通用解决办法,目前实现的是对子应用中的特殊样式进行修改,尽量避免超出容器范围。
资源
子应用的资源加载坑挺多的,下面就列举一些。
加载资源失败
子应用的资源必须支持跨域,这部分可参考qiankun官方文档:
无法使用link标签引入外部资源
可能原因:Qiankun会将子应用外链样式修改为内联样式,无法解析不在<head>中的link标签。
解决方法:需要引入的资源放在index.html的<head>标签内。
图片引入失败
-
可能原因1:同一图片在不同文件中被
import了两次。
解决方法:使用require引入。 -
可能原因2:图片位置在
public或者static中,webpack会忽略这些文件夹。
解决方法:修改存放目录或使用cdn地址。
无法使用SVG
可能原因:使用了svg-sprite-loader,webpack打包时会将svg资源放到<body>节点上。开启严格沙箱后封装了一层shadowDom导致子应用无法访问<body>。
解决方法:注册子应用时关闭严格沙箱:
start({
……
sandbox: { strictStyleIsolation: false } //开启沙箱,但不是严格模式
})
主子应用svg冲突
可能原因:主、子应用使用svg-sprite-loader打包svg时命名冲突导致覆盖。
解决方法:主应用svg名称特殊处理,在webpack配置中:
module.exports = {
chainWebpack(config) {
// set svg-sprite-loader
config.module
.rule('svg')
.exclude.add(resolve('src/assets/svg'))
.end()
config.module
.rule('icons')
.test(/\.svg$/)
.include
.add(resolve('src/assets/svg')) //处理svg目录
.end()
.use('svg-sprite-loader')
.loader('svg-sprite-loader')
.options({
symbolId: 'icon-main-app-[name]' //给svg加入特殊前缀名称
})
}
部署
我们团队使用docker来部署前端项目,只需要将主子应用分别打成镜像就行。部署后主应用fetch子应用可能会报跨域,通过nginx反向代理即可解决。
主应用原先注册子应用的参数:
registerMicroApps(
name: 'react app',
entry: 'http://127.0.0.1', //原先的entry
container: '#yourContainer',
activeRule: '/yourActiveRule',
}
)
使用nginx反向代理:
registerMicroApps(
name: 'react app',
entry: './sub_app_test/', //修改后的entry
container: '#yourContainer',
activeRule: '/yourActiveRule',
}
)
nginx配置:
location /sub_app_test/ {
proxy_pass http://127.0.0.1;
proxy_buffering off;
proxy_request_buffering off;
}
第三方组件相关问题
有一些第三方组件会修改浏览器原生方法或与DOM交互,它们与微前端结合会带来奇妙的效果。
百度地图
百度地图会修改浏览器原生的appendChild方法,导致子应用加载失败。
svg-sprite-loader
见上述章节样式里svg的相关内容。