Vditor 源码分析之内置特性支持

本贴最后更新于 1005 天前,其中的信息可能已经时移世改

写在前面的

对 Vditor 的源码不会进行逐行分析,分析仅限于处理对 Vditor 分析解耦的操作,Vditor 内部代码耦合程度比较高。Vditor Plugin 在不断阅读 Vditor 源码的过程中,不断试图提供更多的开放特性,面临的挑战和设计思路将以博客的形式进行分享。

一个新的目标

抽离 Vditor 自带的特性。需要注意的是,这里需要区分 Vditor 支持的自定义 renderer 和内部支持的特性(下面以 features 进行区分)。Vditor 通过 abcjs、mermaidjs、graphviz、KaTeX 等支持了很多的特性,代码结构十分类似。那么如何将这部分代码统一风格,甚至分离出 Vditor 项目本身呢?这也让我进一步思考如何进行生命周期设计和支持开发者通过 Vditor Plugin 自定义自己的 features~

通过抽离 Vditor 自带的特性实现,可以进一步减小 Vditor 项目本身的体积。

Features 源码分析

Vditor 支持的特性,其源码位于 vditor/src/ts/markdown at master · Vanessa219/vditor (github.com) 其中 xxxRender 的部分。

抽象来说,Vditor 的特性支持是如下的过程:

digraph fetures { 获取特定元素节点的子元素数组 -> 请求静态js资源 -> 遍历节点根据限制条件对特定的特性调用第三方库进行渲染 }

那么,此过程可以抽象,甚至进一步抽离吗?

我觉得是可以的,如果要实现自定义 features,需要先掌握自定义 renderers 的实现。在此就不赘述自定义 renderers 如何进行实现,这个 API 是由 Lute 提供的,实现方式其实与 Lute 实现自定义渲染器相同。自定义 renderers 实现的环节是 Markdown->HTML,但是自定义 features 实现的过程其实是对生成有特定 attributes 的 DOM 节点的二次渲染。

所以如果要实现相同的效果,在 Lute 不支持的语言的情况下,需要先自定义 renderers,以实现提供特定的 attributes 特征。然后在 HTML 渲染完成之后,再提取这些有特征的 DOM 节点进行三方包渲染。这么来看,Vditor 导出 HTML 是仅完成了第一步,第二步是依赖浏览器环境进行实现的。

至此,Vditor 添加运行时环境,其渲染过程将进一步细化。

graph TD; Vditor实例化-->插件Setup-->|Renderers| Markdown-HTML-->|Features| HTML二次渲染-->插件After-->实例挂载渲染结束;

性能优化思考

现有的源码实现调用了 Vditor 工具函数 addScript() ,了解 React 设计的同学都知道 this.state 拿到的状态不是实时的,因为 this.setSate({}) 的异步实现进一步减少对 DOM 更改的频率。

addScript() 的合并添加似乎是一个性能优化的方向。或者说,在加载插件的前期就预请求静态资源。为了不耽误特性的渲染,可以设置特定的 Promise 队列,预先提取插件的配置加入队列进行请求。对于 addStyle() 工具函数也同样是如此,应该可以实现进一步插件化 Vditor 项目,同时为开发者提供更多开放的可能性。

根据滚动条监听页面 DOM 按需加载,也同样是进一步性能优化的方向,在此就不赘述了。

什么时候开发 renderers?又什么时候开发 features 呢?

features 其实是对 renderers 功能掣肘情况下的进一步补充。features 支持是强依赖 renderers 的结果的,无论 renderers 渲染出的 DOM 节点特征 attributes 是由 Lute 提供的,抑或是自己写渲染器实现的。

引入编译时和运行时的理解,即是 renderers 解决了 Markdown->HTML 的编译过程,而 features 解决了 HTML -> JavaScript 特性渲染 的运行时渲染过程。

那如果引用的第三方包是通过输出 HTML + CSS 进行渲染的呢?

那只写 renderers 则足矣了。

进一步思考发展趋势

Vditor 目前作为一个独立包进行发布。如果有可能的话,对于通用的代码我还是希望独立分包发布。以 Vditor 为核心建立 源码 + 文档 + 插件 + 衍生项目 的完整生态体系,这样可以进一步扩大 Vditor 项目的开源影响力。

为了适配现有 Vditor 源码,对于 3.x 的更新着重于项目源码本身的优化,诸如优化冗余代码、迁移代码风格工具、Sass 迁移 Less 面向未来对样式表开发进一步优化等。。

Vditor@next 着重关注运行时设计,与 3.x 并不完全兼容。在保留现有特性的前提下,对代码执行流程进行进一步优化,希望可以进一步提升无论是用户还是开发者的体验。

  • Vditor

    Vditor 是一款浏览器端的 Markdown 编辑器,支持所见即所得、即时渲染(类似 Typora)和分屏预览模式。它使用 TypeScript 实现,支持原生 JavaScript、Vue、React 和 Angular。

    352 引用 • 1815 回帖 • 2 关注
  • Lute

    Lute 是一款结构化的 Markdown 引擎,支持 Go 和 JavaScript。

    25 引用 • 191 回帖 • 16 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • CheGuevara

    害怕(3D-Remast) - 各种害怕版本(滑稽)_动图_害怕_滑稽表情

    1 回复
  • 其他回帖
  • HerbertHe

    如果基于标准 markdown 的语法的话,其实不存在 tokenizer 的问题。我认为 tokenzier 的优化支持,只是进一步通过 AST 提高渲染时的效率,比如我下面提的这个 issue:

    支持 XML 解析为组件 · Issue #164 · 88250/lute (github.com)

    在我 PR lute 的 RenderJSON 这个 API 之前,是无法通过 lute 实现前端全自定义渲染的。其实如果愿意的话,通过这个 API 可以完全前端自行实现渲染器 emmm。当时我只是为了解决 Vditor 还需要通过第三方库实现大纲渲染的问题,仔细研究的话还是蛮好玩的。

  • HerbertHe

    如果往富文本发展的话,是需要支持拓展状态机的,复杂度会提升很多。这个项目我再看看,插件化特性增加其实会导致性能下降,这需要针对具体场景优化。

    实际来说,现在没有让我觉得还不错的 markdown 编辑器。所见即所得和即时渲染多多少少有语法问题,而且还有卡顿的情况。总体来说,我更关注渲染器。。。编辑器 hold 不住,slate 还有中文的问题

    1 回复
  • HerbertHe

    在 tokenizer 的问题上,lute 似乎在试图把这部分剥离重构,如果顺利的话通过 js 来自定义 token 的解析也不是问题。只是我觉得可能就偏离作为一个 markdown 解析器的初心了,这个发展方向就变成了富文本解析了。

    Vditor 的合并比较慢,我设计了一套插件解耦,对于运行时的设计可能需要等待很长的时间。我开始慢慢有想法专门做一套 markdown 渲染器脱离 Vditor 了,但就目前自己的工作安排来说,优先级并没有那么高。markdown-it 的文档写的实在是太差了,之前有想法通过 markdown-it 直接支持小程序渲染 markdown。Vditor 如果重构渲染部分的话,是可以实现同步渲染的(加点逻辑就行了,部分特性可能不支持

    其实目前的主要矛盾还是在 lute.min.js 实在是太大了(即使有 jsdelivr CDN 也还是慢),golang 似乎并没有官方支持 wasm 的打算。gopherjs 和 go-wasm 的作者是同一个人,go-wasm 的引入也并不优雅,打包了 go 的运行时。。。所以,我都有用 rust 重构 lute 的想法了(我随便说说的,别当真 233333

    1 回复
  • 查看全部回帖