微前端框架(qiankun)应用记录

参考:

  • https://qiankun.umijs.org/zh/...
  • https://blog.csdn.net/hjb2722...
  • 其余

纳闷

  1. 主框架和子框架是否都要装置乾坤框架
答:不是,只须要装置在主框架即可,子框架不须要引入

应用办法

主利用

  1. 路由倡议应用history模式
  2. 装置 qiankun

    yarn add qiankun 或者 npm i qiankun -S

  3. 配置微利用

    // /src/micro/apps.jsconst apps = [    {        name: 'planResource',        entry: '//localhost:8083',        container: '#iframe',        activeRule: '/plan'    },    {        name: 'configration',        entry: '//localhost:8081',        container: '#iframe',        activeRule: '/configure'    }];export default apps;
  1. 在主利用中注册微利用

    // src/micro/index.jsimport { registerMicroApps, addGlobalUncaughtErrorHandler, start } from 'qiankun';import apps from './apps';// registerMicroApps 第二个参数能够不要,如果要做点啥,就写到对应的中央registerMicroApps(apps,{  beforeLoad: [    app => {      console.log('[LifeCycle] before load %c%s', 'color: green;', app.name);    },  ],  beforeMount: [    app => {      console.log('[LifeCycle] before mount %c%s', 'color: green;', app.name);    },  ],  afterUnmount: [    app => {      console.log('[LifeCycle] after unmount %c%s', 'color: green;', app.name);    },  ],},);// 出错时显示的内容addGlobalUncaughtErrorHandler((event) => {  // console.log(event);  const { message } = event;  if (message && message.includes('died in status LOADING_SOURCE_CODE')) {    console.log('微利用加载失败,请查看利用是否可运行');  }});export default start;
  2. 应用 start

    // /src/main.jsimport microApp from './micro';new Vue({  router,  store,  render: (h) => h(App)}).$mount('#app');microApp();

留神:

<font color=orange>不肯定要放在入口文件内,看你的我的项目而定</font>

  1. 如果你的微利用容器在index.html里的话,是没有多大问题,
  2. 然而很多时候是嵌入在Layout框架里的,失常进入是没有问题,如果是在微利用门路下刷新页面,会有如下图片的报错

    <font color=red>Uncaught Error: application 'cloud' died in status LOADING_SOURCE_CODE: [qiankun] Target container with #cloud not existed while cloud loading!</font>

这种状况下倡议在改选件的mounted事件钩子下start, main.js下引入,不执行即可

eg:

//main.js...import microApp from './micro' // 加载乾坤appmicroApp // 注册利用// 蕴含子利用容器的VUE组件<template>  <div class="vab-app-main">    <section>      <transition mode="out-in" name="fade-transform">        <vab-keep-alive v-if="routerView" />      </transition>      <div id="cloud"></div>      <div id="vue3"></div>    </section>    <vab-footer />  </div></template><script>  ...  import { start } from 'qiankun'  export default {    name: 'VabAppMain',    data() {      return {        ...      }    },    ...    mounted() {      start({        prefetch: false, // 勾销预加载      }) // 开启    },    ...  }</script>

子利用

  1. 批改webpack配置

    // webpack.config.js || vue.config.jsconst port = 8088;const packageName = require("./package.json").name;module.exports = {  lintOnSave: false, // 敞开eslint检测  devServer: {    port, // 这里的端口是必须和父利用配置的子利用端口统一    disableHostCheck: false, // 敞开主机查看,保障子利用能够被主利用fetch到    headers: {      //因为qiankun外部申请都是fetch来申请资源,所以子利用必须容许跨域      "Access-Control-Allow-Origin": "*",    },  },  configureWebpack: {    output: {      //资源打包门路      library: `${packageName}`,      libraryTarget: "umd",      jsonpFunction: `webpackJsonp_${packageName}`,      // publicPath: `//localhost:${port}`,    },  },  // outputDir: 'dist',  // assetsDir: 'static',  // filenameHashing: true,};
  2. 减少 public-path配置文件并在入口文件引入

    //  /src/micro/public-path.jsif (window.__POWERED_BY_QIANKUN__) {    // eslint-disable-next-line no-undef    __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;}//  /src/main.jsimport '@/micro/public-path'
  1. 路由实例化配置

    // src/router/index.jsimport Vue from 'vue'import VueRouter from 'vue-router'Vue.use(VueRouter)const routes = [    {        path: '/',        name: 'Home',        component: () => import('../views/Home.vue')    },    {        path: '/about',        name: 'About',        component: () => import('../views/About.vue')    }]const router = new VueRouter({    mode: 'history',    // @ts-ignore    base: window.__POWERED_BY_QIANKUN__ ? '/cloud' : '/', // 独立运行是用"/"作为根门路    // base: '/cloud',    routes})export default router
  2. Vue实例化包装和生命周期钩子导出

    // /src/main.jsimport "@/micro/public-path";import Vue from "vue";import App from "./App.vue";import actions from "./micro/actions.js";import router from "./router";import store from "./sotre";let instance = null;function render(props = {}) {  // 通过实际这个判断要有,不然在独立运行时报错  if (window.__POWERED_BY_QIANKUN__) {    if (props) {      actions.setActions(props);      actions.onGlobalStateChange((state) => {        console.log("app1", state);      }, true);    }  }  const { container } = props;  // 这里是挂载到本人的html中  基座会拿到这个挂载后的html 将其插入进去  const renderContainer = container ? container.querySelector("#app") : "#app";  instance = new Vue({    router,    store,    render: (h) => h(App),  }).$mount(renderContainer);}// @ts-ignoreif (!window.__POWERED_BY_QIANKUN__) {  // 默认独立运行  render();}// 父利用加载子利用,子利用必须裸露三个接口:bootstrap、mount、unmountexport async function bootstrap() {  console.log("cloud app bootstraped");}export async function mount(props) {  console.log("mount");  render(props);}export async function unmount() {  console.log("unmount");  instance.$destroy();}

