富文本编辑器按需加载:减少公共页面的资源负担

富文本编辑器按需加载:减少公共页面的资源负担原创封面

先确认编辑依赖从哪里进入页面

博客的公开阅读页需要显示正文,后台写作页需要富文本工具。两者如果共用包含编辑器的布局、插件或静态导入,访客可能在只阅读文章时也取得编辑相关资源。排查时先看导入链,再看实际网络与构建结果,不根据组件名字推断它已经按需加载。大型工具可能经过共享组件进入公共入口,也可能由导航预取提前取得。本文以 Nuxt 与 Tiptap 的后台编辑组件为例,说明如何建立加载边界与验证方法,不给出未经测量的体积减少比例。

可以从编辑组件的导入开始搜索,检查它是否被公共布局、全局插件和共享基础组件引用。再在公开页禁用浏览器缓存,记录文档和脚本请求的发起来源。构建目录中存在编辑器代码,不代表公共页面一定加载它;网络里没有一个叫 editor 的文件,也不代表工具代码没有混入共享块。模块图、资源请求与页面行为需要一起看。目标是解释依赖何时取得,而不是通过改文件名让资源列表看起来更轻量。

客户端组件与懒加载解决不同问题

编辑器依赖浏览器 DOM 时,可以放在客户端组件中,避免在服务端初始化不适用的对象。这个边界说明代码在哪里运行,但不单独保证客户端不会提前取得依赖。懒加载则把代码获取延迟到适用时机,两者可以组合。Nuxt 的组件约定和 Lazy 前缀提供相应组织方式,使用时核对当前版本的行为。不要只给文件加上 client 后缀,就报告公共资源已经减少;仍然需要检查它是否被某个共享入口静态引用。

ClientOnly 可以为服务端提供回退内容,客户端再渲染对应组件,但它也不等于所有依赖自动从公共客户端包消失。编辑器的静态导入位置仍然决定代码分块机会。若外层组件被每个页面使用,即使编辑区域暂时隐藏,也需要确认构建是否将依赖留在共享路径。条件显示与条件渲染同样不同:只隐藏一个已经渲染的编辑器,通常不能作为延迟获取的依据。加载设计应明确用户进入哪个操作时才需要创建工具。

把编辑能力放到后台路由边界

公开文章页可以读取经过服务端校验的正文表示,不需要为了展示文章启动完整编辑器。后台编辑页则拥有文档模型、工具栏和输入状态。将这两条路径分开,可以减少共享组件承担的职责。公共卡片、分类列表和导航不应静态导入富文本扩展;它们只需要文章元数据和展示资源。若公开页需要代码高亮或图片处理,也应按阅读需求选择相应工具,而不是直接复用整套编辑器来取得其中一项能力。

后台内部还可以按用户动作加载,例如进入编辑路由后再取得组件,或者点击开始编辑才创建工具。选择时应考虑使用频率与等待体验,不必对每一个小依赖都拆成独立请求。读写模式切换也需要明确状态所有者,避免懒组件卸载以后丢失尚未保存的文档。路由边界提供了自然的分块位置,具体交互仍由页面承担。加载更晚并不自动改善所有体验,必须同时考虑首次编辑的等待与状态恢复。

文档状态应该属于页面而不是临时实例

编辑器实例可以按需创建,但未保存正文应由页面或受控状态持有,通过明确的输入与更新契约传入工具。实例销毁以后,页面仍然知道文档内容和是否有修改。不要把包含 DOM 与内部对象的编辑器实例直接放进需要服务端序列化的公共状态。文档模型与运行实例是两种不同资源,分开管理有助于懒加载、切换模式和恢复操作。页面离开时如何处理未保存内容,也应有明确规则。

加载完成后,确认初始文档与后续更新不会互相触发无限同步。父页面设置文档、编辑器发出更新、父页面再次传回相同内容,应该采用合适的身份或差异判断。保存以后读取服务器规范化结果,也需考虑本地是否又产生新的编辑。懒加载只改变实例取得时间,不会替代编辑状态设计。验证时保留输入、撤销、切换与保存几条路径,确认工具取得以后仍然能够正确继续用户的工作。

回退内容与样式需要一起设计

首次加载工具时,页面应显示可理解的状态,保留基本表单与导航。回退区域可以预留合理空间,减少编辑区域突然出现造成的布局变化。ClientOnly 中组件使用的样式在服务端输出中可能有不同处理,因此基础布局不应只依赖尚未取得的编辑器样式。检查服务端文档和客户端完成后的布局,确认标题、按钮和文档区域都能阅读。加载状态也应能被辅助技术识别,而不是只有一个没有说明的动画。

