vue3+quasar+qiankun

image.png

上圖描述了qiankun微前端的運(yùn)行過(guò)程,父子應(yīng)用之間可以獨(dú)立運(yùn)行.沒(méi)有子應(yīng)用,不影響父應(yīng)用的運(yùn)行.沒(méi)有父應(yīng)用,子應(yīng)用也是可以獨(dú)立運(yùn)行.

qiankun官網(wǎng)描述步驟非常詳細(xì):https://qiankun.umijs.org/zh/guide/getting-started

父應(yīng)用(使用的是vue2)

  1. 安裝qiankun,npm i qiankun -S
  2. 在vue組件注冊(cè)(不一定是vue組件,main.js中也可以)
    PointsStore.vue:
<template>
    <div class="PointsStore">
        <div id="pointStore"></div><!--子應(yīng)用在父應(yīng)用中的位置-->
    </div>
</template>

<script>
import { registerMicroApps, start, initGlobalState } from 'qiankun';
export default {
    ...
    watch: {
        language () {
            // 數(shù)據(jù)變化時(shí),給子應(yīng)用傳遞數(shù)據(jù)
            this.actions && this.actions.setGlobalState(data);
        }
    },
    mounted() {
        const initState = {};
            // action用來(lái)和子應(yīng)用通信,每次mounted的時(shí)候都要初始化一遍
            this.actions = initGlobalState(initState);
            if (!window.qiankunStarted) { // 只需注冊(cè)一次子應(yīng)用
                window.qiankunStarted = true;
                // 注冊(cè)子應(yīng)用
                registerMicroApps([
                    {
                        name: 'pointStore', // app的名稱
                        entry: 'http://localhost:8081/', // 加載子應(yīng)用的入口url
                        container: '#pointStore', // 對(duì)應(yīng)template中的<div id="pointStore"></div>
                        activeRule: '/point-store/', // 激活子應(yīng)用的路由
                        props: {
                            token: 'xx' // 向子應(yīng)用傳遞的數(shù)據(jù)
                        }
                    }
                ]);

                start();
            }
    },
    beforeDestroy() {
        // 組件銷(xiāo)毀的時(shí)候不要忘了offGlobalStateChange.否則會(huì)出現(xiàn)監(jiān)聽(tīng)不到數(shù)據(jù)的情況
        if (this.actions && this.actions.offGlobalStateChange) {
            this.actions.offGlobalStateChange();
        }
    }
};
</script>
  1. router.js
{
    path: 'point-store/*', // 重要,注意增加'/*',路由匹配到point-store/*時(shí),都加載PointsStore.vue
    name: 'PointsStore',
    component: () => import('../views/PointsStore.vue'),
},

微應(yīng)用(使用的是vue3)

qiankun官網(wǎng)說(shuō)在應(yīng)用入口導(dǎo)出生命周期鉤子,但是quasar的入口不是main.ts,入口文件是quasar自動(dòng)生成的,quasar自動(dòng)生成文件夾:.quasar,其中包含一個(gè)項(xiàng)目入口文件client-entry.js

  1. 新增入口文件
$ quasar new boot micro-lifeCycle.js 

參考:https://next.quasar.dev/quasar-cli/boot-files#usage-of-boot-files

  1. micro-lifeCycle.js如下:
import { boot } from 'quasar/wrappers';
// 重要:由于需要在mount的時(shí)候需要重新實(shí)例化app(即 new Vue),但是quasar應(yīng)用不是通過(guò)new Vue()實(shí)現(xiàn)的,而是調(diào)用.quasar/client-entry.js內(nèi)的方法,所以根據(jù).quasar/*新建了src/quasar-init/*
// src/quasar-init/*的內(nèi)容和./quasar/*的內(nèi)容幾乎是一致的,區(qū)別:src/quasar-init/client-entry導(dǎo)出了init方法
import { init } from 'src/quasar-init/client-entry'; 
import * as Types from 'src/store/consts';

// 如果該應(yīng)用是作為子應(yīng)用運(yùn)行
if (window.__POWERED_BY_QIANKUN__) {
  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__; // 參考:https://qiankun.umijs.org/zh/faq#a-%E4%BD%BF%E7%94%A8-webpack-%E8%BF%90%E8%A1%8C%E6%97%B6-publicpath-%E9%85%8D%E7%BD%AE
  render();
}
class Actions {
  // 默認(rèn)值為空 Action
  actions = {
    onGlobalStateChange: () => { },
    setGlobalState: () => { }
  };
  /**
   * 設(shè)置 actions
   */
  setActions(actions) {
    this.actions = actions;
  }
  /**
   * 映射
   */
  onGlobalStateChange(...args) {
    return this.actions.onGlobalStateChange(...args);
  }
  /**
   * 映射
   */
  setGlobalState(...args) {
    return this.actions.setGlobalState(...args);
  }
}

const actions = new Actions();

