Skyphobia

随便记俩坑:在 react 中集成 reveal.js 和其 markdown 插件

Front-EndReactreveal.jsmarkdown

这两天在帮公司的前端文档工具做一个基于 reveal.js 的在线 slides 扩展功能,由于文档的核心渲染和编辑用的是 rich-markdown-editor 这个库,而这个库又依赖的是 react。一来二去,结果就是要把 reveal.js 集成到这个 react 项目中。

当你参照文档创建好 markup 的结构,随后照着 react 的提示把 markdown 文本通过 defaultValue 塞进 textarea 标签,本以为大功告成的时候就一定会碰到 reveal.js 傻呵呵地以为 data-markdown 塞了个需要远程访问的值,然后跑去远程请求,结果发现啥都请求不到的问题。

去掏了下 reveal.js 的源码,markdown 插件里对是否需要远程请求的判断是根据 getAttribute('data-markdown').length 是否 > 0 来判断的。react 的属性缺省值都是 true,对于 reveal.js 来说这个长度就是 4,于是就非常人性化地替你往 http://xxxxx/true 去请求了……

解决方案就是手动把 data-markdown 设置为空字符串:

HTML
01<div className="reveal">
02 <div className="slides">
03 <section data-markdown="">
04 <textarea data-template="" defaultValue={content} />
05 </section>
06 </div>
07</div>

我的博客背后是利用 vite-plugin-ssr + react ,以及一些第三方 api 生成的纯静态页面,也就是俗称的 JAMStack 架构。这个博客在集成 reveal 的时候还碰到了一些问题:

ReferenceError: navigator is not defined

这个明显是由于服务端渲染时,node 环境中没有 reveal.js 所需要的 navigator 对象造成的。这东西又不需要在服务端渲染,把 reveal.js 的引入时机改到客户端就是了。useEffect 反正肯定是客户端执行的,在这里动态 import reveal.js 和其插件后顺带运行就是了:

JavaScript
01useEffect(() => {
02 Promise.all([
03 import('reveal.js/dist/reveal.esm'),
04 import('reveal.js/plugin/markdown/markdown.esm')
05 ]).then(([Reveal, Markdown]) => {
06 const deck = new Reveal.default()
07 deck.initialize({
08 plugins: [Markdown.default]
09 })
10 })
11}, [])