如果资源加载失败,回退区需要提供适用恢复方式,并保留页面中的正文数据。不要因为工具暂时无法取得,就把文档重置成空内容或误报保存成功。离线与网络限制下,用户可能仍然需要查看已有内容或安全退出。可以按项目能力提供只读预览,具体是否允许替代编辑方式要有内容格式约定。恢复动作应该只重试工具资源或相关任务,不无条件刷新并丢弃未保存输入。

扩展与公共导入也需要检查

富文本扩展、代码高亮和工具栏图标都属于编辑能力的依赖链。即使主组件已经动态加载,若其中某个扩展又被公共插件静态导入,相关代码仍可能提前进入共享块。类型声明尽量使用合适的类型导入,避免为了取得一个类型引入运行时模块。构建优化应从真实模块图出发,确认每条公共路径需要什么。不要把所有扩展删除来追求更小制品,否则已有正文可能失去编辑和保存能力。

扩展精简还需要与数据库中实际文档节点对应。表格、任务列表、代码块和图片等功能如果已经用于文章,编辑器必须能够理解并保留它们。读取与写入路径的能力可以不同,但不能在编辑后悄悄丢失节点。对历史内容选择代表性文档进行加载、编辑和保存验证,再决定哪些扩展可以移除。性能优化的目标是减少不相关页面的负担,而不是让需要该能力的编辑页面失去内容兼容性。

用构建与网络结果验证加载时机

生产构建以后,查看资源分块和依赖关系,确认编辑器由后台路径或动态入口引用。再从干净缓存访问公开首页与文章页,记录是否取得对应资源,以及请求是否由路由预取触发。随后进入后台编辑页面,确认资源在预期时机取得并正常渲染。开发服务器的模块请求方式与生产制品不同,不能只在开发环境看到几个分开的文件,就推断生产分块同样有效。验证应使用实际准备发布的制品。

网络记录需要结合导航条件解释。某些页面会预取链接目标,测试时可以明确关闭该项或记录它的影响,再决定产品是否需要调整预取。不要把预取和公共主包混入视为同一原因,它们对应不同的修改范围。体积与耗时如果需要比较,应保存相同环境、输入和缓存条件的测量记录;本文只描述检查点,不将理论上的分块机会写成已经获得的性能数据。确认依赖取得路径,才是这次优化的首要证据。

验收不能只停在公共页变轻

公开正文需要检查标题、段落、代码、表格和图片等实际内容,确认阅读路径没有因依赖调整失去必要展示。后台需要检查创建、载入历史文档、修改、撤销、保存和重新打开。还应测试资源首次加载失败与页面快速离开,确认状态正确清理。对客户端专用工具,服务端请求不应因为浏览器对象初始化而失败。加载边界、文档兼容和错误恢复都属于同一交付中的必要条件。

可以选择几篇具有不同节点的已公开文章,在隔离环境中进行编辑往返,比较保存前后的内容语义。不要在真实文章上随意试验并覆盖正文,也不要只依据编辑器没有报错判断文档完整。变更记录应说明调整了哪条导入链,以及哪些页面与内容场景通过检查。这样以后升级编辑器或 Nuxt 时,可以沿相同边界复核,避免依赖重新进入公共布局而长期没有被发现。

让按需加载成为可维护的结构

项目约定可以明确公共展示组件与后台编辑组件的目录和职责,公共布局不导入写作工具,全局插件只包含真正全站需要的能力。新增扩展时检查其导入位置,编辑器升级时检查历史文档兼容。构建报告与少量关键网络检查可以帮助发现边界回退,但不必为每次小改动重复完整性能测量。只要出现具体剩余风险,再扩展验证范围,保持维护成本与实际影响相称。

本文适用于编辑器比公共阅读能力更重的内容站点。某些产品本身就是在线编辑工具,公共入口可能需要立即取得编辑能力,不能套用相同延迟策略。对个人博客,明确读写路径、保持文档状态独立、按路由或动作取得实例,再检查生产资源与内容往返,能够让加载边界更清楚。这样的结构既减少公共页面的不必要依赖,也保留写作页面应有的功能,优化才不会只体现在一份资源清单上。

实现片段

<script setup lang="ts">
const editing = ref(false)
const document = ref({ type: 'doc', content: [] })
</script>
<template>
  <button type="button" @click="editing = true">开始编辑</button>
  <ClientOnly v-if="editing">
    <LazyRichTextEditor v-model="document" />
    <template #fallback>
      <p class="editor-placeholder" role="status">正在准备编辑工具…</p>
    </template>
  </ClientOnly>
</template>
<style scoped>
.editor-placeholder { min-height: 18rem; }
</style>

一手参考资料

评论 · 0

还没有评论留下第一句经过思考的话。

游客评论需审核。注册后可直接公开,无需审核。

SHARE / 分享

分享这篇文章

WECHAT / 微信

用微信扫一扫

在手机微信中打开文章后,再从微信右上角分享给朋友或朋友圈。