2020年5月22日,FOLLOWME5.0第一版终于上线了。这也是公司内部基于Genesis推出的第二个项目。首页是一个老项目,经历了最原始的一种VueSSR。后来年初迁移到Nuxt.js,现在迁移到Genesis。可谓一波三折。第一次实践2019年上半年,我们在与APP的混合开发项目中第一次实践了模块化。它有独立的API、路由、状态和页面,按需初始化,但并不完美,它是一个基于路由的微模块,状态也是按需注入全局状态。无路由微模块管理2019年8月,开始接触web首页的开发。Vuex的状态管理,所有的状态都被注入到全局状态中,并且交集在一起。随着业务的迭代,不再明确哪些是需要的,哪些是可以删掉的。随着业务规模的扩大,维护难度越来越大。为了保证非侵入性,在Tms.js的基础上抽象出一个支持微模块的状态库。这时候我们的微模块就有了独立的API、状态和页面。我们的5.0左侧导航被提取到一个独立运行的微模块中。一个微模块由多个组件组成,它有自己的内部状态管理。2019年底,大跃进得知我们要升级到5.0版本,网站也将进行大改版。基于现有的微模块开发理念,我们希望更进一步,解决一些以往项目架构的弊端。在5.0之前,我们有一个公共导航栏,CSR和SSR项目都需要它。每次更换导航栏,都需要重新打包发布十几个项目,极大地消耗了我们的身心。体力,我希望一个页面可以从不同的SSR服务聚合起来,以API的形式提供给另一个服务。在这个大胆的想法诞生后,我们深入研究了Nuxt.js,希望它能满足我们的需求。经过一番研究,确定不能满足我的需求后,我们最终选择了做轮子。Genesis参考了一些社区SSR框架的实现,基本都是封装好的框架,灵活性不高。我们希望它是一个简单的SSR库,作为工具函数使用,从而支持多实例运行。这里的概念下,它不像Nuxt.jsnuxt.config.js那样直接读取一个配置开始运行,而是为你集成了各种功能。它只是一个基本的渲染工具函数import{SSR}from'@fmfe/genesis-core';constssr=新SSR();常量渲染器=ssr.createRenderer();renderer.render({url:'/'});当然在实际业务中,我们还需要创建一个HTTP服务,将我们的内容返回给用户。如果要实现微服务,并且能够被不同的服务调用,首先需要服务本身具备将渲染结果输出为JSON的能力,然后第三方服务读取渲染结果输出为HTMLrenderer.render({url:'/',mode:'ssr-json'});我们巧妙的使用了Vue的Renderer选项模板,传入一个函数,执行后返回一个JSON渲染结果=strHtml.replace(/^(<[A-z]([A-z]|[0-9])+)/,`$1${this._createRootNodeAttr(ctx)}`);constvueCtx:any=ctx;constresource=vueCtx.getPreloadFiles().map((item):Genesis.RenderContextResource=>{return{file:`${this.ssr.publicPath}${item.file}`,extension:item.extension};});const{数据}=ctx;if(html===''){data.html+=`
`;}else{data.html+=html;}data.script+=vueCtx.renderScripts();数据样式+=vueCtx.renderStyles();data.resource=[...data.resource,...resource];(ctxasany)._subs.forEach((fn:Function)=>fn(ctx));(ctxasany)._subs=[];返回ctx.data;};远程组件考虑到并不是所有的项目都需要远程调用,所以远程调用组件由一个独立的包提供,并得到SSRJSON的渲染结果,最后由远程组件负责我们嵌入到页面中服务。