qiankun微前端 采坑 记录

1,201 阅读4分钟

qiankun微前端采坑记录

项目使用qiankun微前端结构,遇到一些坑,记录一下。

项目说明

  • 主项目:localhost:8000,主项目后端:localhost:3000,umi+qiankun
  • 子项目1:localhoust:8001,子项目1后端:localhost:3001,vue+qiankun
  • 子项目2:localhoust:8002,子项目2后端:localhost:3002,react+qiankun 主项目与子项目分别按照qiankun官网接入。

主项目umi配置(.umirc.js)

routes: [
    { path: '/', component: '@/pages/index' },
    { path: '/login', component: '@/pages/login' },
    {
      path: '/subApp1',
      microApp: 'subApp1', // 与下面的子应用对应
    },
    {
      path: '/subApp2',
      microApp: 'subApp2', // 与下面的子应用对应
    },
  ],
  qiankun: {
    master: {
      // 注册子应用信息
      apps: [
        {
          name: 'subApp1', // 唯一 id,与子项目的 output.library 配对
          entry: '//localhost:8001/subApp1', // html entry
        },
        {
          name: 'subApp2', // 唯一 id,与子项目的 output.library 配对
          entry: '//localhost:8002/', // html entry
        },
      ],
    },
  },

主应用: <Link to="/subApp1">subApp1</Link>,点击后路由变成:http://localhost:8000/subApp1,此时去到子应用subApp1,而子应用又有一个入口//localhost:8001/subApp1,为了路由对得上,子应用需要router有个basesubApp1

  • 思考1:入口改为//localhost:8001行不行,会出现什么问题?(答案是不行,路由跳转会出现问题,本来想回到子应用的根路径/,结果跑到了主应用的根路径/
  • 思考2,入口改为//localhost:8001/<otherName>(代表别的名字),行不行?如果行,其他地方要怎么修改?

遇到的问题

  • 子项目静态资源请求不正确,全部请求到主应用上,而主应用没有该资源,导致资源不存在。

eg: http://localhost:8001/img/xx.png是有效路径,但是到了微前端里面,成了http://localhost:8000/img/xx.png,主项目当然没有子项目的资源,界面显示图片碎裂。

  • 子项目ajax请求路径不正确,全部请求到主应用上,而主应用没有子应用对应的后端proxy,导致请求无响应。 eg: http://localhost:8001/api/login是有效请求,会自动转发到子项目的后端,但是到了微前端里面,成了http://localhost:8000/api/login,主项目当然没有这样的请求,请求失败。

解决

  • http://localhost:8000/img/xx.png改造成http://localhost:8000/subApp1/img/xx.png,然后通过proxy转发到http://localhost:8001/img/xx.png
  • http://localhost:8000/api/login改造成http://localhost:8000/subApp1/api/login,然后通过proxy转发到http://localhost:8001/subApp1/api/login 单独项目运行 独立项目

微前端项目运行 微前端架构

如上图所示,就是需要在主应用再一次proxy代理,转发到子应用上。

主应用(umi配置):

import { defineConfig } from 'umi';

export default defineConfig({
  nodeModulesTransform: {
    type: 'none',
  },
  routes: [
    { path: '/', component: '@/pages/index' },
    { path: '/login', component: '@/pages/login' },
    {
      path: '/subApp1',
      microApp: 'subApp1', // 与下面的子应用对应
    },
    {
      path: '/subApp2',
      microApp: 'subApp2', // 与下面的子应用对应
    },
  ],
  qiankun: {
    master: {
      // 注册子应用信息
      apps: [
        {
          name: 'subApp1', // 唯一 id,与子项目的 output.library 配对
          entry: '//localhost:8001/subApp1', // html entry 【1】
        },
        {
          name: 'subApp2', // 唯一 id,与子项目的 output.library 配对
          entry: '//localhost:8080/subApp2', // html entry
        },
      ],
    },
  },
  proxy: {
    '/subApp1': { // 【2】
      target: 'http://localhost:8001', // 不能写成'//localhost:8001',一定要加上'http'
      changeOrigin: true,
    },
    '/subApp2': {
      target: 'http://localhost:8002', // 不能写成'//localhost:8002',一定要加上'http'
      changeOrigin: true,
    },
  },
});

这样,主项目中针对子项目的都会请求自动转发到对应的子项目上。当然也需要子项目相应地配合,看上面的配置中的【1】【2】,分别需要处理。

  • 【1】,是指默认路由就进入有特定子项目标识的路由,好区分是哪个应用。eg: "//localhost:8001/subApp1',这样需要子应用的router配置一个base,比如vue-router配置:
const router = new VueRouter({
  mode: 'history',
  base: 'subApp1', // 这里
  routes
})

这样配置后,主项目进入子项目就去的是默认的路由,与子项目独立运行界面一致。 另外,打包配置也需要修改(vue.config.js):

module.exports = {
    publicPath: '/subApp1
}

这样资源路径就会默认有 /subApp1前缀,这样主应用转发后就能回到子应用的静态资源!

  • 【2】,同意响应地,api 请求也需要加上特有的/subApp1前缀,加好后的配置(vue.config.js)如下:
devServer: {
    headers: {
      'Access-Control-Allow-Origin': '*'
    },
    proxy: {
-     '^/api': {
+     '^/subApp1/api': {
        target: 'http://localhost:3000',
        changeOrigin: true,
        pathRewrite: {
-         '/api': '/'
+         '/subApp1/api': '/'
        }
      }
    }
  }

相应地,在api请求时,都需要加上/subApp1,如果你使用的是fetch或者axios,我相信这个操作难不倒你。

【ps】: 虽然上面只写出了vue子项目的配置,但是react也差不多。

【ps】:上面的subApp1,subApp2是写demo临时取得,真实项目里面最好取个能代表子项目项目且唯一的名字,不然被嘲讽不能怪我。

完结

到此就完结了,希望对大家有帮助。

【ps】:上线的话,把对应的proxy换成nginx配置即可!

后续打算继续研究父子通信问题,以及多个应用相同组件库多次加载问题。