参考 react-live,如何实现代码在线预览?

Last Updated: July 4, 2022 · 11 min read

目前很多平台都支持嵌入 CodeSandbox、StackBlitz 等第三方在线代码运行平台,仅仅通过一个 iframe 标签就可以完成,这个当然是很方便的,不过有时候我们只是想展示一些轻量级代码,再加上经常网络抽风,还需要我们维护一堆仓库,不知道哪天自己手抖就删了,导致文章中 demo 效果无法展示。那么有没有可能我们自己实现这种在线运行的功能呢,答案当然是可以。

应该提供哪些主要功能 🤔

编辑器组件应该与预览组件分离,给予用户只使用编辑器的机会,单独使用编辑器时就是一个普通的代码高亮展示组件,所以提供两个单独组件。为了方便我们代码中编辑器组件与预览组件跨组件交换数据,我们再额外提供一个 Provider 组件,该组件负责为编辑器组件与预览组件包裹一个 ContextProvider,我们的配置都通过 Provider 组件传入,大致写法结构如下:

tsx
  • Provider 组件
    • ContextProvider 的再包装,用于 Editor 与 Preview 的跨组件通讯
    • 负责传入参数配置
  • Editor 组件
    • 支持代码高亮
    • 代码更新后同步到 Context 中
  • Preview 组件
    • 从 Context 中读取最新代码
    • 需支持 react 组件预览
    • 除此之外,我还需要支持原生 html 的预览

Provider 组件

上边说 Provider 负责参数的统一传入,让我们看一下具体实现

tsx

编辑器组件

编辑器组件仅负责代码录入不负责代码编译,只需要保证有代码可编辑可高亮,编辑功能我这里使用了 react-simple-code-editor,它是一个轻量级编辑器,或者也可以使用 use-editable,这里就不具体进行了,代码高亮这块使用了 prism-react-renderer,两者结合便可以实现一个基本的编辑器组件。

tsx

效果预览

007zq4ODly1h34ibj6xssj30lo09qtax

截止到这里,我们已经实现一个代码高亮组件了,如果目标只是如此,你就可以不继续往下看了,当然我们目标应该不只如此,接下来考虑预览组件怎么做。

预览组件

预览组件相对 Editor 而言比较复杂,我们要考虑多种语言的情况,考虑下边一串代码,如何才能编译成一个 react 组件?

tsx

不只 jsx 语法,我还要支持原生 html,为了代码可扩展性,首先让我们把 Preview 组件细分一下再考虑具体不同语言的编译。

jsx

在上边组件中我们根据 Context 提供的 language 选项渲染出对应不同组件,接下来先看最麻烦的 react 怎么渲染。

渲染 react

要实现运行时渲染 jsx 语法,我们需要借助 sucrase,它可以在浏览器环境对代码进行快速编译,更多使用方式可以参考官方文档。

tsx

渲染 html

上边我们介绍了如何预览 react 代码,那我如果我想预览一些 html 代码呢?这个相比渲染 jsx 就简单多了。最简单方式是使用 dangerouslySetInnerHTML 将 html 文本设置进一个元素,例如 <div dangerouslySetInnerHTML={{ __html: "&lt;span&gt;hello&lt;/span&gt;" }}></div>,但是这种方式局限性太大,不适用完整的 html 标签,也没有 window.onload 等一系列事件 ,所以我考虑使用 iframe 来达成这个需求,我们知道 iframe 需要一个 src url,大家是不是以为我们必须把代码转化为可访问 url 才行?我一开始也是这么想的,初版使用的 createObjectURL 方式生成了一个 url,不过后边发现其实有更简单的方式,那就是使用 srcCode 属性,直接将代码传入就行。。。

tsx

效果预览

007zq4ODly1h34gw134djg30ls0a412h

结尾

如上代码只是对 react-live 的拙略模仿,并且为了教程清晰有意删减了很多功能,例如 ErrorBoundrynoInline,推荐各位有条件可以直接阅读源码,很简短。🥹 下篇文章我将记录一下如何在 nextjs 中使用 markdown,并且在 markdown 中嵌入 react-live 组件。

参考


©2022xiaojun1994
 0   0