2020 年,你可能需要基于 Vue 的微服务架构实践,在服务端或客户端聚合子服务 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
1340641314
V2EX    前端开发

2020 年,你可能需要基于 Vue 的微服务架构实践,在服务端或客户端聚合子服务

  •  
  •   1340641314
    lzxb 2020-06-10 11:10:39 +08:00 989 次点击
    这是一个创建于 1951 天前的主题,其中的信息可能已经有所发展或是发生改变。

    快速开始

    # 拉取代码 git clone [email protected]:fmfe/vue-genesis-micro.git # 安装依赖 npm install # 开发环境启动 npm run dev # 打包生产环境代码 npm run build # 生产环境运行 npm run start 

    微服务是什么?

    微服务是一个新兴的软件架构,就是把一个大型的单个应用程序和服务拆分为数十个的支持微服务。

    为什么需要微服务?

    随着业务的发展,项目规模越来越大,给编译打包、合并的代码冲突带来了巨大的挑战,而服务的拆分可以获得更快的编译打包,独立部署、增量更新、不同的团队只需要负责自己的服务、更好的支持多端,在大型的项目中,使用微服务架构可以获得极大的收益。

    微服务和微前端的区别

    目前社区的微前端解决方案,基本上都是基于客户端去进行聚合的思路,而本项目却是完全基于后端微服务的概念而诞生的,页面的聚合既可以在服务端完成,也可以在客户端完成,一切取决于需求。

    项目介绍

    本项目基于 Vue 的Genesis开发,一个编写了三个例子:

    • ssr-common 公共的页面导航
    • ssr-home 首页
    • ssr-about 关于我们
      在学习完成本项目后,你可以搭建属于自己的微服务架构,并且深入的了解到远程组件它是怎么工作的。至此,你可以做到一个大型应用的微服务拆分下。

    关于 Genesis

    Genesis是在FOLLOWME5.0升级而诞生的一个项目,它解决了以往架构的很多弊端,例如:

    • 公共组件库更新,导致同时十几个项目要编译发布更新
    • 页面和页面之间的切换,需要刷新整页,无法做到无刷新跳转
    • 数百个页面,如果全部写到一个大的项目中做 SSR 渲染,只要其中一个地方出现 BUG,就有可能导致整个服务挂掉或者不稳定,发生内存泄漏的问题时,也更加难以排查
    • 大量的项目是基于 CSR 渲染,在国际化和 SEO 方面,导致 index.html 页面的标题、关键词和描述比较难做到国际化
    • 不同的团队,互相交叉开发一个项目,合并代码时,很容易产生各种冲突,服务的拆分后,大大的减少了代码冲突

    渲染接口

    服务的拆分后,那么服务和服务之间的调用是必不可少的,这里提出了一个渲染接口的概念,它可能是这样子的

    // 下面的接口,你可能需要做 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 模板引擎等等。本项目会使用渲染接口,来传递给远程组件进行渲染。

    远程组件

    当你需要调用其它服务的页面渲染时,你请求渲染接口,拿到渲染的结果,传递给远程组件,它就会负责帮你渲染该服务的内容。

    <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 仓库中。

    最后

    目前尚无回复
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     4452 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 05:34 PVG 13:34 LAX 22:34 JFK 01:34
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86