vue3微前端实战

微前端接入方案:qiankunjavascript

经常使用api:html

registerMicroApps: 主应用注册微前端前端

start: 启动微前端应用vue

主、子应用都为hash模式改造:

开发环境:

主应用改造:

import { registerMicroApps, start } from 'qiankun';
registerMicroApps(
  [
    {
      // 微前端应用名
      name: 'app1',
      
      // 微前端启动地址
      entry: '//localhost:8100/',
      
      // 微前端挂载dom
      container: '#app',
      
      // 微前端触发路由
      activeRule: '#/app1',
      
      // 主应用向子应用传递的静态值
      props: {
        name: 'yuxiaoyu',
      },
    },
  ],
);

start();
复制代码

子应用改造:

// 入口文件main.js
// 子应用并不用引入qiankun,只要暴露响应的声明周期钩子给主应用使用就ok
// 挂载实例
function render(props: any = {}) {
  const { container } = props;
  app = createApp(App);
  app.use(router);
  app.use(store);
  router.isReady().then(() => {
    app.mount(container ? container.querySelector('#container') : '#container');
  });
}

// 微应用在主应用运行时,主应用会在微应用中挂载window.__POWERED_BY_QIANKUN__,能够用于判断环境
// 官方提供了下面这个webpack注入publicPath的方法, 开发环境咱们这么使用,生产改到vue.config.js中,后面再介绍。
if (window.__POWERED_BY_QIANKUN__) {
  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}

// 若是是独立运行 window.__POWERED_BY_QIANKUN__=undefined 直接render
if (!window.__POWERED_BY_QIANKUN__) {
  render();
}

// 最后暴露的三个方法是固定的,加载渲染以及销毁
export async function bootstrap() { }

export async function mount(props: any) {
  render(props);
}
export async function unmount() {
  app.unmount();
  app._container.innerHTML = "";
  app = null;
  
  // 这里reload的缘由: 由于这个项目微应用和主应用没有共用导航等信息
  // 至关于一个两个独立的页面,因此就共用的<div id="app"></div>一个节点
  // 在卸载微应用后,为了再把主应用渲染出来,就从新reload了一遍。
  location.reload();
}
复制代码
// router改造
const router = createRouter({
  history: createWebHashHistory(),
  routes,
});

// 由于主应用在激活子应用时,有一个activeRule前缀,因此在hash模式下,咱们须要给每一个一级路由都添加activeRule的前缀,主应用为'#/app1',那么子应用前咱们就加'/app1'就能够了。
export default [
  {
    path: '/app1/fujidaohang',
    redirect: '/app1/fujidaohang/zijidaohang',
    component: BothLayout,
    name: 'fujidaohang',
    meta: {
      title: '父级导航',
      navPosition: 'top',
    },
    children: [
      {
        path: 'zijidaohang',
        component: () => import('@/apps/fujidaohang/views/zijidaohang.vue'),
        name: 'zijidaohang',
        meta: {
          title: '子级导航',
          navPosition: '',
        },
      },
    ],
  },
  {
    path: '/app1/course',
    component: Course,
    name: 'course',
    children: [],
  }
];
复制代码
// vue.config.js改造
const packageName = require('./package.json').name;

module.exports = {
  ...
  
  // 用于主应用识别子应用,固定写法
  configureWebpack: {
    output: {
      library: 'app1',
      libraryTarget: 'umd',
      jsonpFunction: `webpackJsonp_${packageName}`,
    },
  }
}
复制代码

生产构建部署:

构建部署能够选择两种方式:java

同域名和不一样域名部署。由于考虑到接口跨域和不用域名部署须要运维资源,Nginx相关的配置,因此咱们选用同域名部署。部署在主应用构建以后的静态资源目录里,这样前端就能够处理部署流程,不须要后端及运维的支持。固然也能够根据须要选用响应的部署方式,官方都有给出详细的介绍: 如何部署webpack

主应用改造:

// main.js
// 注册微应用
registerMicroApps(
  [
    {
      name: 'app1',
      
      // 路径改成部署后,微应用要存放在主应用的目录,其他不变
      entry: '/static/index.html',
      container: '#app',
      activeRule: '#/app1',
      props: {
        name: 'kuitos',
      },
    },
  ],
);
复制代码

