使用VueGenesis从零开始前端微服务开发(一)开发
1 引言
提到微服务架构,我们会想到Java或者C#,但是真正的微服务应该如本文所述一样,每个服务拥有独立的展示层,独立的数据存储。相互之间绝对的无干扰。无论是前端还是后端。都是独立开发,独立部署,独立运行。
本文源代码:https://gitee.com/bitem/vue-genesis-micro-front-demo.git
微服务大致结构图可能是这样的:
或者这样的:
本文需要讲的是如何做一个如下图所示的微服务架构(这个图片是网上下载的,来源忘记了):
这个图可以看到每个API都有一个展示服务,即将前端拆分为一个个前端服务。每个前端服务拥有独立开发,独立部署,独立运行的能力,相互之间互不干扰,一个服务挂掉不会影响其他服务的正常运行。加上负载均衡配合,同一个服务还可以部署多个实例,形成分布式集群的解决方案。这里就不说怎么去负载均衡部署集群解决方案,只说明如何开始一个前端微服务的开发和部署。
2 工具说明
开发工具:VS Code(其他工具肯定也可以,只是我最近发现VS Code好牛逼的样子,才用VS Code)
开发语言:Vue(版本:2.7.13,为啥用特定版本后面会介绍,另外Vue Genesis只支持Vue2)
依赖框架:Vue Genesis(版本:1.0.13,为啥不用最新版2.x,因为新版本2.x官方都还没完成,暂时懒得去看)。Vue Genesis因为Followme 5.0 而诞生,官方文档和资料少的可怜。甚至连如何部署都没有,只能自己研究怎么部署,作者觉得部署太简单了不屑于写说明,但是对于小白来说,还是需要的。(使用Docker确实省了很多事情)。
3 准备开始
3.1 环境准备
确保你的VS Code安装好,并且安装了以下插件:
3.2 新建文件夹
新建项目根目录e-mes-ui
进入e-mes-ui,新建四个文件夹:e-mes-main、e-mes-home、e-mes-share、e-mes-about,分别为主服务(即入口服务或者叫聚合服务,主页服务、公共组件服务、关于我们服务)。
3.3 工作原理
章节4中主要说明部分重要的代码和配置,详细说明请直接查看源码。本节主要说明Vue Genesis的工作原理。摘抄自Vue Genesis官方文档。
在 Vue Genesis 中,核心的就是渲染器,它提供了最基础渲染能力,有了它,你可以实现微前端、微服务、远程组件、首屏渲染,甚至可以和 React、EJS 等配合使用。
它可以和怎样的你协作?
● 如果你是传统的后端渲染的,需要做SEO,但是你希望在部分布局,部分页面引入 Vue,那么 renderer.renderJson() 足以,将渲染结果传递给后端渲染的模板引擎中即可。
● 如果你是中后台系统,业务系统全部集中在一个项目,你希望可以按照业务进行服务的拆分,那么 <remote-view :fetch="fetch" /> 足以
● 如果你是 CSR 渲染的项目,那么 renderer.renderHtml({ mode: ‘csr-html’ }) 足以
● 如果你是 SSR 渲染的项目,那么 renderer.renderHtml({ mode: ‘ssr-html’ }) 足以
如果你想做微前端、微服务、那么渲染器 天生就具备了这样的能力,你可以把它当成一个工具函数使用,你可以通过 HTTP 、 RPC 等等各种协议访问到你的服务,然后使用它进行渲染。
官方GitHub地址:https://github.com/fmfe/genesis
4 开发
4.1 开发配置文件
文件目录如下,具体配置见源码(四个微服务项目的文件结构都是这样,少量区别下面已经做了说明)。
├── .vscode vscode配置文件
├── src 源代码目录
│ ├── component 组件目录
│ | └── ***.vue 组件
│ ├── view 页面目录
│ | └── ***.vue 页面
│ ├── app.vue 页面入口文件
│ ├── container.vue 子应用容器(子应用无该文件)
│ ├── entry-client.ts 客户端入口文件
│ ├── entry-server.ts 服务端入口文件
│ ├── router.ts 路由配置文件
│ └── shims-vue.d.ts .vue文件的TS声明
├── startup 编译执行脚本目录
│ ├── genesis.ts 启动执行脚本
│ ├── genesis.build.ts 生产构建脚本
│ ├── genesis.dev.ts 开发环境启动脚本
│ └── genesis.prod.ts 生产环境启动脚本
├── .editorconfig 编辑器配置
├── .eslintignore eslint忽略配置
├── .eslintrc.js eslint配置
├── .gitignore git忽略配置
├── .stylelintignore stylelint忽略配置
├── package.json 包配置文件
├── README.md 说明文档
├── stylelint.config.js stylelint配置
└── tsconfig.json TS的配置
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
4.2 依赖特殊说明
以下三个包需要指定相同的版本号:
yarn add vue@2.7.13 vue-template-compiler@2.7.13 vue-server-renderer@2.7.13
4.3 主应用源码
入口 app.vue
应用入口,只需要一个router-view
即可。
登录页 login.vue
登录页面,按照vue和typescript语法开发即可,不做说明。
框架页 default.vue
该文件中需要有个“router-view”标签接收二级路由的组件容器。如下图所示。
远程组件容器 container.vue
该文件中的remote-view
为genesis框架中的组件,用来进行远程组件调用。具体参见源码。
客户端入口脚本 entry-client.ts
import { ClientOptions } from '@fmfe/genesis-core';
import { createClientApp } from '@fmfe/genesis-app';
import { createRouter } from './router';
import Vue from 'vue';
import App from './app.vue';
import Antd from 'ant-design-vue'
import 'ant-design-vue/dist/antd.css'
Vue.use(Antd)
export default async (clientOptions: ClientOptions): Promise<Vue> => {
return createClientApp({
App,
clientOptions,
vueOptions: {
router: createRouter()
}
});
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
服务的入口脚本 entry-server.ts
import { RenderContext } from '@fmfe/genesis-core';
import { createServerApp } from '@fmfe/genesis-app';
import { createRouter } from './router';
import Vue from 'vue';
import App from './app.vue';
export default async (renderContext: RenderContext): Promise<Vue> => {
return createServerApp({
App,
renderContext,
vueOptions: {
router: createRouter()
}
});
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
路由脚本 router.ts
其中每个路由中的ssrname表示该路由对应哪个服务。
import { Router } from '@fmfe/genesis-app';
import Container from './container.vue';
import Default from './view/default.vue';
import Login from './view/login.vue'
export const createRouter = () => {
return new Router({
mode: 'history',
routes: [{
path: '/',
meta: {
title:'E-MES',
ssrname: 'e-mes-main'
},
redirect: '/login'
}, {
path: '/login',
meta: {
title:'E-MES',
ssrname: 'e-mes-main'
},
component:Login
}, {
path: '/default',
meta: {
title:'E-MES',
ssrname: 'e-mes-main'
},
component: Default,
redirect: '/home',
children: [{
path: '/home',
meta: {
title:'系统',
ssrname: 'e-mes-home'
},
component: Container
}, {
path: '/about/*',
meta: {
ssrname: 'e-mes-about'
},
component: Container
}, {
path: '/share/*',
meta: {
ssrname: 'e-mes-share'
},
component: Container
}]
// Default页的二级路由 END
}]
// 一级路由 END
});
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
4.3 子应用源码
子应用没有特殊要求,按照正常路由开发即可