乐趣区

关于前端:给Markdown添加视频支持

本文转载自我的博客:https://blog.kaciras.com/article/18/add-video-support-to-markdown

都 2020 年了,当初最风行的就是什么直播弹幕短视频,你的博客要是还不反对插视频那可就 OUT 啦!

我的博客目前应用 Markdown 写文,惋惜它原生的语法并不反对视频,于是只能本人来实现这性能了。

视频益处都有啥?

视频是个好货色啊,它要不好当初的直播弹幕短视频怎么火的……咳咳,扯远了,就说写博客,比方写教程啊总会遇到须要动静演示的货色吧,比方我本人的纯 CSS 解决图片加载的布局挪动问题里一结尾的动图(其实是视频啦),要用图片或者文字来阐明文本下移的景象必定没有动静的演示好。

另外玩过 Twitter 的都晓得它外面插入的 GIF 图会转换为视频,GIF 是 1987 年创造的货色,在我看来早是就该进入垃圾堆的技术,因为当年浏览器不反对视频才得以风行。动图这一技术齐全能被视频所代替,视频自身就不是一连串图像的序列吗(当然还包含声音)。

在性能上,H.246 编码的视频体积仅为 GIF 的 13 分之一,尽管 GIF 也有 gifsicle 能压缩一下,但成果仍不如视频。

从我的理论教训来看,技术类文章里大部分动静演示都来源于录屏,录屏软件生成的原本就是视频格式,把它们转 GIF 多此一举。综上所述,视频的反对是一个现代化博客必须的性能

语法的抉择

Markdown 版本演进曾经有其它的文章写过了 https://juejin.im/post/5baa5b346fb9a05d2d0225cc#heading-6

次要的几个 Markdown 版本原生都不反对视频,我不晓得它的作者是怎么想的,如此重要的性能居然能没有。既然官网没有,那就本人做呗,于是种各样的实现计划就跑了进去,依照自己强迫症的做法当然要比照一番

间接插 HTML


这是我看到的最多的做法,其劣势就是简略,现有的转换库都反对写 HTML,但我认为这种形式并不好。

  • XSS 危险:若是本人用还好说,一旦给评论之类的第三方输出用上,你都猜不到他们会搞些什么进去。
  • 扩展性差:一旦写死,当前想改变下输入的 HTML 可就麻烦了,须要把所有文章都扫一遍,本博客就遇到过须要改变渲染后果的状况。
  • 可读性差:Markdown 作为轻量级标记语言,扫一眼即可轻松 Parse 是其一大劣势,一旦混入重量级的 HTML 则可读性大打折扣。

这毛病太多,所以我决定还是得用 Markdown 的形式来做。

GitLab Flavored Markdown

GitLab Flavored Markdown(下称 GFM)是 Markdown 的一种修改版,它复用了图片的语法,以扩展名来辨别媒体的类型,比方 ![label](foobar.mp4) 因为链接是 .mp4 结尾所以渲染为视频。

GFM 的反对也很宽泛,实现又简略,还有 GitLab 背书,天然也是个不错的抉择。

但它的毛病也很显著,强制了链接的文件名必须是视频罕用的扩展名,然而并不是所有链接都是如此,Twitter 的视频链接就没有扩展名。另外既然都批改了原始的 Markdown 语义,何不间接另起一个新语法呢?

本人编个语法

对于自定义的语法有很多探讨,我认为比拟好的一种是应用通用指令语法,它的格局是 @< 指令类型 >[...](..){...} 这样的,后面的 @能够换成别的,指令类型用于辨别视频、音频、GIF 视频等,前面三个括号里的内容能够自由发挥。

最终我决定应用这种语法,它跟原生的图片语法一样简洁,又给足了自由发挥的余地。

通常来说,新的语法最好还是跟现有的放弃类似,这里就以语法比拟像的图片为基准。圆括号依然跟图片一样蕴含视频的链接,方括号里填标签(GIF)或者 poster(视频)。

通用指令语法里,花括号用来搁置 key = "val" 这样的键值对,但它们同样能够放在链接 URL 的参数上,而且目前图片就是这么做的,为了保持一致,我抉择不要这个花括号局部。

指令类型蕴含 GIF 视频和一般视频,另外 Markdown 同样不反对插入音频这里也给补上,所以最终的语法为:

  • @audio[](音频链接) 插入一个音频。
  • @gif[标签](视频链接) 插入视频,并尽可能模拟 GIF 图。
  • @video[视频封面](视频链接) 插入一般视频。

解析器的实现

我的博客应用 markdown-it 来转换 Markdown 为 HTML,markdown-it 的流程分为解析和渲染两局部,所以要给这两个中央编写本人的函数实现。

首先是怎么辨认 @< 指令类型 >[...](..) 这种文本呢,如果不思考本义的话倒是一个正则就能搞定,但问题是如果标签里呈现了方括号,或者链接里有圆括号咋办?当然是要本义了,Markdown 对括号的本义形式有两种:配对计数和斜杠本义,其中配对计数须要一个变量来存储左括号数量挺麻烦,而且斜杠本义齐全能用于所有场景,但反过来配对计数却无奈用于右括号独自呈现的状况(尽管不常见)。

综上所述,我决定不反对计数了,斜杠本义用一个前向环视 (?<!\\) 就能解决,再给指令局部加点限度,最初的正则如下:

  • 指令局部:([a-z][a-z0-9\-_]*)
  • 标签局部:\[(.*?)(?<!\\)]
  • 链接局部:\((.*?)(?<!\\)\)

把它们三个连起来就能够匹配通用指令语法啦。

Markdown 有块 block 和行内 inline 两种构造,原始的图片语法是属于行内的,这能够实现图文混排,但在应用中发现我并没有图文混排的需要,我博客里的图片都是独自一行。所以我决定新的语法作为块构造,这样能够升高解析函数被调用的频率,晋升点性能。

最初要留神一下的是反本义和 XSS 查看,这些函数在 markdown-it 库里已有提供。

解析器代码见 kaciras-blog/web-server/packages/server/lib/markdown-media.ts

不同的渲染指标

Markdown 渲染进去的 HTML 是跟场景相干的,比方在 RSS 里渲染的后果应尽量简略,毕竟阅读器的款式是没法由我来管制的;而在我的博客网站里,会有一些额定的款式和元素来展示更好的成果,比方提前固定宽高比避免布局挪动、居中等。

在我的博客,GIF 视频通过暗藏控制面板、静音、给上面加标签、以及 IntersectionObserver 实现的自动播放 / 暂停,实现了跟 GIF 图片一样的成果。另外因为 RSS 阅读器不会加载我的博客的样式表,也不会运行 JS,所以 RSS 阅读器里的 GIF 视频只能跟一般视频一样。

除了这俩之外,我还筹备让评论零碎也应用 Markdown(暂未实现),这又是一个新的渲染指标,用户评论属于第三方输出,对其的渲染必须退出一些限度以防滥用。

对无法控制的前端,渲染实现跟解析器写在一起,见下面的链接。

我博客的渲染实现见 kaciras-blog/website/blob/master/src/markdown/media.js

最终成果

SegmentFault 不反对插入视频,所以这里展现不了,能够去我的博客里看成果:

https://blog.kaciras.com/article/18/add-video-support-to-markdown# 最终成果

退出移动版