基于Vue2 & qiankun的微前端实现(第3章-样式、资源、跨域、部署)

699 阅读4分钟

引子

image.png

不出意外的话,这应该是微前端系列的最后一章了,主要包括我们在样式和线上环境部署时遇到的一些坑。

样式

子应用间样式隔离

开启沙箱的情况下qiankun将会自动隔离子应用之间的样式。当我们使用单实例子应用时,可以将样式隔离的实现都交给qiankun完成。

在主应用注册子应用:

start({
    ……
    sandbox: true   //开启沙箱
})

主、子应用间样式隔离

默认情况下沙箱可以确保单实例场景子应用之间的样式隔离。但是无法确保主应用跟子应用,或者多实例场景的子应用样式隔离。在qiankun@2.0中提供了严格隔离模式sandbox: { strictStyleIsolation: true },这种模式下qiankun会为每个微应用的容器包裹上一个shadow dom节点,从而确保微应用的样式不会对全局造成影响。

但这种方案会导致许多意料之外的问题,比如:子应用无法访问到根节点htmlbody,进而无法使用注册在根节点上的svg

所以我们最后决定采用工程约定的方式来完成样式隔离,该方式并不是绝对可靠的,但却是我们团队目前能先到的最好方法了。

  • 主应用所有样式都加入前缀MainApp-
  • 子应用中的样式不得以MainApp-开头
  • 主子应用尽量避免全局样式
  • 主子应用所有页面都应该尽可能使用scoped约束样式

特殊样式修改

在我们的项目中,主应用提供Main部分作为子应用的渲染容器:

image.png

但子应用中的特殊样式可能会超出此范围,比如position:fixed或者width:100vw等。对此并没有太好的通用解决办法,目前实现的是对子应用中的特殊样式进行修改,尽量避免超出容器范围。

资源

子应用的资源加载坑挺多的,下面就列举一些。

加载资源失败

子应用的资源必须支持跨域,这部分可参考qiankun官方文档:

配置微应用的打包工具

为什么微应用加载的资源会 404?

微应用静态资源一定要支持跨域吗?

无法使用link标签引入外部资源

可能原因:Qiankun会将子应用外链样式修改为内联样式,无法解析不在<head>中的link标签。

解决方法:需要引入的资源放在index.html<head>标签内。

图片引入失败

  • 可能原因1:同一图片在不同文件中被import了两次。
    解决方法:使用require引入。

  • 可能原因2:图片位置在public或者static中,webpack会忽略这些文件夹。
    解决方法:修改存放目录或使用cdn地址。

无法使用SVG

可能原因:使用了svg-sprite-loaderwebpack打包时会将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的相关内容。