Vue + qiankun 快速實(shí)現(xiàn)前端微服務(wù)

本文介紹 Vue 項(xiàng)目如何實(shí)現(xiàn)前端微服務(wù)

一、前言

什么是微前端

Techniques, strategies and recipes for building a modern web app with multiple teams that can ship features independently. -- Micro Frontends

微前端是一種多個(gè)團(tuán)隊(duì)通過(guò)獨(dú)立發(fā)布功能的方式來(lái)共同構(gòu)建現(xiàn)代化 web 應(yīng)用的技術(shù)手段及方法策略。

更多關(guān)于微前端的相關(guān)介紹,推薦大家可以去看這幾篇文章:

qiankun

qiankun 是螞蟻金服開(kāi)源的一套完整的微前端解決方案。具體描述可查看 文檔Github

下面將通過(guò)一個(gè)微服務(wù)Demo 介紹 Vue 項(xiàng)目如何接入 qiankun,代碼地址:micro-front-vue

二、配置主應(yīng)用

  1. 使用 vue cli 快速創(chuàng)建主應(yīng)用;
  2. 安裝 qiankun
$ yarn add qiankun # 或者 npm i qiankun -S
  1. 調(diào)整主應(yīng)用 main.js 文件:具體如下:
import Vue from "vue"
import App from "./App.vue"
import router from "./router"

import { registerMicroApps, setDefaultMountApp, start } from "qiankun"
Vue.config.productionTip = false
let app = null;
/**
 * 渲染函數(shù)
 * appContent 子應(yīng)用html內(nèi)容
 * loading 子應(yīng)用加載效果,可選
 */
function render({ appContent, loading } = {}) {
    if (!app) {
        app = new Vue({
            el: "#container",
            router,
            data() {
                return {
                    content: appContent,
                    loading
                };
            },
            render(h) {
                return h(App, {
                    props: {
                        content: this.content,
                        loading: this.loading
                    }
                });
            }
        });
    } else {
        app.content = appContent;
        app.loading = loading;
    }
}

/**
 * 路由監(jiān)聽(tīng)
 * @param {*} routerPrefix 前綴
 */
function genActiveRule(routerPrefix) {
    return location => location.pathname.startsWith(routerPrefix);
}

function initApp() {
    render({ appContent: '', loading: true });
}

initApp();

// 傳入子應(yīng)用的數(shù)據(jù)
let msg = {
    data: {
        auth: false
    },
    fns: [
        {
            name: "_LOGIN",
            _LOGIN(data) {
                console.log(`父應(yīng)用返回信息${data}`);
            }
        }
    ]
};
// 注冊(cè)子應(yīng)用
registerMicroApps(
    [
        {
            name: "sub-app-1",
            entry: "http://localhost:8091",
            render,
            activeRule: genActiveRule("/app1"),
            props: msg
        },
        {
            name: "sub-app-2",
            entry: "http://localhost:8092",
            render,
            activeRule: genActiveRule("/app2"),
        }
    ],
    {
        beforeLoad: [
            app => {
                console.log("before load", app);
            }
        ], // 掛載前回調(diào)
        beforeMount: [
            app => {
                console.log("before mount", app);
            }
        ], // 掛載后回調(diào)
        afterUnmount: [
            app => {
                console.log("after unload", app);
            }
        ] // 卸載后回調(diào)
    }
);

// 設(shè)置默認(rèn)子應(yīng)用,與 genActiveRule中的參數(shù)保持一致
setDefaultMountApp("/app1");

// 啟動(dòng)
start();

  1. 修改主應(yīng)用 index.html 中綁定的 id ,需與 el 綁定 dom 為一致;
  2. 調(diào)整 App.vue 文件,增加渲染子應(yīng)用的盒子:
<template>
  <div id="main-root">
    <!-- loading -->
    <div v-if="loading">loading</div>
    <!-- 子應(yīng)用盒子 -->
    <div id="root-view" class="app-view-box" v-html="content"></div>
  </div>
</template>

<script>
export default {
  name: "App",
  props: {
    loading: Boolean,
    content: String
  }
};
</script>

  1. 創(chuàng)建 vue.config.js 文件,設(shè)置 port :
module.exports = {
    devServer: {
        port: 8090
    }
}

三、配置子應(yīng)用

  1. 在主應(yīng)用同一級(jí)目錄下快速創(chuàng)建子應(yīng)用,子應(yīng)用無(wú)需安裝 qiankun
  2. 配置子應(yīng)用 main.js:
import Vue from 'vue';
import VueRouter from 'vue-router';
import App from './App.vue';
import routes from './router';
import './public-path';

Vue.config.productionTip = false;

let router = null;
let instance = null;

