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

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

写在前面的

对 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。

    355 引用 • 1825 回帖 • 1 关注
  • Lute

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

    26 引用 • 196 回帖 • 17 关注

相关帖子

欢迎来到这里!

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

注册 关于
请输入回帖内容 ...
  • 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 回复
  • 其他回帖
  • painterpuppets

    阅读过 vditor 的源码,个人觉得用 lute 单独维护一套 mdast 的 parse 是一个有点费力不讨好的操作,而且想拓展 md token 需要直接去改 lute 代码,或许用 unifiedjs 去维护 mdast 是一个更优的选择,同时也可以依靠插件系统支持更灵活的 render

    2 回复
  • HerbertHe

    233333,先动手 Vditor,有时间再继续看看 Lute~Lute 现在也在寻求更新 emmm

  • HerbertHe

    等着 PR 合并,我先做了代码风格规范和 Sass 迁移 Less。我预估了一下底层代码结构得大改(滚动更新),等着慢慢合并(V 说怕我动作大了跟不上 😂

    我是希望在 Vditor 的项目上更新,因为没有打算做编辑器,只做渲染部分。

  • 查看全部回帖