微前端qiankun+vue

qiankun-vue-test-demo

基于qiankun+vue微前端初實踐

項目地址 :https://github.com/zjzhangjie/qiankun-vue-test-demo.git

基于qiankun+vue微應用初實踐

主應用

main.js

將注冊qiankun的方法封裝到register文件

import Vue from 'vue';
import App from './App.vue';
import router from './router';
import store from './store';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import registerApps from './register/index';
import './common/style/index.less';

Vue.config.productionTip = false;
Vue.use(ElementUI);

let app = null;
app = new Vue({
  el: '#container',
  router,
  store,
  render: h => h(App),
});
// 注冊子應用 registerMicroApps(apps,lifeCycles)
registerApps();

register.js

/**
 *qiankun基礎(chǔ)配置
 * Created by zhangJie on 2020/11/23.
 */
import { registerMicroApps, setDefaultMountApp, start, runAfterFirstMounted, addGlobalUncaughtErrorHandler } from 'qiankun';
import loading from '../progress/index';

import { props, initGlState } from '@/share/';
import { apps, defaultActiveRule } from './apps';
// 定義全局狀態(tài)
initGlState();
const baseurl = `${process.env.BASE_URL}`;
/**
 * 重構(gòu)apps
 */
function filterApps() {
  apps.forEach((item) => {
    item.props = props; // 可選骏令,主應用需要傳遞給微應用的數(shù)據(jù)。
    item.activeRule = genActiveRule(baseurl + item.activeRule);
  });
  return apps;
}
/**
 * 注冊子應用 registerMicroApps(apps,lifeCycles)
 *apps - Array<RegistrableApp> - 必選榔袋,微應用的一些注冊信息
 * 注冊微應用的基礎(chǔ)配置信息凰兑。當瀏覽器 url 發(fā)生變化時,會自動檢查每一個微應用注冊的 activeRule 規(guī)則吏够,符合規(guī)則的應用將會被自動激活。
 */
function registerApps() {
  const _apps = filterApps();
  registerMicroApps(
    _apps,
    {
      beforeLoad: [
        loadApp => {
          console.log('before load', loadApp);
          loading.start();
        },
      ],
      beforeMount: [
        mountApp => {
          console.log('before mount', mountApp);
          loading.done();
        },
      ],
      afterMount: [
        mountApp => {
          console.log('before mount', mountApp);
        },
      ],
      afterUnmount: [
        unloadApp => {
          console.log('after unload', unloadApp);
        },
      ],
    },
  );
  // 設(shè)置默認子應用,與 genActiveRule中的參數(shù)保持一致
  setDefaultMountApp(baseurl + defaultActiveRule);
  // 第一個微應用 mount 后需要調(diào)用的方法播急,比如開啟一些監(jiān)控或者埋點腳本售睹。
  runAfterFirstMounted(() => console.log('開啟監(jiān)控'));
  // 添加全局的未捕獲異常處理器昌妹。
  addGlobalUncaughtErrorHandler(event => console.log(event));
  // 啟動
  start({
    // prefetch: true, // 可選,是否開啟預加載飞崖,默認為 true。
    // sandbox: true, // 可選蒜鸡,是否開啟沙箱牢裳,默認為 true。//從而確保微應用的樣式不會對全局造成影響贰健。
    // singular: true, // 可選伶椿,是否為單實例場景氓侧,單實例指的是同一時間只會渲染一個微應用导狡。默認為 true。
    // fetch: () => {}, // 可選旱捧,自定義的 fetch 方法。
    // getPublicPath: (url) => { console.log(url); },
    // getTemplate: (tpl) => { console.log(tpl); },
    // excludeAssetFilter: (assetUrl) => { console.log(assetUrl); }, // 可選氓癌,指定部分特殊的動態(tài)加載的微應用資源(css/js) 不被qiankun 劫持處理
  });
}
/**
 * 路由監(jiān)聽
 * @param {*} routerPrefix 前綴
 */
function genActiveRule(routerPrefix) {
  return location => location.pathname.startsWith(routerPrefix);
}
export default registerApps;

app.js

抽離app.js 方便配置
import { props } from '@/share/';

export const apps = [
  {
    name: 'children-app-1', // 必選贫橙,微應用的名稱,微應用之間必須確保唯一疲迂。
    entry: '//localhost:8092', // 必選莫湘,微應用的 entry 地址。
    container: '#content', // 子應用掛載的div
    activeRule: 'children-app-1', // 微應用的激活規(guī)則腰池。
    loader: (boolean) => { console.log(`loading狀態(tài)${boolean}`); }, // 可選军洼,loading 狀態(tài)發(fā)生變化時會調(diào)用的方法演怎。
  },
  {
    name: 'children-app-2',
    entry: '//localhost:8093',
    container: '#content', // 子應用掛載的div
    activeRule: 'children-app-2',
  },
];
export const defaultActiveRule = 'children-app-1';
export default {
  apps,
  defaultActiveRule,
};

