当前位置: 首页 > 后端技术 > Node.js

完全无服务器!——文档型动态站点强行变身超瘦SPA!

时间:2023-04-03 19:42:39 Node.js

抱歉,用Serverless来做这个标题主要是炒作。本文内容与Serverless无关。但是为什么2X的作者会选择这个名字来吸引眼球呢?众所周知,Serverless的概念并不是字面意义上的“无服务”,而是将中心化的服务端应用打散为功能服务,节省了从前端编码到产品上线中间服务的运营成本部署。它本质上是一个云计算执行模型。聪明的童鞋看了标题和开头第一张图应该就猜到我药里卖的是什么葫芦了。这篇文章的内容其实是一个关于SSG(StaticSiteGeneration)的解决方案。介绍一下我最近如何将一个Mongo+Egg+React+Node架构的动态站点(内部非开源版图表库官网)降级为纯静态SPA(开源图表官网)libraryCloudCharts))并部署在githubpages上(注:考虑到国内访问问题,目前托管在gitee和netlify上)。为了突出方案的独特性,顺便给开源项目引流,难免先说明一下我遇到的需求场景的复杂性和非典型性:1.需求介绍1.1背景)腾(shui),一个Github开源项目:AliyunCloudCharts——又一个开源的信息可视化图表库。众所周知,这座悬崖就是一群无良技术人员在重新发明轮子!(这是一个尖刻的讽刺)。一个不正经的补充说明:CloudCharts的前身是一个应用于阿里云混合云场景的长期业务数据可视化解决方案(非开源版),方便很多不熟悉前端的研发童鞋在日常工作中开展业务实践我们开源版本的目的之一就是寻找更多适合沉淀的业务场景和更多优秀的志同道合的伙伴-(^_^)/没错~就是你!1.2需求在维护CloudCharts开源项目的同时,我们还需要将其内网版本的文档、示例、教程等资料同步至公网,以方便公网用户对项目的了解和使用。对于非开源版本的云图(TXDWidgets),我们实现了一套官网(群内网)用于托管相关文档和数据。本内部站点基于MongoDB+Egg.js+React.js的形式开发和维护。最大的特点是依托后台管理系统,方便开发图表库的童鞋及时维护发布图表库项目的功能特性和功能。相应的教程、示例、API文档等。为了避免手动将内容和文档传输到外网的繁琐工作,并尽可能向外网用户展示本站原有的功能和特性,我们希望把这套网站(首页功能和内容)放到外网。经过一番讨论和考虑,我们决定通过一系列的工作流程,将原来的站点构建成一个SPA应用,方便快速发布和更新到githubpages类型的静态页面服务(true-Serverless???)。2、SSG常规方案研究分析了两种主流的SSG模型,可以看出它们各自的优缺点:(1)基于SSR在构建时的优势(无头浏览器渲染后爬取静态内容),SEO友好的FCP友好性不够(尤其是动态站点数据请求量大时)前端路由功能页面的“爬虫”任务不够,无法有效还原耗时(尤其是动态站点页面层次结构复杂时)(2)XPress类型(如VuePressNext等框架)优点开源框架众多,社区生态完整。提供部署到githubpages等服务能力不足,公司技术体系差异较大。它需要框架迁移和大量代码重构。chartAPI&onlineDemo等内容的输出是超重体力活3.备选方案内网站点的功能和复杂度如下图所示。结合前面的相关分析,我们需要另辟蹊径,找到适合国情的发展道路。经过一定的业务抽象和一段时间的技术尝试,我们最终形成了一套完整的站点迁移技术方案。我们发现,要为动态站点搭建静态站点,最重要最重要的部分就是静态数据服务(即数据接口的内容被构建为可以静态托管的前端资源)。如上图所示,整个流程可以分为四个步骤:数据静态化、静态数据加载、图片资源本地化、SPA构建打包。在接下来的页面中,我们将对每个环节一一进行介绍,展示每个环节的具体内容、遇到的问题以及相应的解决方案。4.各个链接的姿态分解4.1数据资源的静态化由于官网是一个比较结构化的内容页面,我们根据不同页面的特点以及不同数据和数据之间的关系,编写了相应的浏览器脚本来模拟用户的点击和切换跳跃行为。同时记录exceed的数据请求(注意:exceed是一个http请求工具库,本质上是axios-npm地址的业务封装),经过一定的处理后传输到本地数据(过滤敏感数据记录和字段,将“请求参数-返回数据”存储为本地JSON文件,对应关系)。静态数据格式是这样的://demo.json[//单个请求的静态数据{//查询条件(请求参数)params:{api:'fetchAll',params:{module:'studio'},data:{page:1,size:0},},//查询结果(请求返回)response:{status:0,message:'success',data:[...],}},...]4.2加载静态数据(1)在页面加载静态数据SPA页面加载时,首先将静态数据加载到页面的js作用域中,方便数据查询方法的消费://将静态数据解析为字典form方便查询(字典键值对的查询效率远高于列表)functionparseGlobalData(list){varglobalData={};list.forEach(function(x){varkey=objectToKey(x.params);if(!globalData[key]){globalData[key]=x.response;}});returnglobalData;}//将请求参数(一个obj)转换成字符串(base64),作为字典键值对方便键名functionobjectToKey(obj){returnbtoa(JSON.stringify(Object.entries(obj).sort()));}//挂载静态数据到页面的js全局变量中}window.staticGlobalData=Object.assign({},window.staticGlobalData,parseGlobalData(data));}(2)转换exceed.fetch方法用于消费全局数据。内网站点数据使用exceed类库请求后端接口异步加载。在外网版本中,我们重写exceed.fetch方法,使用Proxy从本地读取数据(上一链接生成的静态数据)。原理如下://判断是否为外部站点if(isStaticSite()){consthandler={apply:(target,thisCtx,[params])=>loadLocalData(params),};//Proxyexceed.fetch方法消费全局变量中的数据exceed.fetch=newProxy(eceed.fetch,handler);}//从全局变量中查询数据的方法functionloadLocalData(params){constkey=objectToKey(params);returnwindow.staticGlobalData[key];}4.3图片资源本地化数据本地化完成后,可以通过nodejs脚本匹配官网使用的所有图片资源(CDN地址),无法在官网访问的图片资源公网(如语雀上的内网资源、OSS服务)进行本地化传输。4.4SPA构建与打包将内网站点的前端路由器改造为兼容SPA的形式再创建一个SPA工程构建公网版使用nodejs脚本实现部分模块源码的“一键式”同步需要在内网站点暴露给SPA项目中,最终的线上环境代码是通过SPA项目搭建的。5、结果显示,CloudCharts官网地址内外部版本对比效果如下(仅展示部分首页内容):可以看到,内网版本的图表库需要important功能模块已经恢复并内置到外部网站中(无法导出的部分在SPA的构建中得到了有效过滤)。6.方案总结&改进方向后面写:本文主要介绍SSG的技术方案和关键环节的一些技巧和技巧。在SSG的过程中,还有很多细节问题,比如:如何在一套代码中维护内外网不同版本的内容差异。欢迎有兴趣的童鞋留言讨论。