2020年贤斜,你可能需要基于Vue的微服務(wù)架構(gòu)實(shí)踐,在服務(wù)端或客戶端聚合子服務(wù)

快速開(kāi)始

# 拉取代碼
git clone git@github.com:fmfe/vue-genesis-micro.git
# 進(jìn)入項(xiàng)目目錄
cd vue-genesis-micro
# 安裝依賴
npm install
# 開(kāi)發(fā)環(huán)境啟動(dòng)
npm run dev
# 打包生產(chǎn)環(huán)境代碼
npm run build
# 生產(chǎn)環(huán)境運(yùn)行
npm run start

微服務(wù)是什么逛裤?

微服務(wù)是一個(gè)新興的軟件架構(gòu)瘩绒,就是把一個(gè)大型的單個(gè)應(yīng)用程序和服務(wù)拆分為數(shù)十個(gè)的支持微服務(wù)。

為什么需要微服務(wù)带族?

隨著業(yè)務(wù)的發(fā)展锁荔,項(xiàng)目規(guī)模越來(lái)越大,給編譯打包蝙砌、合并的代碼沖突帶來(lái)了巨大的挑戰(zhàn)阳堕,而服務(wù)的拆分可以獲得更快的編譯打包跋理,獨(dú)立部署、增量更新恬总、不同的團(tuán)隊(duì)只需要負(fù)責(zé)自己的服務(wù)前普、更好的支持多端,在大型的項(xiàng)目中壹堰,使用微服務(wù)架構(gòu)可以獲得極大的收益拭卿。

微服務(wù)和微前端的區(qū)別

目前社區(qū)的微前端解決方案,基本上都是基于客戶端去進(jìn)行聚合的思路贱纠,而本項(xiàng)目卻是完全基于后端微服務(wù)的概念而誕生的峻厚,頁(yè)面的聚合既可以在服務(wù)端完成,也可以在客戶端完成谆焊,一切取決于需求惠桃。

項(xiàng)目介紹

本項(xiàng)目基于 Vue 的Genesis開(kāi)發(fā),一個(gè)編寫了三個(gè)例子:

  • ssr-common 公共的頁(yè)面導(dǎo)航
  • ssr-home 首頁(yè)
  • ssr-about 關(guān)于我們
    在學(xué)習(xí)完成本項(xiàng)目后懊渡,你可以搭建屬于自己的微服務(wù)架構(gòu)刽射,并且深入的了解到遠(yuǎn)程組件它是怎么工作的军拟。至此剃执,你可以做到一個(gè)大型應(yīng)用的微服務(wù)拆分下。

關(guān)于 Genesis

Genesis是在FOLLOWME5.0升級(jí)而誕生的一個(gè)項(xiàng)目懈息,它解決了以往架構(gòu)的很多弊端肾档,例如:

  • 公共組件庫(kù)更新,導(dǎo)致同時(shí)十幾個(gè)項(xiàng)目要編譯發(fā)布更新
  • 頁(yè)面和頁(yè)面之間的切換辫继,需要刷新整頁(yè)怒见,無(wú)法做到無(wú)刷新跳轉(zhuǎn)
  • 數(shù)百個(gè)頁(yè)面,如果全部寫到一個(gè)大的項(xiàng)目中做SSR渲染姑宽,只要其中一個(gè)地方出現(xiàn)BUG遣耍,就有可能導(dǎo)致整個(gè)服務(wù)掛掉或者不穩(wěn)定,發(fā)生內(nèi)存泄漏的問(wèn)題時(shí)炮车,也更加難以排查
  • 大量的項(xiàng)目是基于CSR渲染舵变,在國(guó)際化和SEO方面,導(dǎo)致 index.html 頁(yè)面的標(biāo)題瘦穆、關(guān)鍵詞和描述比較難做到國(guó)際化
  • 不同的團(tuán)隊(duì)纪隙,互相交叉開(kāi)發(fā)一個(gè)項(xiàng)目,合并代碼時(shí)扛或,很容易產(chǎn)生各種沖突绵咱,服務(wù)的拆分后,大大的減少了代碼沖突

渲染接口

服務(wù)的拆分后熙兔,那么服務(wù)和服務(wù)之間的調(diào)用是必不可少的悲伶,這里提出了一個(gè)渲染接口的概念艾恼,它可能是這樣子的

// 下面的接口,你可能需要做Nginx反向代理麸锉,來(lái)做到下面的接口
// /api/ssr-服務(wù)名稱/render?url=渲染地址&mode=渲染模式&routerMode=路由模式
const renderModes = ['ssr-html', 'ssr-json', 'csr-html', 'csr-json'];
/**
 * 提供一個(gè)API允許外部渲染
 */
