🧭

Reactコンポーネントのライブサンプルをwebページに埋め込む: React Runner

2022/05/27に公開

最近Reactコンポーネントライブラリを作った。その際に、このライブラリで何ができるのかがサンプルコードとともに一目でわかるようなデモページを同時に作りたくなった。

実際のページは以下のようになった。サンプルコードがセットされたコードエディタと、ライブラリのReactコンポーネントのレンダリング結果が横に並んだ形。これが他の要素と共にwebページに埋め込まれている。

react-ymd-date-selectのデモページ

TL;DR

これを作るにあたって、 今回に関してはReact Runnerがベストだった。 比較対象は以下。

  • React Live
    • サンプルコード中で import を使えない
  • Sandpack (@codesandbox/sandpack-react)
  • Webpackのraw-loaderのようなバンドラの機能を使ってビルド時に埋め込む
    • これだけでは編集可能なサンプルは作れない(作るなら結局上のようなライブラリが必要)
    • 以下の例のように一つのサンプルごとにインポートが2つ必要になって冗長
      import SampleComponent from "./components/Sample"
      import SampleComponentCode from "./components/Sample?raw"
      
      ...
      
      <LivePreview
        component={SampleComponent}
        code={SampleComponentCode}
      />
      

要件・状況

  • Reactコンポーネントのサンプルコードと実行結果を隣り合わせに表示したい
    • ユーザが動的に編集できるとなお良い
  • これらのサンプル集は同時にE2Eテストとしても利用したい。なので、各サンプルは単体で実行可能な形であってほしい
    • 具体的には、各サンプルそれぞれが必要なパッケージをimportし、サンプルコンポーネントをexportする。
  • デモサイトはReactで作る
  • 対象のライブラリもReact用のもの。なのでサンプルコードもReactで書かれる(JSXがある)
  • TypeScriptも使う

比較

React Runner

React Runner が上記の全てのニーズを満たした。

サンプルコードがimportする可能性のあるパッケージは予めバンドルしておく必要があるので、バンドルサイズが大きくなるのが欠点。当たり前のことなのでしょうがないが。初回ロードサイズはCode Splittingなどでうまいことできるかもしれない。
一番最初にロードされるサイズで比較すると、下記のSandpackの方が良いかもしれない。

React Live

React Live

今回のような目的のためには人気のあるライブラリ。例えばChakra UIのドキュメントは下記のようなeditable examplesにこれを使っている。

またReact Runner の作者は React Live にインスパイアされたと書いている。その生い立ち、設計からして、React RunnerがReact Liveの上位互換といえそう。

サンプルコード中にimportを書けないためReact Liveの採用は見送った。これはReact Runnerはサポートしている。

Sandpack

有名なオンラインコードエディタ CodeSandbox のコンポーネントライブラリ。

今回のプロジェクトはReactベースなので、React用の @codesandbox/sandpack-react が候補になる。

これは素晴らしいライブラリなのだが、サンプルコード中でのネストされたパスからのimport(import Something from "package/subpath"のような)に対応していない。
https://github.com/codesandbox/codesandbox-client/issues/6499

ESMだけをターゲットにするなら問題はないと思うし、今後はそう言う流れとは思うが、一応今回のライブラリはCommonJS用にもビルドしてあり、そのサンプルを見せたかったのでSandpackは見送った。

この制約が問題にならないなら、Sandpackがベストになりうる。

ビルド時にサンプルを埋め込む

Webpackのraw-loaderやViteの?raw queryのように、バンドル時に対象ファイルを文字列として読み込むバンドラの機能を利用する方法。

こうすると普通のReactソースコードを管理するのと同じにサンプルコードも独立した*.jsx, *.tsxファイルとして書けて手軽で良い。

// Sample.tsx

function SampleComponent() {
  return (
    <div>This is a sample</div>
  )
}

export default SampleComponent;
// DemoSite.tsx

import SampleComponent from "./components/Sample"
import SampleComponentCode from "./components/Sample?raw"

...

export default function() {
  ...
  return (
    ...
    <LivePreview
      component={SampleComponent}
      code={SampleComponentCode}
    />
    ...
  )
}

しかし1サンプルに2つのimportが必要になって冗長になる。

また、webページ上で動的に編集する機能はこの方法単体では作れない。


英語版: https://dev.to/whitphx/a-library-for-editable-live-samples-of-react-components-react-runner-105o

Discussion