0.1.1 • Published 3 years ago

micro-shared v0.1.1

Weekly downloads
-
License
MIT
Repository
github
Last release
3 years ago

⚡一个用于微前端的通信模块

micro-shared以redux为核心,采用发布-订阅模式进行封装,实现应用间通信数据上的响应式,并在代码结构上实现模块化,使用上编写方式及api类似vuex,上手难度低, 并可适用多框架(如vue、react)

代码: github or gitee 文档: ⚡qiankun微前端中的应用通信(四)-上手micro-shared及原理解析

安装

yarn add micro-shared

在项目中使用

  1. 首先在主应用里创建pool文件夹 @/pool
pool
 ├── index.ts
 └── modules
     ├── locale.ts
     └── user.ts
  1. 然后开始编写user.ts
import { Mutation } from 'micro-shared';
interface UserInfo {
    username: string,
}

interface State {
    userinfo?: UserInfo | Record<string, never>
}

const state:State = {
    userinfo: {},
};

const reducer = (userState: State = state, mutation: Mutation): State => {
    switch (mutation.type) {
    case 'SET_USERINFO': return {
        ...userState,
        userinfo: mutation.payload,
    }; break;
    default: return userState;
    }
};

const action = {
    getUserinfo: ( { state }: any ): UserInfo | Record<string, never> => {
        return state.userinfo || {};
    },
    setUserinfo: ({ commit }: any, userinfo: UserInfo): void => {
        commit({
            type: 'SET_USERINFO',
            payload: userinfo,
        });
    },
};

export default {
    name: 'user',
    reducer,
    action
};

可以看出整个user由三部分组成statereduceraction

同时对外暴露namereduceraction

其中name为模块名,action是微应用唯一能直接访问的api, 而state只能由reducer改变

graph TD
action --> reducer --> state
  1. 将user模块导入,同时生成shared
// pool/index.ts
import Shared from 'micro-shared';
import User from './modules/user';
import Locale from './modules/locale';

const shared = new Shared({
    modules: {
        User,
        Locale,
    },
})

export default shared.getShared();

至此shared已编写完毕,接下来通过qiankun的props传给微应用即可。

  1. 在主应用项目中,进行qiankun的微应用注册的地方
import { registerMicroApps, start } from 'qiankun';
import shared from '@/pool';

registerMicroApps([
  {
    name: 'micro',
    entry: '//localhost:8888',
    container: '#nav',
    activeRule: '/micro',
    props: {
        shared
    },
  },
]);

start();
  1. 在微应用中,接收shared实例
// @/main.ts 已隐藏无关代码
import SharedModule from '@/pool';

function render(props: any = {}) {
    const { container, shared = SharedModule.getShared() } = props;
    SharedModule.overloadShared(shared);
}
  1. 在微应用中创建 @/pool目录 (也是上一步里, import SharedModule的来源)
pool
 ├── index.ts

@/pool/index.ts也十分简单,相当于只需做模块注册即可

import SharedModule from 'micro-shared/sharedmodule';

import { Shared } from './shared';// 本地模块

SharedModule.initShared(Shared);// 加载本地模块

export default SharedModule;

第二行和第三行是用于加载本地shared实例(确保微应用独立运行时不会缺失shared),如果不考虑独立运行的话,这两行代码也可以删去。

  1. 现在你就可以在微应用自身的store里使用了
import Vue from 'vue';
import Vuex from 'vuex';
import SharedModule from '@/pool';// 从第6步创建的pool目录里引入

Vue.use(Vuex);

let shared:any = null;

export interface UserInfo {
    username: string,
}

interface State {
    locale: string,
    userinfo: UserInfo | Record<string, never>,
}

export default new Vuex.Store({
    state: {
        locale: '',
        userinfo: {},
    },
    mutations: {
        SET_LOCALE: (state: State, locale: string) => {
            state.locale = locale;
        },
        SET_USERINFO: (state: State, userinfo: UserInfo) => {
            state.userinfo = userinfo;
        },
    },
    actions: {
        /*
            初始化shared模块
            建议在main.ts中,在执行完SharedModule.overloadShared(shared)后就执行该初始化
        */
        initShared() {
            shared = SharedModule.getShared();
            this.dispatch('setLocale');
            this.dispatch('setUserinfo');

            SharedModule.subscribe([
                (stateName: string) => {
                    if(stateName === 'locale') this.dispatch('setLocale');
                },
                (stateName: string) => {
                    if(stateName === 'user') this.dispatch('setUserinfo');
                },
            ]);
        },
        setLocale({ commit }) {
            const locale = shared.dispatch('locale/getLocale');
            commit('SET_LOCALE', locale);
        },
        setUserinfo({ commit }) {
            const userinfo = shared.dispatch('user/getUserinfo');
            commit('SET_USERINFO', userinfo);
        },
    },
    getters: {
        locale: (state: State) => state.locale,
        userinfo: (state: State) => state.userinfo,
    },
    modules: {
    },
});
  1. SharedModule.subscribe 用于注册订阅事件。通过传入回调函数进行订阅, 可以数组形式批量传入,当pool内数据有变化时(监听到redux提供的set方法执行了),会通过回调函数统一发布。
  2. 注册的订阅事件可以接收一个参数 stateName,该参数会返回当前发生改变的state, 例如此次demo的state有 user 和 locale, 当user里的userinfo发生改变时, 每个订阅事件都会获得stateName参数,告诉你user这个state发生了改变,这可以更好的帮助你决定更新哪些模块的状态
  3. 由于2实现的核心是浅比较,因此当stateName为空字符串时,可以判断出是嵌套较深的state发生了改变,这在一定程度上也可以知道到底是哪个state改变了

api

SharedModule

api说明
initShared加载本地shared
overloadShared用于重载SharedModule内的shared实例
getShared获取SharedModule内部的shared实例
subscribe注册订阅事件(可传数组),在state发生改变后会触发此处订阅的事件

shared

api说明
dispatch类似vuex的store.dispatch,用于调用不同模块的action