app.use('/api/render', (req, res, next) => {
    // 獲取渲染的地址
    const url = decodeURIComponent(String(req.query.renderUrl));
    // 獲取路由渲染的模式
    const routerMode =
        ['abstract', 'history'].indexOf(String(req.query.routerMode)) > -1
            ? req.query.routerMode
            : 'history';
    // 渲染默認(rèn)
    const mode: any =
        renderModes.indexOf(String(req.query.renderMode)) > -1
            ? String(req.query.renderMode)
            : 'ssr-json';

    renderer
        .render({
            url,
            mode,
            state: {
                routerMode
            }
        })
        .then((r) => {
            res.send(r.data);
        })
        .catch(next);
});

這樣第三方的服務(wù)蒂萎,就可以隨意的調(diào)用這個(gè)服務(wù)的渲染結(jié)果,傳遞需要渲染的地方渲染淮椰,比如Vue五慈、React、或者其它的EJS模板引擎等等主穗。本項(xiàng)目會(huì)使用渲染接口泻拦,來(lái)傳遞給遠(yuǎn)程組件進(jìn)行渲染。

遠(yuǎn)程組件

當(dāng)你需要調(diào)用其它服務(wù)的頁(yè)面渲染時(shí)忽媒,你請(qǐng)求渲染接口争拐,拿到渲染的結(jié)果,傳遞給遠(yuǎn)程組件晦雨,它就會(huì)負(fù)責(zé)幫你渲染該服務(wù)的內(nèi)容架曹。

<template>
    <div>
        <remote-view
            v-for="name in names"
            v-show="ssrname === name"
            :key="name"
            :clientFetch="() => clientFetch(name)"
            :serverFetch="() => serverFetch(name)"
        ></remote-view>
    </div>
</template>
<script lang="ts">
import Vue from 'vue';
import { RemoteView } from '@fmfe/genesis-remote';
import axios from 'axios';

interface Data {
    names: string[];
}
interface Methods {
    clientFetch: (ssrname: string) => Promise<void>;
    serverFetch: (ssrname: string) => Promise<void>;
}
interface Computed {
    ssrname: string;
}

export default Vue.extend<Data, Methods, Computed>({
    name: 'container',
    components: {
        RemoteView
    },
    data() {
        return {
            names: []
        };
    },
    computed: {
        ssrname() {
            return this.$route.meta.ssrname;
        }
    },
    watch: {
        ssrname() {
            if (this.names.indexOf(this.ssrname) > -1) return;
            this.names.push(this.ssrname);
        }
    },
    created() {
        this.names.push(this.ssrname);
    },
    methods: {
        /**
         * 客戶端遠(yuǎn)程調(diào)用時(shí),走 CSR 渲染
         */
        async clientFetch(ssrname: string) {
            const renderUrl = encodeURIComponent(this.$route.fullPath);
            const res = await axios.get(
                `http://localhost:3000/api/${ssrname}/render`,
                {
                    params: {
                        routerMode: 'history',
                        renderMode: 'csr-json',
                        renderUrl
                    }
                }
            );
            if (res.status === 200) {
                return res.data;
            }
            return null;
        },
        /**
         * 服務(wù)端遠(yuǎn)程調(diào)用時(shí)闹瞧,走 SSR渲染
         */
        async serverFetch(ssrname: string) {
            const renderUrl = encodeURIComponent(this.$route.fullPath);
            const res = await axios.get(
                `http://localhost:3000/api/${ssrname}/render`,
                {
                    params: {
                        routerMode: 'history',
                        renderMode: 'ssr-json',
                        renderUrl
                    }
                }
            );
            if (res.status === 200) {
                return res.data;
            }
            return null;
        }
    }
});
</script>

目錄說(shuō)明