微應用

main.js

import Vue from 'vue';
import App from './App.vue';
import router from './router';
import './public-path';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import common from './common/index';

Vue.config.productionTip = false;
Vue.use(ElementUI);

/* eslint-disable */
let instance = null;
function render() {
  instance = new Vue({
    router,
    render: h => h(App),
  }).$mount('#app');
}
if (!window.__POWERED_BY_QIANKUN__) {render();}
export async function bootstrap(props) {
  common.setCommonData(props)
}
export async function mount(props) {
  common.initGlState(props)
  render();
}
export async function unmount() {
  instance.$destroy();
}
// 增加 update 鉤子以便主應用手動更新微應用
export async function update(props) {
  common.setCommonData(props)
  common.initGlState(props)
}

common.js

import Vue from 'vue';
/**
 * 接受主應用的傳參
 * @param props 主應用穿的公共數(shù)據(jù)
 */
function setCommonData(props) {
  const { data } = props;
  const { publicPath, commonUi, utils, http } = data;
  Vue.prototype.$utils = utils;
  Vue.prototype.$publicPath = publicPath;
  Vue.prototype.$http = http;
  Vue.use(commonUi);// 注冊公共組件
  return {
    publicPath,
    commonUi,
    utils,
  };
}

/**
 * 設(shè)置微應用全局狀態(tài)
 * @param props 主應用穿的公共數(shù)據(jù)
 */
function initGlState(props) {
  console.log('父應用傳的值', props);
  Vue.prototype.$onGlobalStateChange = props.onGlobalStateChange;
  Vue.prototype.$setGlobalState = props.setGlobalState;
  // 設(shè)置通訊
  props.onGlobalStateChange((state, prev) => {
    // state: 變更后的狀態(tài); prev 變更前的狀態(tài)
    alert('子應用監(jiān)聽到主應用改變啦');
  });
}
export default {
  setCommonData,
  initGlState,
};

打包

將所有的應用打包到一個文件夾里

const fs = require('fs-extra');
const path = require('path');
const outputDir = 'qiankun';
// 拷貝文件
fs.copySync(path.join(process.cwd(), '../children-app-1/children-app-1'), path.join(process.cwd(), outputDir, 'children-app-1'));
fs.copySync(path.join(process.cwd(), '../children-app-2/children-app-2'), path.join(process.cwd(), outputDir, 'children-app-2'));

在package.json的scripts中配置

"build:all": "yarn build:register && yarn build:app1 && yarn build:app2 && yarn copyDir",
"build:register": "vue-cli-service build",
"build:app1": "cd ../children-app-1 && yarn build",
"build:app2": "cd ../children-app-2 && yarn build",
"copyDir": "node ./script/build.js",
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末甘桑,一起剝皮案震驚了整個濱河市歹叮,隨后出現(xiàn)的幾起案子咆耿,更是在濱河造成了極大的恐慌,老刑警劉巖萨螺,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異椭盏,居然都是意外死亡,警方通過查閱死者的電腦和手機糟红,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進店門乌叶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人陈肛,你說我怎么就攤上這事兄裂。” “怎么了晰奖?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵匾南,是天一觀的道長。 經(jīng)常有香客問我蛆楞,道長,這世上最難降的妖魔是什么裆悄? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任臂聋,我火速辦了婚禮,結(jié)果婚禮上孩等,老公的妹妹穿的比我還像新娘肄方。我一直安慰自己冰垄,他們只是感情好权她,可當我...
    茶點故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著写烤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪感局。 梳的紋絲不亂的頭發(fā)上暂衡,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天,我揣著相機與錄音撑毛,去河邊找鬼。 笑死唧领,一個胖子當著我的面吹牛藻雌,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播斩个,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼胯杭,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了受啥?” 一聲冷哼從身側(cè)響起做个,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎滚局,沒想到半個月后居暖,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡藤肢,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年太闺,在試婚紗的時候發(fā)現(xiàn)自己被綠了谤草。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片跟束。...
    茶點故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡莺奸,死狀恐怖丑孩,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情灭贷,我是刑警寧澤温学,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站甚疟,受9級特大地震影響仗岖,放射性物質(zhì)發(fā)生泄漏逃延。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一轧拄、第九天 我趴在偏房一處隱蔽的房頂上張望揽祥。 院中可真熱鬧,春花似錦檩电、人聲如沸拄丰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽料按。三九已至,卻和暖如春卓箫,著一層夾襖步出監(jiān)牢的瞬間载矿,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工烹卒, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留闷盔,地道東北人。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓甫题,卻偏偏與公主長得像馁筐,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子坠非,可洞房花燭夜當晚...
    茶點故事閱讀 44,927評論 2 355