vue3+quasar+qiankun

image.png

上图描述了qiankun微前端的运行过程,父子应用之间可以独立运行.没有子应用,不影响父应用的运行.没有父应用,子应用也是可以独立运行.

qiankun官网描述步骤非常详细:https://qiankun.umijs.org/zh/guide/getting-started

父应用(使用的是vue2)

  1. 安装qiankun,npm i qiankun -S
  2. 在vue组件注册(不一定是vue组件,main.js中也可以)
    PointsStore.vue:
<template>
    <div class="PointsStore">
        <div id="pointStore"></div><!--子应用在父应用中的位置-->
    </div>
</template>

<script>
import { registerMicroApps, start, initGlobalState } from 'qiankun';
export default {
    ...
    watch: {
        language () {
            // 数据变化时,给子应用传递数据
            this.actions && this.actions.setGlobalState(data);
        }
    },
    mounted() {
        const initState = {};
            // action用来和子应用通信,每次mounted的时候都要初始化一遍
            this.actions = initGlobalState(initState);
            if (!window.qiankunStarted) { // 只需注册一次子应用
                window.qiankunStarted = true;
                // 注册子应用
                registerMicroApps([
                    {
                        name: 'pointStore', // app的名称
                        entry: 'http://localhost:8081/', // 加载子应用的入口url
                        container: '#pointStore', // 对应template中的<div id="pointStore"></div>
                        activeRule: '/point-store/', // 激活子应用的路由
                        props: {
                            token: 'xx' // 向子应用传递的数据
                        }
                    }
                ]);

                start();
            }
    },
    beforeDestroy() {
        // 组件销毁的时候不要忘了offGlobalStateChange.否则会出现监听不到数据的情况
        if (this.actions && this.actions.offGlobalStateChange) {
            this.actions.offGlobalStateChange();
        }
    }
};
</script>
  1. router.js
{
    path: 'point-store/*', // 重要,注意增加'/*',路由匹配到point-store/*时,都加载PointsStore.vue
    name: 'PointsStore',
    component: () => import('../views/PointsStore.vue'),
},

微应用(使用的是vue3)

qiankun官网说在应用入口导出生命周期钩子,但是quasar的入口不是main.ts,入口文件是quasar自动生成的,quasar自动生成文件夹:.quasar,其中包含一个项目入口文件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的时候需要重新实例化app(即 new Vue),但是quasar应用不是通过new Vue()实现的,而是调用.quasar/client-entry.js内的方法,所以根据.quasar/*新建了src/quasar-init/*
// src/quasar-init/*的内容和./quasar/*的内容几乎是一致的,区别:src/quasar-init/client-entry导出了init方法
import { init } from 'src/quasar-init/client-entry'; 
import * as Types from 'src/store/consts';

// 如果该应用是作为子应用运行
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 {
  // 默认值为空 Action
  actions = {
    onGlobalStateChange: () => { },
    setGlobalState: () => { }
  };
  /**
   * 设置 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第一次和第二次被调用是: if (window.__POWERED_BY_QIANKUN__) { render(); }, // props为{}
// 后面被调用是微前端生命周期钩子的mount: async function mount(props) {render(props);} // props不再事空对象,有container属性和值
function render(props = {}) {
  const { container } = props; // props来自父应用,container是注册子前端时,设置的container
  // container有值,表示子应用找到落脚点了,需要重新初始化;
  // init方法相当于执行了一遍./quasar/client-entry.js
  if (container) {
    init();
    // action的作用:和主应用通信
    actions.setActions(props);
    actions.onGlobalStateChange(state => {
      const { xxx } = state;
      // todo something
    }, true);
  }
}


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

/**
 * 应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法
 */
async function mount(props) {
  console.log('vue app mount');
  render(props); // 相当于new Vue
}

/**
 * 应用每次 切出/卸载 会调用的方法,通常在这里我们会卸载微应用的应用实例
 */
async function unmount() {
  console.log('vue app unmount');
  if (window._POINT_STORE_APP_INSTANCE) {
    window._POINT_STORE_APP_INSTANCE.unmount(); // 一定要卸载
  }
}

/**
 * 可选生命周期钩子,仅使用 loadMicroApp 方式加载微应用时生效
 */
async function update() {
  console.log('update props');
}

export default boot(({ app, store }) => {
  // 如果有实例,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差不多,区别:
// src/quasar-init/client-entry.js
// 封装createQuasarApp且导出
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. 配置微应用的打包工具
    qiankun配置微应用的打包工具
    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) {
                // 设置入口文件,设置微前端的生命周期钩子
                chain
                    .entry('main')
                    .add('src/boot/micro-lifeCycle.js')
                    .end()
                    .output
                    .library('pointStore')
                    .libraryTarget('umd')
                    .jsonpFunction(`webpackJsonp_${packageName}`);
                // 重要:参考https://qiankun.umijs.org/zh/faq; 如果不设置,那么字体库找不到
                chain.module.rule('fonts').use('url-loader').loader('url-loader').options({}).end();
            },

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

  1. 目录结构


    image.png

注意事项

  1. 基座应用的全局样式会影响子应用,子应用的不会影响基座应用
  2. 子应用的字体库需要在build的时候使用loader字体配置:
    chain.module.rule('fonts').use('url-loader').loader('url-loader').options({}).end();

抖音上看到一个图:


image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容