function render() {
    router = new VueRouter({
        base: window.__POWERED_BY_QIANKUN__ ? '/app1' : '/',
        mode: 'history',
        routes,
    });

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

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

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

export async function mount(props) {
    console.log('props from main app', props);
    render();
}

export async function unmount() {
    instance.$destroy();
    instance = null;
    router = null;
}
  1. 配置 vue.config.js
const path = require('path');
const { name } = require('./package');

function resolve(dir) {
    return path.join(__dirname, dir);
}

const port = 8091; // dev port

module.exports = {
  /**
   * You will need to set publicPath if you plan to deploy your site under a sub path,
   * for example GitHub Pages. If you plan to deploy your site to https://foo.github.io/bar/,
   * then publicPath should be set to "/bar/".
   * In most cases please use '/' !!!
   * Detail: https://cli.vuejs.org/config/#publicpath
   */
    outputDir: 'dist',
    assetsDir: 'static',
    filenameHashing: true,
    // tweak internal webpack configuration.
    // see https://github.com/vuejs/vue-cli/blob/dev/docs/webpack.md
    devServer: {
        // host: '0.0.0.0',
        hot: true,
        disableHostCheck: true,
        port,
        overlay: {
            warnings: false,
            errors: true,
        },
        headers: {
            'Access-Control-Allow-Origin': '*',
        },
    },
    // 自定義webpack配置
    configureWebpack: {
        resolve: {
            alias: {
                '@': resolve('src'),
            },
        },
        output: {
            // 把子應(yīng)用打包成 umd 庫(kù)格式
            library: `${name}-[name]`,
            libraryTarget: 'umd',
            jsonpFunction: `webpackJsonp_${name}`,
        },
    },
};

其中有個(gè)需要注意的點(diǎn):

  1. 子應(yīng)用必須支持跨域:由于 qiankun 是通過(guò) fetch 去獲取子應(yīng)用的引入的靜態(tài)資源的,所以必須要求這些靜態(tài)資源支持跨域;
  2. 使用 webpack 靜態(tài) publicPath 配置:可以通過(guò)兩種方式設(shè)置,一種是直接在 mian.js 中引入 public-path.js 文件,一種是在開(kāi)發(fā)環(huán)境直接修改 vue.config.js:
{
  output: {
    publicPath: `//localhost:${port}`;
  }
}

public-path.js 內(nèi)容如下:

if (window.__POWERED_BY_QIANKUN__) {
  // eslint-disable-next-line no-undef
  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__
}

至此,Vue 項(xiàng)目的前端微服務(wù)已經(jīng)簡(jiǎn)單完成了。

但是在實(shí)際的開(kāi)發(fā)過(guò)程中,并非如此簡(jiǎn)單,同時(shí)還存在應(yīng)用間跳轉(zhuǎn)、應(yīng)用間通信等問(wèn)題。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,825評(píng)論 6 546
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,814評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 178,980評(píng)論 0 384
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 64,064評(píng)論 1 319
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,779評(píng)論 6 414
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 56,109評(píng)論 1 330
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,099評(píng)論 3 450
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 43,287評(píng)論 0 291
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,799評(píng)論 1 338
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,515評(píng)論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,750評(píng)論 1 375
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,221評(píng)論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,933評(píng)論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 35,327評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 36,667評(píng)論 1 296
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,492評(píng)論 3 400
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,703評(píng)論 2 380

推薦閱讀更多精彩內(nèi)容

  • 主題:微服務(wù)的安全認(rèn)證 一、認(rèn)識(shí)微服務(wù) 1.1 微服務(wù)的出道 軟件架構(gòu)(Software Architecture...
    suxin1932閱讀 1,995評(píng)論 0 0
  • 小編推薦: Fundebug提供JS、微信小程序、微信小游戲,Node.js和Java錯(cuò)誤監(jiān)控。真的是一個(gè)很好用的...
    Fundebug閱讀 3,870評(píng)論 0 4
  • 在求學(xué)的階段,為了練習(xí)自己的自學(xué)能力,曾經(jīng)做過(guò)一個(gè)測(cè)試,將一本書(shū)籍前前后后一共讀了六次,在讀完之后有什么收獲呢? ...
    緊箍咒下的人影閱讀 621評(píng)論 0 0
  • 接受不可以改變的。 改變可以改變的。 以感恩之心感激擁有的一切。 以平常之心接受已發(fā)生的事。 z?j
    女王殿下1884閱讀 126評(píng)論 0 0
  • 天藍(lán)久未雨 夜深久未眠 思念久未見(jiàn) 花開(kāi)只一夏 難再紅一秋 我從未愛(ài)過(guò)這江湖 只愛(ài)著這江湖的顏色
    一毫米閱讀 166評(píng)論 2 3