はじめに
技術ブログやドキュメントにコード例を載せたとき、「これ、その場で動かして試せたらいいのに」と思ったことはありませんか?読者はコードをコピーして、エディタに貼り付けて、環境を整えて……とハードルを越えないと動作を確認できません。かといってCodePenやJSFiddleへのリンクを貼ると、読者はページの外へ出て行ってしまいます。
そんな悩みを解決してくれるのが、今回紹介するLiveCodesです。オープンソースのコードプレイグラウンドで、自分のWebページに直接埋め込めて、しかも90以上の言語・フレームワークに対応しています。実行はすべてブラウザ内で完結するため、サーバーを用意する必要すらありません。
説明を読むより、実際にcreatePlaygroundが動く様子を見た方が早いと思います。この記事自体もLiveCodesの上に構築されているので、まずは埋め込みプレイグラウンドを触ってみてください。
LiveCodesとは
LiveCodesは「A Code Playground That Just Works!(ちゃんと動くコードプレイグラウンド)」を掲げるオープンソースプロジェクトです。TypeScriptで開発されており、MITライセンスで公開されています。
興味深いのは、CodePenやJSFiddleといった既存サービスと「競争する」のではなく、「統合される」ことを目指している点です。スタンドアロンのアプリとして使うこともできますが、真価を発揮するのはSDKを使って自分のサイトやドキュメントに埋め込んだときです。
主な特徴
- 90以上の言語・フレームワークに対応 - JavaScript/TypeScriptはもちろん、React・Vue・Svelte、さらにPython・Go・Ruby・PHPまでブラウザ上で動きます
- 完全クライアントサイド実行 - コードの実行はすべてブラウザ内で完結します。バックエンドサーバーもデータベースも不要です
- 設定不要ですぐ使える - インストールもビルドステップも設定ファイルもなしで、npmモジュールのインポートまで動きます
- 強力なSDK - JavaScript/TypeScriptに加えて、React・Vue・Svelte用のコンポーネントが用意されており、数行で埋め込めます
- セルフホスト可能 - オープンソースなので、自社ドキュメント用に自前でホスティングすることもできます
インストール
SDKはnpmパッケージとして公開されています。お使いのパッケージマネージャーでインストールしてください。
# npm
npm install livecodes
# yarn
yarn add livecodes
# pnpm
pnpm add livecodes
# bun
bun add livecodes
ビルド環境を使わない場合は、CDNから直接読み込むこともできます。
<script type="module">
import { createPlayground } from 'https://cdn.jsdelivr.net/npm/livecodes';
</script>
LiveCodesのサンプルを動かす
下の枠はcreatePlaygroundで埋め込んだ、実際に動くLiveCodesのプレイグラウンドです。セレクトボックスで言語を切り替えると、playground.setConfig()を使ってエディタとコンソールの中身がその場で入れ替わります。JavaScript・Python・TypeScriptのどれを選んでも、コンパイルや実行系のインストールなしにブラウザだけで結果が出ることを確認してください。
コアになっているのは次の部分です。createPlaygroundにコンテナとconfigを渡してプレイグラウンドを生成し、以降はsetConfigで表示中のコードを差し替えています。
import { createPlayground } from 'livecodes@0.14.1';
const playground = await createPlayground('#container', {
config: {
activeEditor: 'script',
script: { language: 'javascript', content: 'console.log("Hello")' },
tools: { active: 'console', status: 'open' },
},
});
// 表示中のスクリプトを差し替える(言語ごと入れ替え可能)
await playground.setConfig({
script: { language: 'python', content: 'print("Hola")' },
});
実際にセレクトボックスで言語を切り替えられるサンプルが以下です。
セレクトボックスで「Python」を選ぶと、script.languageがpythonに切り替わり、エディタの構文ハイライトとコンソールの出力言語が同時に変わります。samplesオブジェクトのキーを増やせば、Rust・Go・PHPなど他の対応言語もワンクリックで試せます。
基本的な使い方
もっともシンプルな例から始めましょう。createPlayground にコンテナのセレクタとオプションを渡すだけで、プレイグラウンドが埋め込まれます。
<div id="container"></div>
<script type="module">
import { createPlayground } from 'https://cdn.jsdelivr.net/npm/livecodes';
createPlayground('#container', {
config: {
markup: {
language: 'html',
content: '<h1 id="title">Hello, LiveCodes!</h1>',
},
style: {
language: 'css',
content: 'h1 { color: steelblue; }',
},
script: {
language: 'javascript',
content: 'console.log(document.querySelector("#title").textContent);',
},
tools: { active: 'console', status: 'open' },
},
});
</script>
これだけで、HTML・CSS・JavaScriptの3つのエディタと実行結果、そしてコンソールまで表示されます。読者はその場でコードを書き換えて、即座に結果を確認できます。
プレイグラウンドをコードから操作する
createPlayground はPromiseを返し、解決されるとplaygroundオブジェクトが得られます。これを使うと、埋め込んだプレイグラウンドを外部から操作できます。
import { createPlayground } from 'livecodes';
const playground = await createPlayground('#container', {
config: {
script: {
language: 'typescript',
content: 'const greet = (name: string) => `Hello, ${name}!`;',
},
},
});
// コードを実行する
await playground.run();
// 現在のコードを取得する(コンパイル結果も含まれます)
const code = await playground.getCode();
console.log(code.script.content);
// コードの変更を監視する
playground.watch('code', ({ config }) => {
console.log('コードが更新されました');
});
getCodeはヘッドレスモードと組み合わせると、UIなしでコンパイル結果だけを取り出す用途にも使えます。TypeScriptのソースを書き換えてボタンを押すと、getCodeが返すcompiled.content(=コンパイル済みJavaScript)がその場で表示されるサンプルです。
テキストエリアの型注釈(name: string)を消してgreet = (name) => `Hello, ${name}`;にすると、コンパイル結果から型情報だけが取り除かれてプレーンなJavaScriptになるのが分かります。destroy()を呼んでいるのは、クリックのたびにヘッドレスインスタンスを使い捨てにして後始末するためです。
実践的なユースケース
Reactアプリのドキュメントに組み込む
Reactプロジェクトなら、専用コンポーネントを使うのが手軽です。ライブラリのドキュメントサイトに「試してみる」セクションを作る例を見てみましょう。
import LiveCodes from 'livecodes/react';
export default function TryItSection() {
const options = {
config: {
activeEditor: 'script' as const,
script: {
language: 'jsx',
content: `import { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
クリック回数: {count}
</button>
);
}
export default Counter;`,
},
},
};
return (
<section>
<h2>試してみる</h2>
<LiveCodes {...options} height="400px" />
</section>
);
}
VueやSvelteにも同様のコンポーネント(livecodes/vue、livecodes/svelte)が用意されているので、どのフレームワークでも同じ感覚で使えます。
JavaScript以外の言語のチュートリアルに使う
LiveCodesの大きな強みは、PythonやRubyのようなJavaScript以外の言語もブラウザ内で動くことです。たとえばPythonのチュートリアル記事に、実行可能なサンプルを埋め込めます。
createPlayground('#python-demo', {
config: {
activeEditor: 'script',
script: {
language: 'python',
content: `def fizzbuzz(n):
for i in range(1, n + 1):
if i % 15 == 0:
print("FizzBuzz")
elif i % 3 == 0:
print("Fizz")
elif i % 5 == 0:
print("Buzz")
else:
print(i)
fizzbuzz(15)`,
},
tools: { active: 'console', status: 'full' },
},
});
言語処理系のインストール手順を説明する必要がなくなるため、チュートリアルの導入ハードルが大きく下がります。
実際にNの値を変えて動かせるサンプルが以下です。数値入力を変更すると、playground.setConfig()でPythonのスクリプトを組み立て直し、playground.run()で再実行してコンソールの出力を更新します。
入力欄の数値を100に増やすと、コンソールに流れるFizzBuzzの行数がそのまま増えるのが分かります。Pythonのコードを一切ローカルにインストールせずに、ブラウザ内だけでfizzbuzz関数が実行されている点がポイントです。
ヘッドレスモードでコード実行基盤として使う
UIを表示せず、コードのコンパイル・実行機能だけを利用する「ヘッドレスモード」もあります。たとえば、自作のエディタUIと組み合わせて、コンパイル処理だけLiveCodesに任せるといった使い方ができます。
const playground = await createPlayground({
view: 'headless',
config: {
script: { language: 'typescript', content: 'const x: number = 42;' },
},
});
const code = await playground.getCode();
// TypeScriptからコンパイルされたJavaScriptを取得できます
console.log(code.script.compiled.content);
コンパイルもブラウザ内で完結するので、実行用のサーバーを立てる必要がありません。
まとめ
LiveCodesは、「コード例を読ませる」から「コード例を動かしてもらう」への転換を、驚くほど簡単に実現してくれるツールです。ポイントを振り返りましょう。
- 90以上の言語・フレームワークがブラウザ内だけで動く、完全クライアントサイドのプレイグラウンド
createPlaygroundの1関数、あるいはReact/Vue/Svelteコンポーネントで自分のページに埋め込めるrunやgetCodeなどのSDKメソッドで外部から操作でき、ヘッドレスモードならコード実行基盤としても使える- MITライセンスのオープンソースで、セルフホストも可能
技術ブログ、ライブラリのドキュメント、社内のチュートリアル資料など、「動くコード例」が価値を生む場面は数多くあります。まずは公式サイトのプレイグラウンドを触ってみて、その手軽さを体感してみてください。