传值 <font color=red>Actions</font>

props 传值不够灵便,不举荐应用

<font color=red>Actions</font>举荐应用办法,能够在状态扭转时触发

主利用

  1. 初始化全局跨利用通信办法
// /src/micro/actions.jsimport { initGlobalState } from 'qiankun';const initState = {};const actions = initGlobalState(initState);export default actions;
  1. 在须要设置跨利用全局状态的组件内:
// /src/app.vue<template>  <div id="app">    <router-view />  </div></template><script>  import actions from '@/micro/actions'  export default {    name: 'App',    computed: {      visitedRoutes() {        return this.$store.state.tabs.visitedRoutes //须要监听的数据      },    },    watch: {      visitedRoutes(newVal, oldVal) {        this.setGlobalState()      },    },    created() {      // this.setGlobalState()    },    methods: {      setGlobalState() {        let data = {          time: this.$store.state.user.time,          token: this.$store.state.user.token,          ability: this.$store.state.acl,          routes: this.$store.state.routes,          tabs: this.$store.state.tabs.visitedRoutes,        }        actions.setGlobalState(data)      },    },  }</script>

留神:

<font color=orange>能够监听vuex数据,如果变动,执行setGlobalState</font>

子利用

  1. 全局actions定义
//  /src/micro/actions.jsfunction emptyAction() {    // 正告:提醒以后应用的是空 Action    console.warn('Current execute action is empty!');  }  class Actions {    // 默认值为空 Action    actions = {      onGlobalStateChange: emptyAction,      setGlobalState: emptyAction    };    /**     * 设置 actions     */    setActions(actions) {      this.actions = actions;    }    /**     * 映射     */    onGlobalStateChange(...args) {      return this.actions.onGlobalStateChange(...args);    }    /**     * 映射     */    setGlobalState(...args) {      return this.actions.setGlobalState(...args);    }  }  const actions = new Actions();  export default actions;
  1. 在利用渲染前获取从主利用上的通信办法并注入到actions里
// /src/main.jsimport "@/micro/public-path";import Vue from "vue";import App from "./App.vue";import actions from "./micro/actions.js";import router from "./router";import store from "./sotre";let instance = null;function render(props = {}) {  // @ts-ignore  if (window.__POWERED_BY_QIANKUN__) {    if (props) {      actions.setActions(props);      actions.onGlobalStateChange((state) => {        console.log("app1", state);        const { token, ability, tabs } = state;        store.state.ability = ability        store.state.token = token        store.state.tabs = tabs      }, true);    }  }  const { container } = props;  // 这里是挂载到本人的html中  基座会拿到这个挂载后的html 将其插入进去  const renderContainer = container ? container.querySelector("#app") : "#app";  instance = new Vue({    router,    store,    render: (h) => h(App),  }).$mount(renderContainer);}// @ts-ignoreif (!window.__POWERED_BY_QIANKUN__) {  // 默认独立运行  render();}// 父利用加载子利用,子利用必须裸露三个接口:bootstrap、mount、unmountexport async function bootstrap() {  console.log("cloud app bootstraped");}export async function mount(props) {  console.log("mount");  render(props);}export async function unmount() {  console.log("unmount");  instance.$destroy();}

开发DevTools

如果基座和子利用应用的都是VUE,要应用devtools是比拟老火的事件:

  1. 如果应用的devtools 5.xx 的版本,那么只能查看主框架的数据
  2. 如果应用devtools 6.xx(目前只有bata版本),且基座和子利用应用不同的VUE版本,那么能够查看对应利用的数据,<font color=orange>可是开发开发工具会不停的报错,蛋痛</font>

倡议:基座框架和子框架应用不同的框架语言开发(这样是否要好一些,或者有解决的方法)

<font color=red>主利用在什么时候传值</font>

很重要:不然首次是拿不到值的哦

参考传值Actions 主利用下的设置 监听vuex