.
├── .vscode
│   ├── settings.json                         vscode的配置
├── examples                                  服務(wù)拆分的例子
│   ├── ssr-about                             關(guān)于我們服務(wù)
│   |   ├── src                                 Vue源碼目錄
│   |   |   ├── views                           頁(yè)面目錄
│   |   |   |   ├── about-help.vue              幫助中心頁(yè)面
│   |   |   |   └── about-us.vue                關(guān)于我們頁(yè)面
│   |   |   ├── app.vue                         頁(yè)面入口文件绑雄,公共導(dǎo)航
│   |   |   ├── entry-client.ts                 客戶端入口文件
│   |   |   ├── entry-server.ts                 服務(wù)端入口文件
│   |   |   ├── router.ts                       路由配置文件
│   |   |   └── shims-vue.d.ts                  .vue文件的TS聲明
│   |   ├──   genesis.build.ts                  當(dāng)前服務(wù)生產(chǎn)環(huán)境構(gòu)建入口
│   |   ├──   genesis.dev.ts                    當(dāng)前服務(wù)開(kāi)發(fā)環(huán)境入口
│   |   ├──   genesis.prod.ts                   當(dāng)前服務(wù)生產(chǎn)環(huán)境入口
│   |   └──   genesis.ts                        當(dāng)前服務(wù)通用的服務(wù)端邏輯
│   ├── ssr-common                            基礎(chǔ)的頁(yè)面聚合服務(wù),包含公共導(dǎo)航
│   |   ├── src                                 Vue源碼目錄
│   |   |   ├── views                           頁(yè)面目錄
│   |   |   |   ├── about-help.vue              幫助中心頁(yè)面
│   |   |   |   └── about-us.vue                關(guān)于我們頁(yè)面
│   |   |   ├── app.vue                         頁(yè)面入口文件奥邮,公共導(dǎo)航
│   |   |   ├── container.vue                   子應(yīng)用的容器
│   |   |   ├── entry-client.ts                 客戶端入口文件
│   |   |   ├── entry-server.ts                 服務(wù)端入口文件
│   |   |   ├── router.ts                       路由配置文件
│   |   |   └── shims-vue.d.ts                  .vue文件的TS聲明
│   |   ├──   genesis.build.ts                  當(dāng)前服務(wù)生產(chǎn)環(huán)境構(gòu)建入口
│   |   ├──   genesis.dev.ts                    當(dāng)前服務(wù)開(kāi)發(fā)環(huán)境入口
│   |   ├──   genesis.prod.ts                   當(dāng)前服務(wù)生產(chǎn)環(huán)境入口
│   |   └──   genesis.ts                        當(dāng)前服務(wù)通用的服務(wù)端邏輯
│   ├── ssr-home                              首頁(yè)的服務(wù)
│   |   ├── src                                 Vue源碼目錄
│   |   |   ├── views                           頁(yè)面目錄
│   |   |   |   └── home.vue                    首頁(yè)頁(yè)面
│   |   |   ├── app.vue                         頁(yè)面入口文件万牺,公共導(dǎo)航
│   |   |   ├── container.vue                   子應(yīng)用的容器
│   |   |   ├── entry-client.ts                 客戶端入口文件
│   |   |   ├── entry-server.ts                 服務(wù)端入口文件
│   |   |   ├── router.ts                       路由配置文件
│   |   |   └── shims-vue.d.ts                  .vue文件的TS聲明
│   |   ├──   genesis.build.ts                  當(dāng)前服務(wù)生產(chǎn)環(huán)境構(gòu)建入口
│   |   ├──   genesis.dev.ts                    當(dāng)前服務(wù)開(kāi)發(fā)環(huán)境入口
│   |   ├──   genesis.prod.ts                   當(dāng)前服務(wù)生產(chǎn)環(huán)境入口
│   |   └──   genesis.ts                        當(dāng)前服務(wù)通用的服務(wù)端邏輯
|   ├── .editorconfig                         編輯器配置
|   ├── .eslintignore                         eslint忽略配置
|   ├── .eslintrc.js                          eslint配置
|   ├── .gitignore                            git忽略配置
|   ├── .stylelintignore                      stylelint忽略配置
|   ├── genesis.build.ts                      所有服務(wù)生產(chǎn)構(gòu)建
|   ├── genesis.dev.ts                        所有服務(wù)開(kāi)發(fā)環(huán)境啟動(dòng)
|   ├── genesis.prod.ts                       所有服務(wù)生產(chǎn)環(huán)境入口
|   ├── stylelint.config.js                   stylelint配置
|   └── tsconfig.json                         TS的配置
│ 
└── package.json

注意:本項(xiàng)目是為了演示,才把幾個(gè)服務(wù)全部放到一個(gè)倉(cāng)庫(kù)中洽腺,在實(shí)際的應(yīng)用中脚粟,每一個(gè)服務(wù),都應(yīng)該放到獨(dú)立的git倉(cāng)庫(kù)中蘸朋。

最后

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市堕担,隨后出現(xiàn)的幾起案子已慢,更是在濱河造成了極大的恐慌,老刑警劉巖霹购,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件佑惠,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)膜楷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門旭咽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人赌厅,你說(shuō)我怎么就攤上這事穷绵。” “怎么了特愿?”我有些...
    開(kāi)封第一講書人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵仲墨,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我揍障,道長(zhǎng)目养,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任毒嫡,我火速辦了婚禮癌蚁,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘兜畸。我一直安慰自己努释,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布咬摇。 她就那樣靜靜地躺著伐蒂,像睡著了一般。 火紅的嫁衣襯著肌膚如雪菲嘴。 梳的紋絲不亂的頭發(fā)上饿自,一...
    開(kāi)封第一講書人閱讀 49,166評(píng)論 1 284
  • 那天汰翠,我揣著相機(jī)與錄音龄坪,去河邊找鬼。 笑死复唤,一個(gè)胖子當(dāng)著我的面吹牛健田,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播佛纫,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼妓局,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了呈宇?” 一聲冷哼從身側(cè)響起好爬,我...
    開(kāi)封第一講書人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎甥啄,沒(méi)想到半個(gè)月后存炮,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年穆桂,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了宫盔。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡享完,死狀恐怖灼芭,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情般又,我是刑警寧澤彼绷,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站茴迁,受9級(jí)特大地震影響苛预,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜笋熬,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一热某、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧胳螟,春花似錦昔馋、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至嘉竟,卻和暖如春邦危,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背舍扰。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工倦蚪, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人边苹。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓陵且,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親个束。 傳聞我的和親對(duì)象是個(gè)殘疾皇子慕购,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344