├── .gitignore ├── .huskyrc ├── .fatherrc.js ├── jest.config.js ├── tsconfig.json ├── LICENSE ├── package.json ├── src └── index.ts ├── README.md └── test.ts /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | -------------------------------------------------------------------------------- /.huskyrc: -------------------------------------------------------------------------------- 1 | { 2 | "hooks": { 3 | "pre-commit": "npm run test" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.fatherrc.js: -------------------------------------------------------------------------------- 1 | export default { 2 | entry: "./src/index.ts", 3 | file: "vuex-micro-frontends-plugin", 4 | esm: true, 5 | umd: true 6 | }; 7 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | transform: { 3 | "^.+\\.tsx?$": "ts-jest" 4 | }, 5 | testRegex: "test.ts", 6 | moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"] 7 | }; 8 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "moduleResolution": "node", 5 | "module": "es2015", 6 | "declaration": true, 7 | "declarationMap": false, 8 | "sourceMap": false, 9 | "outDir": "./dist", 10 | "strict": true, 11 | "esModuleInterop": true, 12 | "forceConsistentCasingInFileNames": true 13 | }, 14 | "include": ["src/**/*"] 15 | } 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 张超杰 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE.m 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vuex-micro-frontends", 3 | "description": "微前端 vuex 父子通信解决方案. vue micro frontends communication solution.", 4 | "version": "1.0.0", 5 | "license": "MIT", 6 | "author": "dream2023 <1098626505@qq.com>", 7 | "keywords": [ 8 | "vue", 9 | "vuex", 10 | "plugin", 11 | "micro frontends", 12 | "vue micro frontends" 13 | ], 14 | "repository": "dream2023/vuex-micro-frontends", 15 | "scripts": { 16 | "build": "father-build", 17 | "test": "jest --env=jsdom", 18 | "prepublish": "yarn build" 19 | }, 20 | "source": "src/index.ts", 21 | "main": "./dist/vuex-micro-frontends.umd.min.js", 22 | "module": "./dist/vuex-micro-frontends.mjs", 23 | "unpkg": "./dist/vuex-micro-frontends.umd.min.js", 24 | "type": "./dist/index.d.ts", 25 | "files": [ 26 | "dist", 27 | "src" 28 | ], 29 | "dependencies": { 30 | "@ice/stark-data": "^0.1.2" 31 | }, 32 | "devDependencies": { 33 | "@types/jest": "^25.1.4", 34 | "father-build": "^1.17.2", 35 | "husky": "^4.2.3", 36 | "jest": "^25.2.4", 37 | "ts-jest": "^25.3.0", 38 | "typescript": "^3.8.3", 39 | "vue": "^2.6.11", 40 | "vuex": "^3.1.3" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { Plugin } from "vuex"; 2 | import { store as iceStore } from "@ice/stark-data"; 3 | 4 | const VUEX_DATA_KEY: string = "vuex"; 5 | 6 | interface AnyObj { 7 | [index: string]: any; 8 | } 9 | 10 | // 捡取数据 11 | export function pick(obj: AnyObj, keys?: string[]) { 12 | // 如果keys未传递, 则直接返回 obj 13 | if (!keys) return obj; 14 | 15 | // 如果传递, 则进行挑选 16 | return Object.keys(obj).reduce((acc: AnyObj, key) => { 17 | if (keys.includes(key)) { 18 | acc[key] = obj[key]; 19 | } 20 | return acc; 21 | }, {}); 22 | } 23 | 24 | // 触发数据改变 25 | export function send(keys?: string[]): Plugin { 26 | return store => { 27 | store.subscribe((mutation, state) => { 28 | iceStore.set(VUEX_DATA_KEY, pick(state, keys)); 29 | }); 30 | }; 31 | } 32 | 33 | // 监听数据改变 34 | export function receive(keys?: string[]): Plugin { 35 | return store => { 36 | // 监听变化, 设置数据 37 | iceStore.on( 38 | VUEX_DATA_KEY, 39 | (data: AnyObj) => { 40 | data = pick(data, keys); 41 | Object.keys(data).forEach((key: string) => { 42 | store.state[key] = data[key]; 43 | }); 44 | }, 45 | true 46 | ); 47 | }; 48 | } 49 | 50 | export default { 51 | send, 52 | receive 53 | }; 54 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vuex-micro-frontends 2 | 3 | ![NPM](https://img.shields.io/npm/l/vuex-micro-frontends) 4 | ![npm](https://img.shields.io/npm/v/vuex-micro-frontends) 5 | ![npm bundle size](https://img.shields.io/bundlephobia/min/vuex-micro-frontends) 6 | ![David](https://img.shields.io/david/dev/dream2023/vuex-micro-frontends) 7 | ![npm](https://img.shields.io/npm/dt/vuex-micro-frontends) 8 | 9 | 微前端 vuex 父子通信解决方案. vue micro frontends communication solution. 10 | 11 | ## 介绍 12 | 13 | 我们知道微前端父子通信方式有很多, 例如 `location`、`Cookie`、`LocalStorage`、`window`, 但是他们都有一个通病, 即无法实时监测变化, 例如换肤或者多语言切换, 想要应用到子项目, 必须进行页面的刷新, 然后才能通知到, 而尽量少的改动原项目的原则, 很多`Vue`项目都是基于`vuex`进行全局数据的共享, 所以才诞生了`vuex-micro-frontends` 14 | 15 | ## 特点 16 | 17 | - 父子传递、实时变化 18 | - 仅 1kb 19 | 20 | ## Installation 21 | 22 | ```bash 23 | yarn add vuex-micro-frontends # npm install vuex-micro-frontends 24 | ``` 25 | 26 | ## Usage 27 | 28 | ```js 29 | // master, send state data 主应用, 负责发送数据 30 | import vuexMicroFrontends from "vuex-micro-frontends"; 31 | 32 | const store = new Vuex.Store({ 33 | state: { 34 | name: "jack", 35 | age: 10, 36 | gender: "men" 37 | }, 38 | plugins: [vuexMicroFrontends.send()] // 默认下发全部数据 39 | // plugins: [vuexMicroFrontends.send(['name', 'age'])] // 仅向子应用下发 name 和 age 数据 40 | }); 41 | ``` 42 | 43 | ```js 44 | // slave, receive master state 子应用, 负责接受数据 45 | import vuexMicroFrontends from "vuex-micro-frontends"; 46 | 47 | const store = new Vuex.Store({ 48 | state: { 49 | name: "", 50 | age: null, 51 | address: "" 52 | }, 53 | plugins: [vuexMicroFrontends.receive()] // 默认接受全部父组件传递的数据 54 | // plugins: [vuexMicroFrontends.receive(['name'])], // 仅接受 name 字段数据 55 | }); 56 | ``` 57 | -------------------------------------------------------------------------------- /test.ts: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import Vuex from "vuex"; 3 | import { pick, send, receive } from "./src/index"; 4 | 5 | Vue.config.productionTip = false; 6 | Vue.use(Vuex); 7 | 8 | it("pick function", () => { 9 | const obj = { name: "zhang", age: 10 }; 10 | 11 | // 不传参数情况 12 | expect(pick(obj)).toStrictEqual({ name: "zhang", age: 10 }); 13 | // 传参数的情况 14 | expect(pick(obj, ["name"])).toStrictEqual({ name: "zhang" }); 15 | }); 16 | 17 | it("send & receive without keys", done => { 18 | const masterStore = new Vuex.Store({ 19 | state: { name: "zhang", age: 10 }, 20 | mutations: { 21 | updateAge(state) { 22 | state.age += 1; 23 | } 24 | }, 25 | plugins: [send()] 26 | }); 27 | 28 | masterStore.commit("updateAge"); 29 | 30 | setTimeout(() => { 31 | const slaveStore = new Vuex.Store({ 32 | state: { 33 | age: null, 34 | name: "" 35 | }, 36 | plugins: [receive()] 37 | }); 38 | expect(slaveStore.state.name).toBe("zhang"); 39 | expect(slaveStore.state.age).toBe(11); 40 | done(); 41 | }); 42 | }); 43 | 44 | it("send & receive with keys", done => { 45 | const masterStore = new Vuex.Store({ 46 | state: { name: "zhang", age: 10, sex: "man" }, 47 | mutations: { 48 | updateAge(state) { 49 | state.age += 1; 50 | } 51 | }, 52 | plugins: [send(["name", "sex"])] 53 | }); 54 | 55 | masterStore.commit("updateAge"); 56 | 57 | setTimeout(() => { 58 | const slaveStore = new Vuex.Store({ 59 | state: { 60 | age: null, 61 | name: "", 62 | sex: "" 63 | }, 64 | plugins: [receive(["name"])] 65 | }); 66 | expect(slaveStore.state.name).toBe("zhang"); 67 | expect(slaveStore.state.age).toBe(null); 68 | expect(slaveStore.state.sex).toBe(""); 69 | done(); 70 | }); 71 | }); 72 | --------------------------------------------------------------------------------