微前端实践之vue3使用qiankun(一)创建主子应用

1,680 阅读1分钟

一、创建主应用项目

(1)创建主应用

首先创建vue3项目,具体步骤就不说了,网上一大堆,这里给项目取名main

vue creat main

(2)安装qiankun

qiankun官方教程地址

$ yarn add qiankun # 
或者 
npm i qiankun -S

(3)配置main.js(注册子应用)

子应用的名称设置为vueSub,跳转地址为/vueSub,渲染容器为id为subapp-container的元素(必须有该元素)

import { createApp } from 'vue';
import {
  registerMicroApps, start,
} from 'qiankun';
import App from './App.vue';
import router from './router';
import store from './store';
import actions from './shared/actions';

createApp(App).use(store).use(router).mount('#main');

registerMicroApps([
  {
    name: 'vueSub', // 微应用的名称,微应用之间必须确保唯一。
    entry: '//localhost:9002', // 必选,微应用的入口。
    container: '#subapp-container', // 必选,微应用的容器节点的选择器或者 Element 实例。
    activeRule: '/vueSub', // 必选,微应用的激活规则。
    props: {
      router, // 将主应用的路由传给子应用,子应用才能返回到主应用上
    }, // 参数
  },
]);

//设置默认进入的子应用
// setDefaultMountApp('/vue3');

start();

(4)在页面中配置子应用的渲染元素

在APP.vue中,我增加了个div,官方是使用router-view和router-link来进行主页面和子页面切换,但是我需要用的场景是主应用打开后,点击子应用的图标进入 子应用,之后在子应用中点击返回按钮返回主应用界面,所以采用了以下的方式。

<template>
  <div >
    <router-view />
    <div id="subapp-container"></div>
  </div>
</template>

<style lang="stylus">

</style>

\

路由文件使用的就是创建后的例子,使用的history模式

import { createRouter, createWebHistory } from 'vue-router';
import Home from '../views/Home.vue';
import Login from '../views/Login.vue';

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home,
  },
  {
    path: '/about',
    name: 'About',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/About.vue'),
  },
];

const router = createRouter({
  history: createWebHistory(),
  routes,
});

export default router;

二、创建子应用项目链接

(1)创建子应用,不需要导入qiankun

同样使用创建一个vue项目, 之前注册的名称加vueSub,这里也用这个名称,这里的名称不影响跳转,但是为了保持统一用一个,之后的配置打包里面需要和上面主应用的名称一致。

vue create vueSub

之后在创建一个文件public-path.js在main.js同级目录下,内容如下

这个主要解决的是子应用动态载入的脚本,样式,图片等地址不正确的问题。

//public-path.js
if (window.__POWERED_BY_QIANKUN__) {
  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__
}

(2)配置main.js

在子应用中,需要将生命周期钩子暴露出来,引入上面创建的js

import './public-path';
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';
import store from './store';

let instance = null;

function render(props = {}) {
  const { container } = props;
  instance = createApp(App);
  instance.use(store)
    .use(router)
    .mount(container ? container.querySelector('#app') : '#app');
  //这里的app是在public/index.html里的div的id,和之前主应用了配置的无关
}

if (!window.__POWERED_BY_QIANKUN__) {
  render();
}

//暴露生命周期的三个函数
export async function bootstrap() {
  console.log('%c ', 'color: green;', 'vue3.0 app bootstraped');
}

export async function unmount() {
  instance.unmount();
  instance._container.innerHTML = '';
  instance = null;
}

export const mount = async (props) => {
  console.log('子应用加载');

  render(props);
};

(3)配置router.js

主要是history: 的配置,这里的vueSub要和主应用里配置的一致。

import { createRouter, createWebHistory } from 'vue-router';
import Home from '../views/Home.vue';

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home,
    children: [
      {
        path: '/about',
        component: () => import(/* webpackChunkName: "about" */ '../views/About.vue'),
        name: '用户列表',
      },
    ],
  },
];

const router = createRouter({
  base: '',
  history: createWebHistory(window.__POWERED_BY_QIANKUN__ ? '/vueSub' : '/'),

  routes,
});

export default router;

(4)配置vue.config.js

这里的配置重点是3个地方,一个是端口号,要和主应用的一致,library也要和主应用一致,最后是要配置跨域。 library: 'vueSub', port: 9002,

const path = require('path')
const { packageName } = require('./package')

function resolve (dir) {
  return path.join(__dirname, dir)
}

module.exports = {
  filenameHashing: true,
  lintOnSave: process.env.NODE_ENV !== 'production',
  runtimeCompiler: true,
  productionSourceMap: false,
  devServer: {
    hot: true,
    disableHostCheck: true,
    port: 9002,//与主应用配置的一致
    overlay: {
      warnings: false,
      errors: true
    },
    headers: {
      "Access-Control-Allow-Origin": "*"
  },
  },
  // 自定义webpack配置
  configureWebpack: {
    resolve: {
      alias: {
        '@': resolve('src')
      }
    },
    output: {
      // 把子应用打包成 umd 库格式
      library: 'vueSub',//与主应用配置的一致
      libraryTarget: 'umd',
      jsonpFunction: `webpackJsonp_${packageName}`
    }
  }
}

以上项目建完了,只要调用router的push就能进行跳转。具体看下一部分