デザインシステムのUIプロトタイピング環境としてPlayroomを試す
はじめに
Chakra UIやTailwind CSSなど、人気のあるUIフレームワークが持つブラウザー上のPlayground環境は、ユーザーがローカルに環境を用意することなくUIフレームワークを試すことができる。
自身でデザインシステムのコンポーネントライブラリーを開発する場合にこのようなPlayground環境があると、そのコンポーネントを用いたプロトタイピングが可能になり良いかなと思うけど、
それを実現できるツールとしてPlayroomを試してみる。
Playroomとは
Design with JSX, powered by your own component library.
Playroomとは、seekというオーストラリアの企業のOSSの1つで、端的には「コンポーネントライブラリーを用いてJSXでデザインする」ツール。
最近登場したツールというわけではなく、数年前から開発されている。
コンポーネントライブラリーのコンポーネントを全てPlayroomで利用可能な状態にしておくことで、ブラウザーさえあれば、プロダクトで利用される実際のコンポーネントを用いて高速にプロトタイピングできる。
どのようなツールか理解するのに、以下デモのgifが分かりやすい。
複数のスクリーンサイズで表示確認しながらJSXを記述することができて、その結果に合わせてURLが生成される。そのため、Playroomを共有可能な環境へホスティングしておけば、プロトタイピングの結果を他者と共有することも可能になる。
なお、ソースコードを眺めると、CodeMirrorを利用してブラウザー上でのエディターとライブプレビューを実現していると考えられる。
試す
プロジェクトを作って、GitHub Pagesにデプロイするところまでを試してみる。
プロジェクトを作成してローカルで動かす
まずViteでプロジェクトを作る。
❯ pnpm create vite
.../Library/pnpm/store/v3/tmp/dlx-2072 | +1 +
.../Library/pnpm/store/v3/tmp/dlx-2072 | Progress: resolved 1, reused 1, downloaded 0, added 1, done
✔ Project name: … try-playroom
✔ Select a framework: › React
✔ Select a variant: › TypeScript + SWC
Scaffolding project in /path/to/try-playroom...
Done. Now run:
cd try-playroom
pnpm install
pnpm run dev
プロジェクトを作成し終わったら、pnpm i
を実行して依存ライブラリーを追加しておく。
playroom
をpnpm add -D
でプロジェクトのdevDependencies
に追加する。
❯ pnpm add -D playroom
WARN 1 deprecated subdependencies found: @types/lz-string@1.5.0
Packages: +609
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Progress: resolved 810, reused 767, downloaded 0, added 0, done
devDependencies:
+ playroom 0.34.2
Done in 8.9s
package.json
のscripts
にplayroom:start
とplayroom:build
コマンドを追加する。
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview",
+ "playroom:start": "playroom start",
+ "playroom:build": "playroom build"
},
playroom.config.js
ファイルを作って、設定を記述する。
必須の項目はcomponents
とoutputPath
のみ。
export default {
components: './src/components/index.ts', // Playroomで利用するコンポーネントがexportされているファイル
outputPath: './dist/playroom', // Playroomのビルド結果を出力するパス
}
設定できる項目については、READMEに記載がある。より詳細には、以下の型定義を参照すると良いかもしれない。
試す用のコンポーネントを用意するため、今回はdaisyUIを用いる。daisyUIはTailwind CSSベースのコンポーネントライブラリー。
まず、Tailwind CSSを公式の案内に従ってセットアップする。
❯ pnpm add -D tailwindcss postcss autoprefixer
WARN 1 deprecated subdependencies found: @types/lz-string@1.5.0
Packages: +20
++++++++++++++++++++
Progress: resolved 830, reused 787, downloaded 0, added 20, done
devDependencies:
+ autoprefixer 10.4.17
+ postcss 8.4.33
+ tailwindcss 3.4.1
Done in 2.3s
❯ pnpm dlx tailwindcss init -p
Packages: +106
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Progress: resolved 106, reused 106, downloaded 0, added 106, done
Created Tailwind CSS config file: tailwind.config.js
Created PostCSS config file: postcss.config.js
/** @type {import('tailwindcss').Config} */
export default {
content: [
+ "./index.html",
+ "./src/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}
+ @tailwind base;
+ @tailwind components;
+ @tailwind utilities;
次にdaisyUIをインストールする。
❯ pnpm add -D daisyui
WARN 1 deprecated subdependencies found: @types/lz-string@1.5.0
Packages: +4
++++
Progress: resolved 834, reused 791, downloaded 0, added 4, done
devDependencies:
+ daisyui 4.6.0
Done in 1.7s
plugins
にdaisyui
を追加する。
+ import daisyui from 'daisyui'
/** @type {import('tailwindcss').Config} */
export default {
content: [
"./index.html",
"./src/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {},
},
- plugins: [],
+ plugins: [daisyui],
}
ViteでビルドしたCSSファイルをPlayroomで利用したいけど、ユニークなハッシュが付与されたファイル名になっているとその指定が難しい。
そのため、キャッシュバスティングを無効にするように設定する。
export default defineConfig({
plugins: [react()],
+ build: {
+ rollupOptions: {
+ output: {
+ assetFileNames: 'assets/[name].[ext]'
+ }
+ }
+ }
})
ViteでビルドしたCSSをPlayroomで読み込めるように、loaderを追加する。
❯ pnpm add -E -D css-loader style-loader
WARN 1 deprecated subdependencies found: @types/lz-string@1.5.0
Packages: +1
+
Progress: resolved 829, reused 795, downloaded 0, added 1, done
devDependencies:
+ css-loader 6.10.0
+ style-loader 3.3.4
Done in 1.9s
export default {
components: './src/components/index.ts', // Playroomで利用するコンポーネントがexportされているファイル
outputPath: './dist/playroom', // Playroomのビルド結果を出力するパス
+ webpackConfig: () => ({
+ module: {
+ rules: [
+ {
+ test: /\.css$/i, // iがないと動かなかった 🤔
+ exclude: /node_modules/,
+ use: [
+ 'style-loader',
+ 'css-loader',
+ ],
+ }
+ ],
+ },
+ }),
}
Playroomのサーバーを動かす前にViteでビルドするようにplayroom:start
の内容を書き換える。
- "playroom:start": "playroom start",
+ "playroom:start": "pnpm run build && playroom start",
- "playroom:build": "playroom build"
+ "playroom:build": "pnpm run build && playroom build"
playroom:build
の方も事前にViteのビルドが必要なことは同じなので、合わせて変更する。
tsxを解釈できるようにloaderなどを追加する。
❯ pnpm add -E -D babel-loader @babel/preset-env @babel/preset-react @babel/preset-typescript
WARN 1 deprecated subdependencies found: @types/lz-string@1.5.0
Already up to date
Progress: resolved 829, reused 795, downloaded 0, added 0, done
devDependencies:
+ @babel/preset-env 7.23.9
+ @babel/preset-react 7.23.3
+ @babel/preset-typescript 7.23.3
+ babel-loader 9.1.3
Done in 3.7s
rules: [
+ {
+ test: /\.tsx?$/,
+ exclude: /node_modules/,
+ use: [
+ {
+ loader: 'babel-loader',
+ options: {
+ presets: [
+ '@babel/preset-env',
+ ['@babel/preset-react', { runtime: 'automatic' }],
+ '@babel/preset-typescript'
+ ],
+ },
+ },
+ ],
+ },
後は、UIコンポーネントを作ってplayroom.config.js
のcomponents
で設定したsrc/components/index.ts
においてコンポーネントをexport
するだけ。
export { Button } from './Button'
export { Link } from './Link'
export { Card } from './Card'
.
.
.
ひとまず試すだけなのでコンポーネントの実装は適当な形で行う。
import { PropsWithChildren } from "react";
export const Button = ({children}: PropsWithChildren) => (
<button className="btn">{children}</button>
)
このままだとCSSファイルが読み込めないので、frameComponent
のオプションで外枠となるコンポーネントを用意して、ViteでビルドしたCSSを読み込むようにする。
frameComponent
オプションは、Providerコンポーネントで全体を囲いたいときなどに有用なもの。
components: './src/components/index.ts', // Playroomで利用するコンポーネントがexportされているファイル
outputPath: './playroom', // Playroomのビルド結果を出力するパス
+ frameComponent: './.playroom/Frame.tsx',
import React, { PropsWithChildren } from "react";
import '../dist/assets/index.css'
export default ({children}: PropsWithChildren) => (
<div>{children}</div>
)
以上でローカル環境においてPlayroomを動かすことが出来る。npm run playrom:start
すればhttp://localhost:9000/
で確認可能となる。
GitHub Pagesへデプロイ
GitHub Pagesへのデプロイは、GitHub Actionsから行う。
以下の通り、ワークフローのファイルを用意しておけば、main
ブランチへpush
したらワークフローが動いてデプロイされる。
name: Deploy Playroom
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Set up pnpm
uses: pnpm/action-setup@v2
with:
version: 8
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: 20
- name: Install dependencies
run: pnpm i
- name: Build Playroom
run: pnpm run playroom:build
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./playroom
pnpm i
で依存ライブラリーをインストールして、ViteとPlayroomのビルドを行い、そのビルド成果物をpeaceiris/actions-gh-pagesでGitHub Pagesへデプロイするというだけの流れ。
なお、該当のGitHubリポジトリーでGitHub Pagesのブランチ設定はgh-pages
ブランチを利用するようにしておく。
今回は以下のGitHubリポジトリーにおいたので、デプロイは https://makotot.github.io/try-playroom へ行われる。
Storybook
UIコンポーネント開発ツールとしては、Storybookが非常に多くの機能を持っていると思う。ただ、把握している限り、Storybook自体にはPlayroomのようなブラウザー上でプロトタイピングできるような機能がない。コンポーネントのパラメーターの値の変更はControlsアドオンで可能であるものの、公式のアドオンでよりPlayroomに類似するものは見当たらない。
Playroom自体をStorybookで利用できるようにしたアドオンは、個人で開発されているものがある。
まとめ
1通りの流れを適当なコンポーネントを用意して試しただけではあるものの、環境を用意してなくてもブラウザーだけで高速に実現したいUIを試作したり、それを共有したり、有効活用できそうなイメージが持てた。
ただ、何をやるにもある程度コンポーネントがないと作れないので、コンポーネントが充実していないのであれば、まずその整備が必要になる。コンポーネントライブラリーとしてコンポーネント不足を明らかにする1つの手段としても考えられるかもしれない。
Discussion