微应用改造:

// main.js
// 去掉qiankun的__webpack_public_path__注入
// if (window.__POWERED_BY_QIANKUN__) {
// __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
// }

// vue.config.js
module.exports = {
  ...
  
  // 这里新增打包资源存放路径,与上面主应用相对应
  publicPath: '/static'
}
复制代码

主、子应用打包后存放如图所示,以后就能够走运维的部署流程了。web

image.png

主、子应用都为history模式改造:

开发模式:

这里咱们和hash-dev模式进行对比,只列举差别的部分。json

// 主应用
// main.js, 注册微应用有变化
registerMicroApps(
  [
    {
      name: 'app1',
      entry: '//localhost:8101',
      container: '#app',
      
      // 改变点:激活路由由hash模式变为history模式
      activeRule: '/app1',
      props: {
        name: 'yuxiaoyu',
      },
    },
  ],
);

// router.js 

const router = new VueRouter({

  // 由hash改成history模式
  mode: 'history',
  base: process.env.BASE_URL,
  routes,
});
复制代码
// 子应用
// router/index.js
const router = createRouter({
  
  // 改成history模式,而且加activeRule前缀
  history: createWebHistory('/app1'),
  routes,
});

// router.js

// 去掉这里的app1前缀
export default [
  {
    path: '/fujidaohang',
    redirect: '/fujidaohang/zijidaohang',
    component: BothLayout,
    name: 'fujidaohang',
    meta: {
      title: '父级导航',
      navPosition: 'top',
    },
    children: [
      {
        path: 'zijidaohang',
        component: () => import('@/apps/fujidaohang/views/zijidaohang.vue'),
        name: 'zijidaohang',
        meta: {
          title: '子级导航',
          navPosition: '',
        },
      },
    ],
  },
  {
    path: '/course',
    component: Course,
    name: 'course',
    children: [],
  }
];
复制代码

生产构建部署:

这里与hash模式改动点是一致的bootstrap

主应用改造:

// main.js
// 注册微应用
registerMicroApps(
  [
    {
      // 路径改成部署后,微应用要存放在主应用的目录,其他不变
      entry: '/static/index.html',
    },
  ],
);
复制代码

微应用改造:

// main.js
// 去掉qiankun的__webpack_public_path__注入
// if (window.__POWERED_BY_QIANKUN__) {
// __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
// }

// vue.config.js
module.exports = {
  ...
  
  // 这里新增打包资源存放路径,与上面主应用相对应
  publicPath: '/static'
}
复制代码

鉴权

当进入微应用时,咱们鉴定微应用是否登陆时,咱们能够考虑在微应用作鉴权,也能够在主应用作鉴权。后端

qiankun里在注册微应用时,registerMicroApps提供了第二个参数,lifeCycles- 可选,全局的微应用生命周期钩子

registerMicroApps(
    [{}], {
    
    // 这里采用在进入微前端以前进行鉴权,确保进入微前端时,已经登录。
    beforeLoad: [
      () => {
        if (!vm.$auth.check()) {
            vm.$router.push(vm.$auth.options.loginPath);
            location.reload();
        }
      },
    ],
  },);
复制代码

样式隔离

1.主、子应用都是用antd

这里官方提供了修改antd前缀的方法,如将ant改成dida-ant, 如何确保主应用跟微应用之间的样式隔离

这里ant-design-vue文档里虽然没有提供prefixCls的参数,可是可使用的,源码里相应的处理。

2.主应用自定义样式与子应用冲突

这里咱们能够采用官方提供的start(options?),将微应用放入浏览器所支持的shadow dom中。

start({
  sandbox: {
    // 主应用 & 子应用样式隔离
    strictStyleIsolation: true, // 放入shadow dom中
  }
});
复制代码

image.png

这里咱们能够看到微前端被放入了shadow-root里,对于shadow dom能够经过这里进行了解。

这样隔离后,在咱们使用ant design这种外部库时会有一些问题,例如popup组件,本来实现是挂在document.body中的,咱们将子应用放到了shadow dom中,那就须要将popup也挂进去。ant design官方提供了方法,搜索getPopupContainer;

相关文章
相关标签/搜索