Reactコンポーネントのライブサンプルをwebページに埋め込む: React Runner
最近Reactコンポーネントライブラリを作った。その際に、このライブラリで何ができるのかがサンプルコードとともに一目でわかるようなデモページを同時に作りたくなった。
実際のページは以下のようになった。サンプルコードがセットされたコードエディタと、ライブラリのReactコンポーネントのレンダリング結果が横に並んだ形。これが他の要素と共にwebページに埋め込まれている。
react-ymd-date-select
のデモページ
TL;DR
これを作るにあたって、 今回に関してはReact Runnerがベストだった。 比較対象は以下。
-
React Live
- サンプルコード中で
import
を使えない
- サンプルコード中で
-
Sandpack (
@codesandbox/sandpack-react
)- ネストしたパスのimportが使えない(
import Something from "package/subpath"
のような)
- ネストしたパスのimportが使えない(
- 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
今回のような目的のためには人気のあるライブラリ。例えば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"
のような)に対応していない。
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