关于qiankun与vue-cli的使用和构建过程

2022年了,我还在研究qiankun,都被用烂了。看到招聘要求上一栏写着会qiankun,我默默的学起来。

这里主应用和子应用都是用vue-cli4X框架,期间遇到了一些坑也都解决了。

第一步安装qiankun

yarn add qiankun # 或者 npm i qiankun -S

main为主应用,sub-app1,sub-app2为微应用,如下图。

 

 

第二步,在主应用入口文件注册微应用

/qiankun-vue/main/main.js

 

 

import './public-path.js'
import { createApp } from 'vue'
import router from './router'
import store from './store'
import App from './App.vue'
const app = createApp(App);
app.use(store)
app.use(router)
app.mount('#app')
function genActiveRule(routerPrefix) {
  return location => location.pathname.startsWith(routerPrefix);
}

import { registerMicroApps, start } from 'qiankun';
registerMicroApps([
    {
        name: 'sub-app1',
          entry: '//localhost:3012', // 运行微应用的地址
          container: '#container', // 展示的DOM容器 id
          activeRule: genActiveRule('/sub-app1'), // 跳转路径
    },{
        name: 'sub-app2',
        entry: '//localhost:3013',
        container: '#container',
        activeRule: genActiveRule('/sub-app2'),
    },
],
{
    beforeLoad: [
      app => {
        console.log('before load', app);
      },
    ],
    beforeMount: [
      app => {
        console.log('before mount', app);
      },
    ],
    afterMount: [
      app => {
        console.log('after mount', app);
      },
    ],
    afterUnmount: [
      app => {
        console.log('after unload', app);
       // app.render({appContent: '', loading: false});
      },
    ],
  }
  );
// 启动 qiankun
start();

第三步,配置主应用路由

/qiankun-vue/main/...router/index.js

import { createRouter,createWebHistory }  from 'vue-router';
const Home = () => import(/*WebpackChunkName*/'@/views/Home.vue')
const About = () => import(/*WebpackChunkName*/'@/views/About.vue')
const routes = [
    {path:'/',name:'home',component: Home},
    {path:'/about',name:'about',component: About},
    {path:'/sub:catchAll(.*)',name:'Child',component:()=>import(/*webpackChunkName:'Empty.vue'*/'@/views/Empty.vue')} //这里遇到一个坑,就是找不到/sub-app1 /sub-app2路由路径,我就在此设置默认路径
]; const router = createRouter({ history: createWebHistory(), routes, }) export default router

/qiankun-vue/main/App.vue

<template>
<nav>
      <router-link to="/">Home</router-link> |
      <router-link to="/about">About</router-link> |
      <!--需要与main.js配置的跳转路由一致-->
      <router-link to="/sub-app1">sub-app1</router-link> |
      <router-link to="/sub-app2">sub-app2</router-link>
    </nav>
    <router-view/>
    <!--微应用在此展示-->
    <div id="container"></div>
  <img alt="Vue logo" src="./assets/logo.png">

</template>

第四步,就需要在微应用上做对接了,只在主应用上配置了,微应用不配置也跑不起来

/qiankun-vue/sub-app1/main.js

import './public-path.js'
import { createApp } from 'vue'
import App from './App.vue'
import routes from './router'
import { createRouter, createWebHistory } from 'vue-router';
import store from './store'

let router = null;
let instance = null;
let history = null;

function render(props = {}) {
    const { container } = props;
    history = createWebHistory(window.__POWERED_BY_QIANKUN__ ? '/sub-app1' : '/');
    router = createRouter({
        history,
        routes: routes,
    });
    instance = createApp(App);
    instance.use(router);
    instance.use(store);
    instance.mount(container ? container.querySelector('#app') : '#app');
}

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

export async function bootstrap() {
    console.log('%c%s', 'color: green;', 'vue3.0 app bootstraped');
}

