29 前台页面的渲染方式:如何设计前台页面的渲染策略?
你好,我是杨文坚。
经过前面几节课的学习,在运营搭建平台的页面功能维度中,我们完成了页面发布流程和页面回滚措施,可以放心地把页面发布到生产环境,提供给让外部客户使用。下一步,就是进行前台页面的渲染操作了,这也是运营搭建平台中,页面功能维度的最后一个环节——“页面渲染方式”。
可能你会有困惑,之前我们学过的“页面的编译和运行”里,也讲了页面渲染策略,为什么还有一节课讲解“页面渲染方式”呢?
有这个疑问很正常,因为我们之前学的都是一些分散的技术点,比如Vue.js的服务端渲染、Vue.js组件的多种模块格式等等,这些技术散点都是你的知识储备。今天,我们就要把这些知识储备,通过实际项目应用实践,有机结合起来,应用到搭建平台的前台场景中。
那么“页面渲染方式”这个页面维度的功能模块,在前台服务上,我们如何进行设计和实现呢?
1. 设计前台页面的链接
页面渲染的第一件事,就是在要在浏览器输入页面的URL,也就是页面的链接,所以我们今天第一件事就是设计页面的链接。
前台页面的链接,是面向外部用户的,考虑到用户的传播和使用,我们要尽量让链接简单一些,后续生成的链接二维码图片也会精简一些。
一般我们会这么设计URL。
你可能会觉得页面uuid太长了,导致URL太长,影响页面链接传播效果。我们可以换种uuid生成方式,在后台服务创建页面生成uuid时候,换一种简单的随机字符串生成方法。
例如,随机生成只有英文和数字的短字符串。
但是,如果业务搭建页面非常频繁,生产出来页面的数量非常庞大,用比较复杂的uuid还是很有必要。因为复杂的uuid能避免重复,从而避免带来数据操作的污染或者干扰。
要特别注意,URL里不能用页面在数据库的自增数字id。因为自增数字id容易被“灰黑产”利用,“灰黑产”可以按自增数字拼接页面URL,用“爬虫”抓取所有页面内容。这也算是一种变相的“拖库”行为,容易造成大量页面数据泄露。
现在,我们有了页面URL,客户就可以在浏览里通过URL访问页面了,那么接下来就要进入页面渲染环节了。
2. 设计前台页面的浏览器端渲染
我们之前学过Vue.js页面的浏览器端渲染(客户端渲染)和服务端渲染原理,CSR和SSR。页面大部分功能,都是基于浏览器端渲染来实现的,服务端渲染的作用更多是减少白屏时间和支持SEO。
所以,我们优先做浏览器端渲染的技术设计和实现。
首先,回顾一下“物料组件多种模块格式”和“页面编译和运行”这两节课,我们可以总结出三种浏览器端渲染方式。
- Bundle文件渲染
- 基于ESM模块的动态加载渲染
- 基于AMD模块的动态加载渲染
接下来结合前面学过的知识点,我们基于前台服务,从前端到服务端,设计这三种浏览器端渲染的技术方案。
第一个浏览器渲染方式是Bundle文件渲染。
我画了步骤图,Bundle文件渲染分成四步。
- 第一步:浏览器发起前台服务请求。
- 第二步:服务器接受请求,解析出页面uuid。
- 第三步:数据库查找页面数据,判断页面是否存在,如果存在就拼接对应的HTML结果。
- 第四步:浏览器执行和渲染服务端响应回来的HTML结果。
第二个浏览器渲染方式是ESM动态渲染方式。
Bundle文件渲染分成五个步骤。
- 第一步:浏览器发起前台服务请求。
- 第二步:服务器接受请求,解析出页面uuid。
- 第三步:数据库查找页面数据,判断页面是否存在,如果存在就把页面数据埋在HTML全局变量中。
- 第四步:浏览器执行和渲染服务端响应回来的HTML结果。
- 第五步:运行ESM运行时来异步加载ESM模块,动态加载物料渲染页面。
第三个浏览器渲染方式,AMD动态渲染方式,具体步骤和ESM基本一样,只是在最后一步中,动态加载物料组件资源的方式,从纯ESM动态加载渲染,变成基于RequireJS,加载AMD物料组件模块,进行动态渲染。
有了三种浏览器端渲染方式,接下来就要灵活利用这三种渲染方式,构建页面渲染策略。
还记得我们之前设计的“页面渲染策略”吗?当时的策略是优先进行Bundle文件渲染,提升用户体验,如果页面报错导致不可用,就进入降级渲染逻辑,按客户浏览器的兼容情况选择ESM或AMD的渲染方式。
今天我们就来实际实现一下。
3. 做前台渲染测试的落地实现
根据之前课程页面渲染策略的理论技术方案,进入降级渲染逻辑的部分,我稍作调整,画了一张步骤图。
渲染策略分成三个步骤。
- 第一步:默认Bundle文件渲染,监听页面错误异常。
- 第二步:渲染提示用户,选择是否降级渲染。
- 第三步:根据浏览器环境,选择ESM或AMD渲染方式。
第一步,默认Bundle文件渲染,监听页面错误异常。核心操作是要监听页面错误,我们可以分成“Vue.js应用内部错误”和“其它错误”。
在Vue.js应用的内部,可以通过Vue.js官方提供的API(app.config.errorHandler)来捕获错误异常。
app.config.errorHandler = (err, instance, info) => {
console.log('捕获到Vue.js内部报错: ', err);
// 处理后续的页面降级处理
}
其它错误,可以通过监听window的错误事件。
第二步,渲染出错误提示,让客户选择是否要降级。看课程代码案例的截图。
你可能会有疑问,为什么要让客户自行选择降级呢?为什么不能直接用代码处理强制降级呢?
这是因为客户遇到页面出现错误的时候,程序员不一定能第一时间得到反馈和处理问题。与此同时,客户遇到页面错误后,不一定影响页面主要功能的使用,这时候强制降级可能会适得其反。
第三步,根据浏览器兼容情况,选择和执行ESM或AMD的渲染方式,对物料组件逐个动态加载,以及隔离组件独立渲染。
如何判断页面是否支持ESM呢?这里我们可以基于impormap,来用执行import操作,检测是否支持ESM模块。
// packages/portal-server/src/public/static/page-helper.js
let canSupportESM = true;
try {
// 用import()动态加载importmap指向的vue模块
import('vue').then(() => {
canSupportESM = true;
}).catch((err) => {
console.warn(err);
// 如果出错,就证明当前不支持ESM
canSupportESM = false;
});
} catch (err) {
console.warn(err);
// 如果出错,就证明当前不支持ESM
canSupportESM = false;
}
课程案例是直接在第二步时候就判断降级选择方案,然后生成对应的URL,提供给用户触发降级渲染页面时,跳转到降级页面使用。
进行页面降级跳转的时候,进入ESM或AMD降级渲染的页面链接,这个链接其实跟原来的Bundle渲染页面是同一个URL路径Path,只不过携带的参数不同。然后,服务端根据这个参数做对应的服务端处理,输出相应渲染方式的HTML代码,携带不同的JS和CSS静态资源链接。
你可以看对应截图。同一个页面URL的Bundle渲染结果。
基于同一个页面URL路径,带上参数“runModule=amd”的渲染结果。
基于同一个页面URL路径,带上参数“runModule=esm”的渲染结果。
现在,我们完成了浏览器渲染和页面渲染策略的技术实现。接下来就要进入页面的服务端渲染了。
4. 设计和实现前台页面的服务端渲染
服务端渲染主要是解决白屏等待问题和SEO需求,其中,最重要的是SEO需求。所以做服务端渲染之前,我们要考虑是否有SEO需求,如果有需求,就要必须要用服务端渲染。
回忆我们学过的Vue.js服务端渲染,我重新画了一张技术步骤图。
服务端渲染可以分成四个步骤。
- 第一步,浏览器发起前台服务请求。
- 第二步,服务器接受请求,解析出页面uuid。
- 第三步,数据库查找页面数据,根据页面布局数据,获取物料组件的CommonJS模块,将其动态编译组装成页面HTML字符串。
- 第四步,浏览器执行和渲染服务端响应回来的HTML结果。
具体技术实现我们已经学过了,就不再重复(定制化服务端渲染的实现,你可以查看代码案例,在目录:packages/portal-server/src/service/page-app.ts)。
前面提到,有SEO需求,我们必须选择用服务端渲染。那么页面白屏等待问题,就不是选择服务端渲染的必要条件吗?答案是否定的,服务端渲染可以解决白屏等待时间,但是不一定能完全解决,因为服务端渲染存在一些隐患。
服务端渲染存在哪些隐患
课程中,我们用的是Node.js来开发项目的服务端功能。那么基于Node.js在服务端,做运营搭建平台的服务端渲染,会有哪些隐患呢?
首先,页面是由物料组件组成的,而且物料组件不是固定的,是动态的。所以每次做服务端渲染,都需要在Node.js环境里做动态的组件编译,生成HTML结果。
其次,一个页面可以存在多个物料,可能几个,可能几十个。那么Node.js服务在组装页面HTML代码的时候,就要对每个物料Vue.js组件,传入组件的数据源,编译成HTML代码。这个编译过程是外部客户访问页面时候进行的,也需要时间执行操作。页面使用物料一旦变多,服务端动态编译HTML时间就变长。
所以,这也是我们刚刚说的“服务端渲染可以解决白屏等待时间,但是不一定能完全解决”,反而可能因为编译物料组件过多,白屏时间更长。
总的来说,Node.js做Vue.js的全栈服务,可能存在的隐患大致可以分成三点。
- 编译复杂组件耗性能。Node.js服务,处理复杂物料组件,比较耗性能。
- 组装编译页面耗性能。如果页面布局复杂,物料组件依赖太多,Node.js处理页面的时候,会占用较多的CPU和内存性能。
- 服务端运行Vue.js不可预测的错误。物料组件的CommonJS模块格式,不一定能百分百在Node.js服务端处理成HTML,可能组件里存在浏览器API的使用,导致在服务器运行时候中报错。
不过,解决办法也是有的,这三点隐患其实都指向一个问题,客户访问页面的时候,要动态“编译组件成HTML”和“组装页面成HTML”,所以,我们可以前置这个步骤,放在后台服务中,在页面发布流程中,就把页面的服务端HTML直接编译出来,放到CDN给前台服务使用。
具体实现思路也很简单。
解决动态编译组件耗Node.js性能问题,可以在后台服务发布流程中,前置编译成HTML文件,发布到CDN或其他静态资源服务上,前台渲染直接使用这个已经编译好的HTML。解决动态组装页面耗Node.js性能,也可以按照同样的物料组件的方式,前置编译HTML文件结果。
总结
今天我们围绕着“页面的渲染方式”,学习了如何在客户视角实现搭建页面的渲染。
首先,我们整合了三种页面渲染方式:Bundle文件渲染、基于ESM模块的动态加载渲染和基于AMD模块的动态加载渲染。
在具体实现方案上,页面渲染,优先使用Bundle渲染,如果出现异常,就提醒客户,让客户自行选择是否降级处理。“让客户选择降级”是一种折中的方案,不是绝对方案。你在实际工作中,可以根据自己业务需求,选择是折中方案或者强制降级方案。
另外,服务端渲染不是万能的,不能绝对解决白屏等待问题。服务端渲染的隐患,基本来自Vue.js组件编译HTML的操作过程,比较难发现,也很难根除,所以,最好解决办法是把隐患前置到“企业内部页面发布阶段”,前置服务端编译组件成HTML的过程,及早发现问题和解决问题。
你应该能发现,今天讲的很多技术方案都是基于以往课程里学过的技术点。其实,技术的成长,就是要依靠长期的“技术储备”和“技术实践”。当你遇到任何技术问题,都能想到使用以前学过的“技术点”,并且比以前更加得心应手地设计技术方案,实现技术功能。那么恭喜你,你的技术已经得到成长了。
思考题
课程中,前台服务的浏览器端渲染和服务端渲染,都是基于Node.js服务的。假设随着业务发展,我们要对前后台服务架构进行分离,面向客户的前台服务要变成Java开发和维护,面向内部员工的后台保持用Node.js。
那么如何保证服务端渲染的功能,从Node.js环境平滑转换支持Java服务端的服务端渲染?
期待看到你的思考,参与讨论。我们下节课见。
完整的代码在这里
- Akili 👍(0) 💬(4)
老师,请教一个问题,我们现在涉及的都是后台管理系统开发,遇到的问题就是一直在重复的工作,对自己也没有提升,有没有什么方案避免这样的工作方式?谢谢你
2023-02-17 - ifelse 👍(0) 💬(0)
学习打卡
2024-10-01 - Geek_12e8fd 👍(0) 💬(0)
在将前台服务的服务端渲染从 Node.js 平滑转换到 Java 服务端时,需要确保渲染逻辑、数据模型、模板引擎以及可能的缓存机制都能在新的环境中得到支持。以下是一些关键的步骤和考虑因素: 分析现有服务端渲染逻辑: 理解当前 Node.js 服务端渲染的工作流程,包括数据准备、模板渲染、缓存等。 确定哪些部分可以直接移植到 Java,哪些部分需要重写或调整。 选择或开发 Java 中的模板引擎: Node.js 中常用的模板引擎如 Pug(Jade)、EJS、Nunjucks 等在 Java 中可能没有直接对应的实现。 你可能需要选择一个现有的 Java 模板引擎,如 Thymeleaf、FreeMarker、Velocity 等,或者开发一个自定义的模板引擎来匹配现有的模板语法。 数据模型与接口对齐: 确保 Java 后端与 Node.js 后端使用相同的数据模型,或者至少能够提供相同的数据接口。 可能需要对现有的 API 进行调整,以便 Java 后端能够访问所需的数据。 实现服务端渲染逻辑: 在 Java 后端中重写或实现服务端渲染逻辑。 这可能包括数据获取、模板渲染、错误处理等部分。 缓存机制: 如果 Node.js 后端使用了缓存来提高性能,确保 Java 后端也实现了类似的缓存机制。 可以考虑使用 Redis、Memcached 或其他缓存解决方案来共享缓存数据。 测试与部署: 在开发过程中进行详细的测试,确保新的 Java 后端能够正确地渲染页面并与前端交互。 逐步部署新的 Java 后端,并监控生产环境中的性能和用户反馈。 持续集成与持续部署(CI/CD): 建立或更新 CI/CD 流程,以便能够快速、可靠地部署新的 Java 后端。 文档与培训: 编写详细的文档,解释新的 Java 后端的工作原理、配置选项以及维护指南。 对开发团队进行培训,确保他们熟悉新的后端架构和工作流程。 监控与日志记录: 实施监控和日志记录机制,以便能够及时发现和解决问题。 确保新的 Java 后端与现有的监控和日志记录系统兼容。 性能优化: 在将服务端渲染迁移到 Java 后端后,可能需要进行性能优化以确保与 Node.js 后端相当的性能。 这可能包括调整 JVM 设置、优化数据库访问、使用异步处理等技术。 安全性考虑: 确保新的 Java 后端遵循最佳的安全实践,包括输入验证、防止跨站脚本攻击(XSS)、跨站请求伪造(CSRF)等。 通过遵循这些步骤和考虑因素,你可以将服务端渲染功能从 Node.js 平滑转换到 Java 服务端。需要注意的是,这个过程可能需要一定的时间和资源投入,因此建议在进行迁移之前进行充分的规划和准备。
2024-06-14