2020年,你可能須要基於Vue的微服務架構實踐,在服務端或客戶端聚合子服務

快速開始

# 拉取代碼
git clone git@github.com:fmfe/vue-genesis-micro.git
# 進入項目目錄
cd vue-genesis-micro
# 安裝依賴
npm install
# 開發環境啓動
npm run dev
# 打包生產環境代碼
npm run build
# 生產環境運行
npm run start
複製代碼

微服務是什麼?

微服務是一個新興的軟件架構,就是把一個大型的單個應用程序和服務拆分爲數十個的支持微服務。html

爲何須要微服務?

隨着業務的發展,項目規模愈來愈大,給編譯打包、合併的代碼衝突帶來了巨大的挑戰,而服務的拆分能夠得到更快的編譯打包,獨立部署、增量更新、不一樣的團隊只須要負責本身的服務、更好的支持多端,在大型的項目中,使用微服務架構能夠得到極大的收益。前端

微服務和微前端的區別

目前社區的微前端解決方案,基本上都是基於客戶端去進行聚合的思路,而本項目倒是徹底基於後端微服務的概念而誕生的,頁面的聚合既能夠在服務端完成,也能夠在客戶端完成,一切取決於需求。vue

項目介紹

本項目基於 Vue 的Genesis開發,一個編寫了三個例子:ios

  • ssr-common 公共的頁面導航
  • ssr-home 首頁
  • ssr-about 關於咱們
    在學習完成本項目後,你能夠搭建屬於本身的微服務架構,而且深刻的瞭解到遠程組件它是怎麼工做的。至此,你能夠作到一個大型應用的微服務拆分下。

關於 Genesis

Genesis是在FOLLOWME5.0升級而誕生的一個項目,它解決了以往架構的不少弊端,例如:git

  • 公共組件庫更新,致使同時十幾個項目要編譯發佈更新
  • 頁面和頁面之間的切換,須要刷新整頁,沒法作到無刷新跳轉
  • 數百個頁面,若是所有寫到一個大的項目中作SSR渲染,只要其中一個地方出現BUG,就有可能致使整個服務掛掉或者不穩定,發生內存泄漏的問題時,也更加難以排查
  • 大量的項目是基於CSR渲染,在國際化和SEO方面,致使 index.html 頁面的標題、關鍵詞和描述比較難作到國際化
  • 不一樣的團隊,互相交叉開發一個項目,合併代碼時,很容易產生各類衝突,服務的拆分後,大大的減小了代碼衝突

渲染接口

服務的拆分後,那麼服務和服務之間的調用是必不可少的,這裏提出了一個渲染接口的概念,它多是這樣子的github

// 下面的接口,你可能須要作Nginx反向代理,來作到下面的接口
// /api/ssr-服務名稱/render?url=渲染地址&mode=渲染模式&routerMode=路由模式
const renderModes = ['ssr-html', 'ssr-json', 'csr-html', 'csr-json'];
/** * 提供一個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';
    // 渲染默認
    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);
});
複製代碼

這樣第三方的服務,就能夠隨意的調用這個服務的渲染結果,傳遞須要渲染的地方渲染,好比Vue、React、或者其它的EJS模板引擎等等。本項目會使用渲染接口,來傳遞給遠程組件進行渲染。npm

遠程組件

當你須要調用其它服務的頁面渲染時,你請求渲染接口,拿到渲染的結果,傳遞給遠程組件,它就會負責幫你渲染該服務的內容。json

<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: {
        /**
         * 客戶端遠程調用時,走 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;
        },
        /**
         * 服務端遠程調用時,走 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>

複製代碼

目錄說明

.
├── .vscode
│   ├── settings.json                         vscode的配置
├── examples                                  服務拆分的例子
│   ├── ssr-about                             關於咱們服務
│   |   ├── src                                 Vue源碼目錄
│   |   |   ├── views                           頁面目錄
│   |   |   |   ├── about-help.vue              幫助中心頁面
│   |   |   |   └── about-us.vue                關於咱們頁面
│   |   |   ├── app.vue                         頁面入口文件,公共導航
│   |   |   ├── entry-client.ts                 客戶端入口文件
│   |   |   ├── entry-server.ts                 服務端入口文件
│   |   |   ├── router.ts                       路由配置文件
│   |   |   └── shims-vue.d.ts                  .vue文件的TS聲明
│   |   ├──   genesis.build.ts                  當前服務生產環境構建入口
│   |   ├──   genesis.dev.ts                    當前服務開發環境入口
│   |   ├──   genesis.prod.ts                   當前服務生產環境入口
│   |   └──   genesis.ts                        當前服務通用的服務端邏輯
│   ├── ssr-common                            基礎的頁面聚合服務,包含公共導航
│   |   ├── src                                 Vue源碼目錄
│   |   |   ├── views                           頁面目錄
│   |   |   |   ├── about-help.vue              幫助中心頁面
│   |   |   |   └── about-us.vue                關於咱們頁面
│   |   |   ├── app.vue                         頁面入口文件,公共導航
│   |   |   ├── container.vue                   子應用的容器
│   |   |   ├── entry-client.ts                 客戶端入口文件
│   |   |   ├── entry-server.ts                 服務端入口文件
│   |   |   ├── router.ts                       路由配置文件
│   |   |   └── shims-vue.d.ts                  .vue文件的TS聲明
│   |   ├──   genesis.build.ts                  當前服務生產環境構建入口
│   |   ├──   genesis.dev.ts                    當前服務開發環境入口
│   |   ├──   genesis.prod.ts                   當前服務生產環境入口
│   |   └──   genesis.ts                        當前服務通用的服務端邏輯
│   ├── ssr-home                              首頁的服務
│   |   ├── src                                 Vue源碼目錄
│   |   |   ├── views                           頁面目錄
│   |   |   |   └── home.vue                    首頁頁面
│   |   |   ├── app.vue                         頁面入口文件,公共導航
│   |   |   ├── container.vue                   子應用的容器
│   |   |   ├── entry-client.ts                 客戶端入口文件
│   |   |   ├── entry-server.ts                 服務端入口文件
│   |   |   ├── router.ts                       路由配置文件
│   |   |   └── shims-vue.d.ts                  .vue文件的TS聲明
│   |   ├──   genesis.build.ts                  當前服務生產環境構建入口
│   |   ├──   genesis.dev.ts                    當前服務開發環境入口
│   |   ├──   genesis.prod.ts                   當前服務生產環境入口
│   |   └──   genesis.ts                        當前服務通用的服務端邏輯
|   ├── .editorconfig                         編輯器配置
|   ├── .eslintignore                         eslint忽略配置
|   ├── .eslintrc.js                          eslint配置
|   ├── .gitignore                            git忽略配置
|   ├── .stylelintignore                      stylelint忽略配置
|   ├── genesis.build.ts                      全部服務生產構建
|   ├── genesis.dev.ts                        全部服務開發環境啓動
|   ├── genesis.prod.ts                       全部服務生產環境入口
|   ├── stylelint.config.js                   stylelint配置
|   └── tsconfig.json                         TS的配置
│ 
└── package.json
複製代碼

注意:本項目是爲了演示,才把幾個服務所有放到一個倉庫中,在實際的應用中,每個服務,都應該放到獨立的git倉庫中。axios

最後

相關文章
相關標籤/搜索