微前端框架乾坤配置记录

news/2024/7/10 0:37:43 标签: 前端, 微前端, 乾坤, qiankun, vue

主应用

1. 路由包装为history模式

// src/main.js
import routes from './routes';
const router = new VueRouter({
  mode: 'history',
  routes
});

new Vue({
  router,
  store,
  render: (h) => h(App)
}).$mount('#app');

2. 引入乾坤前端主应用配置

// src/mico/index.js

import { registerMicroApps, addGlobalUncaughtErrorHandler, start } from 'qiankun';

import apps from './apps';

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 { msg } = event;
  if (msg && msg.includes('died in status LOADING_SOURCE_CODE')) {
    console.log('微应用加载失败,请检查应用是否可运行');
  }
});

export default start;

3. 配置子应用列表

// /src/micfo/apps.js

const apps = [
    {
        name: 'planResource',
        entry: '//localhost:8083',
        container: '#iframe',
        activeRule: '/plan'
    },
    {
        name: 'configration',
        entry: '//localhost:8081',
        container: '#iframe',
        activeRule: '/configure'
    }
];

export default apps;

4. 主应用实例化后启动微应用监听

// /src/main.js
import startQiankui from './micro';

new Vue({
  router,
  store,
  render: (h) => h(App)
}).$mount('#app');

startQiankui();

子应用

1. Vue应用接入

1.1 修改webpack配置

// webpack.config.js || vue.config.js

devServer: 
	port: 8083 // 端口要写死,因为主应用中配置子应用列表时用的是写死的端口配置
	disableHostCheck: false // 关闭主机检查,保证子应用可以被主应用fetch到
	headers: {
		'Access-Control-Allow-Origin': '*', // 配置跨域请求头,解决开发环境跨域问题
	}
	publicPath: process.env.NODE_ENV === 'production' ? '/newplanning/' : '//localhost:8083',  // 开发环境设置为当前固定访问地址
}
configureWebpack: {
	 output: { 
            library: 'planResource', // 名称要和主应用中配置的子应用列表中的name字段相同
            libraryTarget: 'umd', // 把子应用打包成 umd 库格式
            jsonpFunction: `webpackJsonp_planResource` //  此处后缀也要和名称保持一致
        }
}

1.2 增加 public-path配置文件并在入口文件引入

//  /src/micro/public-path.js
if (window.__POWERED_BY_QIANKUN__) {
    // eslint-disable-next-line no-undef
    __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}

//  /src/main.js

import '@micro/public-path'

1.3 路由实例化配置

// src/router/index.js
import Vue from 'vue';
import Router from 'vue-router';
import routes from './routers.js';

Vue.use(Router);

export default new Router({
    base: window.__POWERED_BY_QIANKUN__ ? '/plan' : '/', // 如果作为乾坤的子应用则使用主应用中配置的路由前缀,如果是独立运行则使用根目录
    mode: 'hash', 
    routes // 路由定义数组
});

1.4 Vue实例化包装和生命周期钩子导出

//  /src/main.js
import './public-path';
import router from './router';
let instance = null;

// 重新包装render方法
function render(props = {}) {
    const { container } = props;
    const renderContainer = container ? container.querySelector('#app') : '#app'; // 如果是作为子应用渲染,则渲染到主应用中配置的DOM节点中

    instance = new Vue({
        router,
        store,
        render: h => h(App)
    }).$mount(renderContainer);
}

// 独立运行时直接渲染
if (!window.__POWERED_BY_QIANKUN__) {
    render();
}

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

export async function mount(props) {
    console.log('[vue] props from main framework', props);
    render(props); // 作为子应用渲染时将主应用传入的配置作为参数去渲染
}

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

1.5 将代理信息复制到主应用

2. angularjs 应用接入

2.1 引入 HTML entry

// index.html
<body>
  <!-- ... >
	<script src="//localhost:8080/lib/micro/entry.js" entry></script>
</body>

2.2 入口配置

// /src/lib/micro/entry.js

((global) => {
    global['myAngularApp'] = {
        bootstrap: () => {
            console.log('myAngularApp bootstrap');
            return Promise.resolve();
        },
        mount: (props) => {
            console.log('myAngularApp mount', props);
            return render(props);
        },
        unmount: () => {
            console.log('myAngularApp unmount');
            return Promise.resolve();
        },
    };
})(window);

/**
 * [render 渲染函数]
 *
 * @param   {[type]}  props  [props description]
 *
 * @return  {[type]}         [return description]
 */
function render(props = {}) {
    if (props && props.container) {
        console.log('乾坤渲染');
        window.myActions = {
            onGlobalStateChange: function(...args) {
                props.onGlobalStateChange(...args);
            },
            setGlobalState: function(...args) {
                props.setGlobalState(...args);
            }
        };
        window.myActions.onGlobalStateChange(state => {
            const { token } = state;
            console.log(token);
            // 未登录 - 返回主页
            if (!token) {
                console.log('未检测到登录信息!');
                window.location.href = '/';
            }
            localStorage.setItem('myAngularApp-token', token);
        }, true);
    } else {
        angular.element(document).ready(function () {
            angular.bootstrap(document, ['app']);
            return Promise.resolve();
        });
    }
}

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

