摘要(Auto)
- 生成时间:2025-12-21
- 关注点:Schema 驱动渲染链路、编辑器一致性、运行时性能治理、SSR/Hydration、导出一致性与权限隔离、稳定性与降级
建议追问(Auto)
- 为什么选 SSR/CSR/流式 SSR?反例是什么?
- 导出怎么保证一致性与权限?失败怎么兜底?
- 低代码如何做物料版本治理与 schema 迁移?
关联卡片
在我项目中的角色与使用场景
- 低代码(大屏/报表)里通常会同时遇到三类“选型问题”:
- 渲染器:自研 vs 开源二次开发;编辑态/运行态一致性如何保证?
- 渲染模式:SSR vs CSR vs 流式 SSR,首屏/SEO/鉴权/稳定性如何权衡?
- 导出:客户端截图 vs 服务端渲染/离线渲染;一致性、权限隔离与失败兜底怎么做?
原理简述
把问题拆成三段更容易讲清楚:
- Schema 驱动低代码(核心):
- schema 是可序列化的“UI + 数据 + 事件”描述;runtime 把 schema → runtime tree → 组件树。
- 关键:nodeId 索引 + 局部更新,避免“schema 一动全树重渲染”。
- 编辑器:拖拽/撤销重做/编组,本质是对 schema 的增量变更(command/patch)。
- SSR/CSR(核心):
- CSR:逻辑简单、生态成熟,但首屏完全依赖 JS 下载与执行;弱网/低端机更容易慢。
- SSR:服务端先把 HTML 渲染出来(可带鉴权),客户端 hydration 接管;要处理一致性(时间/随机数/环境差异)。
- 流式 SSR:边渲染边输出,TTFB 更早;但错误处理/中断/缓存隔离更复杂。
- 导出(核心):
- 最重要的是“一致性 + 权限”:导出任务要带用户身份/权限快照,服务端按权限过滤数据,且与线上展示口径一致。
- 失败兜底:异步任务、重试、降级到截图或导出占位(按业务约束选择)。
对比表格
1)低代码渲染器:自研 vs 开源二次开发
| 维度 | 自研渲染器 | 开源框架二次开发 |
|---|---|---|
| 定制能力 | 强(贴合业务 DSL) | 中-强(受框架边界影响) |
| 交付速度 | 中 | 快 |
| 治理成本 | 高(长期维护) | 中(跟随社区升级) |
| 风险与回滚 | 可控(版本锁定)但需要自建迁移体系 | 受上游版本影响,需要隔离升级风险 |
2)渲染模式:CSR vs SSR vs 流式 SSR
| 维度 | CSR | SSR | 流式 SSR |
|---|---|---|---|
| 首屏 | 中-差(依赖 JS) | 好(HTML 直出) | 更好(边渲染边输出) |
| SEO | 弱 | 强 | 强 |
| 实现复杂度 | 低 | 中-高(hydration/同构数据) | 高(错误/中断/缓存) |
| 稳定性与降级 | 简单(直接回退) | 需要 SSR→CSR 降级策略 | 更需要(流中断/异常) |
3)导出:截图 vs 服务端渲染 vs 离线渲染任务
| 维度 | 客户端截图 | 服务端渲染导出 | 离线渲染任务(队列) |
|---|---|---|---|
| 一致性 | 中(受浏览器影响) | 强(同口径渲染) | 强(可控环境) |
| 性能/稳定性 | 受客户端影响 | 中(服务端压力) | 高(异步、可重试) |
| 权限隔离 | 易遗漏 | 可严控 | 可严控 |
| 适用场景 | 轻量兜底 | 中等规模、实时导出 | 大规模/耗时导出 |
模拟问答
[ ] Q1:为什么低代码一定要做“物料版本治理 + schema 迁移”?不做会怎样?
- 不做的后果:物料升级后线上配置失效、渲染报错、回滚困难。
- 口径:配置锁定物料版本;破坏性变更用 migration 脚本升级 schema;支持一键回滚旧物料版本。
[ ] Q2:SSR 的 hydration mismatch 常见原因是什么?你怎么避免?
- 常见原因:时间/随机数、依赖浏览器 API、服务端与客户端数据不一致、条件渲染分支不同。
- 避免:同构数据注水/脱水(dehydrate)、避免在 render 中引入不确定性、把浏览器专属逻辑放到 effect。
[ ] Q3:流式 SSR 的收益点是什么?最大的坑是什么?怎么做降级?
- 收益:TTFB 更早、首屏更快。
- 坑:错误处理/中断恢复更复杂;缓存必须按用户/权限隔离;并发下超时与资源泄露风险更高。
- 降级:SSR 超时/失败回退 CSR;关键模块失败只降级局部,不拖垮整页。
[ ] Q4:导出怎么保证“一致性 + 权限隔离”?失败怎么兜底?
- 一致性:导出与线上展示同一份数据与渲染口径(同一套数据加工/筛选规则)。
- 权限:导出任务携带用户身份与权限快照,服务端按权限过滤数据,避免越权导出。
- 兜底:异步任务 + 重试;必要时降级到截图或导出占位,并完整上报失败原因与版本号。
[ ] Q5:高频刷新大屏为什么容易卡?你怎么治理并“可观测”?
- 卡的根因:长任务(计算/渲染)、联动触发链过长、图表动画/数据量过大、内存增长。
- 治理:数据层合并/节流/降采样;渲染层局部更新/分片/虚拟化;图表降级(动画/细节)。
- 可观测:Long Task、FPS/掉帧、内存趋势、错误率与关键交互耗时(按大屏/组件维度打标签)。
手写代码区
1)SSR 注水/脱水(避免 hydration mismatch 的最小思路)
type Dehydrated = { route: string; data: unknown }
export function serializeState(state: Dehydrated) {
// 真实项目:注意 XSS(转义/安全序列化)
return JSON.stringify(state)
}
export function deserializeState(raw: string): Dehydrated {
return JSON.parse(raw) as Dehydrated
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
2)导出任务:带权限快照的最小协议(伪代码)
type ExportJob = {
reportId: string
userId: string
permissionSnapshot: string[] // 例如资源权限列表
params: Record<string, any>
}
export function canExport(job: ExportJob, requiredPerm: string) {
return job.permissionSnapshot.includes(requiredPerm)
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
我的补充(Manual)
(不会被脚本覆盖:真实约束、组织因素、踩坑)