// render第一次和第二次被調(diào)用是: if (window.__POWERED_BY_QIANKUN__) { render(); }, // props為{}
// 后面被調(diào)用是微前端生命周期鉤子的mount: async function mount(props) {render(props);} // props不再事空對(duì)象,有container屬性和值
function render(props = {}) {
  const { container } = props; // props來(lái)自父應(yīng)用,container是注冊(cè)子前端時(shí),設(shè)置的container
  // container有值,表示子應(yīng)用找到落腳點(diǎn)了,需要重新初始化;
  // init方法相當(dāng)于執(zhí)行了一遍./quasar/client-entry.js
  if (container) {
    init();
    // action的作用:和主應(yīng)用通信
    actions.setActions(props);
    actions.onGlobalStateChange(state => {
      const { xxx } = state;
      // todo something
    }, true);
  }
}


async function bootstrap() {
  console.log('vue app bootstraped');
}

/**
 * 應(yīng)用每次進(jìn)入都會(huì)調(diào)用 mount 方法,通常我們?cè)谶@里觸發(fā)應(yīng)用的渲染方法
 */
async function mount(props) {
  console.log('vue app mount');
  render(props); // 相當(dāng)于new Vue
}

/**
 * 應(yīng)用每次 切出/卸載 會(huì)調(diào)用的方法,通常在這里我們會(huì)卸載微應(yīng)用的應(yīng)用實(shí)例
 */
async function unmount() {
  console.log('vue app unmount');
  if (window._POINT_STORE_APP_INSTANCE) {
    window._POINT_STORE_APP_INSTANCE.unmount(); // 一定要卸載
  }
}

/**
 * 可選生命周期鉤子,僅使用 loadMicroApp 方式加載微應(yīng)用時(shí)生效
 */
async function update() {
  console.log('update props');
}

export default boot(({ app, store }) => {
  // 如果有實(shí)例,unmount
  if (window._POINT_STORE_APP_INSTANCE) {
    window._POINT_STORE_APP_INSTANCE.unmount();
  }
  window._POINT_STORE_APP_INSTANCE = app;
  window._POINT_STORE_STORE = store; // store保存到window下,如果有用到store的話
})

export { bootstrap, mount, unmount, update }

props:


image.png
  1. src/quasar-init/client-entry.js
    和.quasar/client-entry.js差不多,區(qū)別:
// src/quasar-init/client-entry.js
// 封裝createQuasarApp且導(dǎo)出
export function init() { 
  createQuasarApp(createApp)

    .then(app => {
      return Promise.all([
        
        import(/* webpackMode: "eager" */ 'boot/i18n'),
        
        import(/* webpackMode: "eager" */ 'boot/axios'),
        
        import(/* webpackMode: "eager" */ 'boot/initApp.ts'),
        
        import(/* webpackMode: "eager" */ 'src/boot/micro-lifeCycle.js')
        
      ]).then(bootFiles => {
        const boot = bootFiles
          .map(entry => entry.default)
          .filter(entry => typeof entry === 'function')

        start(app, boot)
      })
    })
}
// .quasar/client-entry.js
createQuasarApp(createApp)

  .then(app => {
    return Promise.all([
      
      import(/* webpackMode: "eager" */ 'boot/i18n'),
      
      import(/* webpackMode: "eager" */ 'boot/axios'),
      
      import(/* webpackMode: "eager" */ 'boot/initApp.ts'),
      
      import(/* webpackMode: "eager" */ 'boot/./micro-lifeCycle.js')
      
    ]).then(bootFiles => {
      const boot = bootFiles
        .map(entry => entry.default)
        .filter(entry => typeof entry === 'function')

      start(app, boot)
    })
  })
  1. 配置微應(yīng)用的打包工具
    qiankun配置微應(yīng)用的打包工具
    quasar.conf.js:
const packageName = require('./package.json').name;
module.exports = configure(function (/* ctx */) {
    return {
        boot: [
            'i18n',
            'axios',
            'initApp.ts',
            './micro-lifeCycle.js'
        ],
        build: {
            ...
            chainWebpack(chain) {
                // 設(shè)置入口文件,設(shè)置微前端的生命周期鉤子
                chain
                    .entry('main')
                    .add('src/boot/micro-lifeCycle.js')
                    .end()
                    .output
                    .library('pointStore')
                    .libraryTarget('umd')
                    .jsonpFunction(`webpackJsonp_${packageName}`);
                // 重要:參考https://qiankun.umijs.org/zh/faq; 如果不設(shè)置,那么字體庫(kù)找不到
                chain.module.rule('fonts').use('url-loader').loader('url-loader').options({}).end();
            },

        },
        devServer: {
            headers: {
                'Access-Control-Allow-Origin': '*' // 重要
            },
            port: 8000,
            ...
        }
        ...
    }
});

  1. 目錄結(jié)構(gòu)


    image.png

注意事項(xiàng)

  1. 基座應(yīng)用的全局樣式會(huì)影響子應(yīng)用,子應(yīng)用的不會(huì)影響基座應(yīng)用
  2. 子應(yīng)用的字體庫(kù)需要在build的時(shí)候使用loader字體配置:
    chain.module.rule('fonts').use('url-loader').loader('url-loader').options({}).end();

抖音上看到一個(gè)圖:


image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容