2.3 路由前缀

需要注意的是,对于angularjs,路由一定要改造为统一的前缀,这样子应用不同路由之间的跳转才好被主路由统一获取到。

2.4 模板路径问题

在angularjs中,我们常常会写templateUrl属性,大多数时候我们会写模板的相对地址,但是这样就造成在主应用中对应的相对路径位置是找不到模板文件的,所以路径需要加一个统一的前缀参数,根据是否运行在主应用内来设定不同前缀。

通信

1.主应用

1.1 初始化全局跨应用通信方法

// /src/mico/actions

import { initGlobalState } from 'qiankun';
const initState = {};

const actions = initGlobalState(initState);
  
export default actions;

1.2 在需要设置跨应用全局状态的组件内:

<script>
import store from '@/store'
import httpService from '@/core/httpService'
import actions from '@/micro/actions'

export default {
  name: 'App',
  created() {
    if (!store.getters.token) {
        httpService.getToken().then(data => {
            store.commit('SET_TOKEN', data.data.token);
            actions.setGlobalState({ token: data.data.token });
        });
    }
  }
}
</script>

2. 子应用

2.1 全局actions定义

//  /src/micro/actions.js

function 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;

2.2 在应用渲染前获取从主应用上的通信方法并注入到actions里

// /src/main.js

import actions from '@/micro/actions';

function render(props = {}) {
    if (props) {
        actions.setActions(props);
        actions.onGlobalStateChange(state => {
            const { token } = state;
            console.log(token);
            // 未登录 - 返回主页
            if (!token) {
              this.$message.error('未检测到登录信息!');
              return this.$router.push('/');
            }
            store.commit('SET_TOKEN', token);
          }, true);
    }
    const { container } = props;
    const renderContainer = container ? container.querySelector('#app') : '#app';

    instance = new Vue({
        router,
        store,
        render: h => h(App)
    }).$mount(renderContainer);
}

export async function mount(props) {
    console.log('[vue] props from main framework', props);
    // 注册应用间通信
    render(props);
}


http://www.niftyadmin.cn/n/1736051.html

相关文章

C语言头文件避免重复包含

假定有以下几个头文件及其包含关系为&#xff1a; 假定有以下几个头文件及其包含关系为&#xff1a; File1.h&#xff0c;file2.h&#xff0c;file3.h&#xff0c;file4.h&#xff0c;file5.h&#xff0c;main.c 那么&#xff1a;file3.h包含file1.h&#xff0c;file2.h&#x…

一种内容区高度不定的展开收起方案

缘起 在日常开发中&#xff0c;经常会遇到有些区块内容可以展开收起的需求&#xff0c;例如以下这两种&#xff1a; 固定高度式&#xff1a; 非固定式: 固定式 对于内容固定&#xff0c;高度固定的情况&#xff0c;很好实现&#xff0c;可以一开始就显示展开/收起按钮&#…

字符串拷贝

char * strcpy (char *strDest,const char *strSrc) { assert ((strDest!NULL)&&(srtrSrc!NULL)); char *strDestCopystrDest; while ((*strDest*strSrc)!\0); return strDestCopy; } 为什么要使用局部变量strDestCopy&#xff1f;这是为了不改变原来strDest 指向的…

vue项目配置多个代理的注意点

在Vue项目的开发过程中,为了本地调试方便&#xff0c;我们通常会在 vue.config.js 中配置 devServer 来在本地启动一个服务器&#xff0c;在这个选项中&#xff0c;我们会配置proxy 属性来将指向到本地的请求&#xff08;例如&#xff1a; /api/action&#xff09; 代理到后端的…

NDEBUG

头文件assert.h定义的宏受NDEBUG的影响.如果预程序在处理这个头文件时已经定义了NDEBUG,assert宏的内容就定义为空,这意味着assert宏不在起作用.所以,可以在最终发布程序的时候可以使用-DNDEBUG关闭断言功能或者把#define NDEBUG加到每个源文件中,但这条语句必须放在#include &…

JS 中 `toLocaleString`妙用

缘起 kaven老师分享了一个数值取整的方法&#xff0c;即利用按位非操作符&#xff08;~&#xff09;进行取整&#xff1a; var a 1.5; console.log(~~a); // 1但是这种方法有点限制就是它只能进行向下取整&#xff0c;无法实现四舍五入。 所以就想到了toLocaleString() 方法…

js经典面试题-连续赋值时发生了什么

题目 var a {n:1}; var b a; a.x a {n:2}console.log(a); // ? console.log(b); // ? console.log(a.x) // ?考点分析 连续赋值的解析是从左到右的连续赋值的运算是从右到左的引用类型变量二次赋值时有一个重新绑定的过程对于引用类型&#xff0c;栈内存里存储的是一个…

TRACE宏 ASSERT宏 VERIFY 宏

一、TRACE宏 当选择了Debug目标&#xff0c;并且afxTraceEnabled变量被置为TRUE时&#xff0c;TRACE宏也就随之被激活了。但在程序的Release版本中&#xff0c;它们是被完全禁止的。下面是一个典型的TRACE语句&#xff1a; … int nCount 9 ; CStr…