function storeTest(props) {
    props.onGlobalStateChange &&
    props.onGlobalStateChange(
        (value, prev) => console.log(`[onGlobalStateChange - ${props.name}]:`, value, prev),
        true,
    );
    props.setGlobalState &&
    props.setGlobalState({

    });
}

export async function mount(props) {
    storeTest(props);
    render(props);
    instance.config.globalProperties.$onGlobalStateChange = props.onGlobalStateChange;
    instance.config.globalProperties.$setGlobalState = props.setGlobalState;
}

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

在/sub-app1根目录下新建一个public-path.js文件

if (window.__POWERED_BY_QIANKUN__) {
    __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
  }

然后配置vue.config.js

const { defineConfig } = require('@vue/cli-service')
const path = require('path')
const packageName = require('./package').name;

function resolve(dir){
  return  path.join(__dirname,dir)
}
module.exports = defineConfig({
  transpileDependencies: true,
  lintOnSave:false,
  publicPath: '//localhost:3012',
  devServer:{
    port:3012,
    client:{
      overlay: {
        warnings: false,
        errors: true
      },
    },
    headers: {
      'Access-Control-Allow-Origin': '*',
    },
  },
  configureWebpack: {
    resolve: {
      alias: {
        '@': resolve('src')
      }
    },
    output: {
      library: `sub-app1`,
      libraryTarget: 'umd', // 把微应用打包成 umd 库格式
      chunkLoadingGlobal: `webpackJsonp_${packageName}`,
    },
  }
})

第五步配置sub-app2的微任务

/sub-app2/main.js

import './public-path.js'
import { createApp } from 'vue'
import App from './App.vue'
import routes from './router'
import { createRouter, createWebHistory } from 'vue-router';
import store from './store'

let router = null;
let instance = null;
let history = null;

function render(props = {}) {
    const { container } = props;
    history = createWebHistory(window.__POWERED_BY_QIANKUN__ ? '/sub-app2' : '/');
    router = createRouter({
        history,
        routes: routes,
    });
    instance = createApp(App);
    instance.use(router);
    instance.use(store);
    instance.mount(container ? container.querySelector('#app') : '#app');
}

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

export async function bootstrap() {
    console.log('%c%s', 'color: green;', 'sub-app2 page');
}

function storeTest(props) {
    props.onGlobalStateChange &&
    props.onGlobalStateChange(
        (value, prev) => console.log(`[onGlobalStateChange - ${props.name}]:`, value, prev),
        true,
    );
    props.setGlobalState &&
    props.setGlobalState({
        ignore: props.name,
        user: {
            name: props.name,
        },
    });
}

export async function mount(props) {
    storeTest(props);
    render(props);
    instance.config.globalProperties.$onGlobalStateChange = props.onGlobalStateChange;
    instance.config.globalProperties.$setGlobalState = props.setGlobalState;
}

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


新键public-path.js,同sub-app1方法一样,再重复一次,我直接放代码了。

vue.config.js

const { defineConfig } = require('@vue/cli-service')
const path = require('path')
const packageName = require('./package').name;

function resolve(dir){
  return  path.join(__dirname,dir)
}
module.exports = defineConfig({
  transpileDependencies: true,
  lintOnSave:false,
  publicPath: '//localhost:3013',
  devServer:{
    port:3013,
    client:{
      overlay: {
        warnings: false,
        errors: true
      },
    },
    headers: {
      'Access-Control-Allow-Origin': '*',
    },
  },
  configureWebpack: {
    resolve: {
      alias: {
        '@': resolve('src')
      }
    },
    output: {
      library: `sub-app2`,
      libraryTarget: 'umd', // 把微应用打包成 umd 库格式
      chunkLoadingGlobal: `webpackJsonp_${packageName}`,
    },
  }
})

最后就可以跑起来啦

 

 

posted @ 2022-06-17 07:39  前端噜噜  阅读(473)  评论(0编辑  收藏  举报