Ateam LifeDesign Advent Calendar 2022(カレンダー2)の8日目は
株式会社エイチームライフデザインの@oekazumaが担当します。
whyframeとは
whyframeを使えば、Svelte、Vue、Solid、Preact、Reactなど、あらゆるUIフレームワークのマークアップをiframe内でレンダリングすることができます。
どういうことをしたい場合に使うと便利か?
- 実際の使用例を示したコンポーネントライブラリのドキュメントを作りたい
- コンポーネントの使用例を埋め込む記事を書きたい
- StoryBookのようなものを作りたい
使い方
※今回はSvelte + Viteの例で使い方を紹介します。
他の構成で試したい場合は公式ドキュメントを参照ください。
インストール
まず、新しいプロジェクトを作成して、依存関係をインストールします。
$ npm create vite@latest whyframe-demo -- --template svelte
$ cd whyframe-demo
$ npm install
次にwhyframe
を使うために必要なパッケージをインストールします。
$ npm install -D @whyframe/core @whyframe/svelte
執筆時のバージョン
- @whyframe/core: 0.1.9
- @whyframe/svelte:0.1.5
設定
vite.config.js
に設定を記述していきます。
注意
whyframe
はコンパイル済みコードではなく生のフレームワークコードを前処理する必要があるのでwhyframeSvelte()
はsvelte()
の前に必ず記述するようにしてください。
import { defineConfig } from 'vite';
import { svelte } from '@sveltejs/vite-plugin-svelte';
+ import { whyframe } from '@whyframe/core';
+ import { whyframeSvelte } from '@whyframe/svelte';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
+ whyframe(),
+ whyframeSvelte()
svelte(),
],
});
使い方
App.svelte
に以下のようにコードを書きます。
<iframe>
にdata-why
を加えるだけでiframe内にマークアップをレンダリングすることができます。
<iframe data-why>
Hello World!
</iframe>
ちゃんとHello World!が表示されてます!
次は、コンポーネントを表示してみましょう。
ポップアップのコンポーネントを作って表示してみます。
Popup.svelteのコード
<script>
export let content;
let open = false;
</script>
<button
class="activator"
aria-haspopup="dialog"
on:click={() => (open = !open)}
>
<slot />
</button>
{#if open}
<button class="background" on:click={() => (open = false)}>
<p>{content}</p>
</button>
{/if}
<style>
.activator {
display: block;
border-radius: 8px;
border: 1px solid transparent;
padding: 0.5em 1em;
font-size: 0.9em;
font-weight: 500;
font-family: inherit;
color: #efefef;
background-color: #1e1e1e;
cursor: pointer;
transition: border-color 0.25s;
}
.activator:hover {
border-color: #ffed24;
}
.activator:focus,
.activator:focus-visible {
outline: 4px auto -webkit-focus-ring-color;
}
.background {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
border: 0;
background-color: #090909;
color: #efefef;
font-size: 1.5rem;
opacity: 0.8;
z-index: 1;
display: flex;
justify-content: center;
align-items: center;
}
.background:focus,
.background:focus-visible {
border: 4px solid #ffed24;
}
</style>
<script>
import Popup from './Popup.svelte'
const content = 'Hoozah!'
</script>
<iframe data-why>
<Popup {content}>Open</Popup>
</iframe>
ポップアップが表示され、動作も確認できました!
コンポーネントにpropsもきちんと渡せています。
HTMLソースを変更する
whyframe
でレンダリング時に使用するHTMLソースを指定して変更することができます。
別のHTMLを作成して、HTMLソースを変更してみます。
other.htmlのコード
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Whyframe - Other</title>
<style>
*,
*::before,
*::after {
box-sizing: border-box;
}
html,
body {
font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
width: 100%;
height: 100%;
padding: 0;
margin: 0;
}
body {
background-color: #2b2b2b;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' viewBox='0 0 100 100'%3E%3Cg fill-rule='evenodd'%3E%3Cg fill='%239e9e9e' fill-opacity='0.4'%3E%3Cpath opacity='.5' d='M96 95h4v1h-4v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h4v1h-4v9h4v1h-4v9h4v1h-4v9h4v1h-4v9h4v1h-4v9h4v1h-4v9h4v1h-4v9h4v1h-4v9zm-1 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-9-10h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm9-10v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-9-10h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm9-10v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-9-10h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm9-10v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-9-10h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9z'/%3E%3Cpath d='M6 5V0H5v5H0v1h5v94h1V6h94V5H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E");
background-position: 2px 2px;
padding: 0.5rem;
color: #efefef;
}
</style>
</head>
<body>
<div id="app"></div>
<script type="module">
import { createApp } from "whyframe:app";
createApp(document.getElementById("app"));
</script>
</body>
</html>
<script>
import Popup from './Popup.svelte'
const content = 'Hoozah!'
</script>
<iframe data-why>
<p>Default HTML source</p>
<Popup {content}>Open</Popup>
</iframe>
<iframe data-why src="/other.html">
<p>Custom HTML source</p>
<Popup {content}>Open</Popup>
</iframe>
デフォルトのHTMLソースとして使いたい場合は設定を以下のようにvite.config.js
を変更すれば大丈夫です。
import { svelte } from "@sveltejs/vite-plugin-svelte";
import { whyframe } from "@whyframe/core";
import { whyframeSvelte } from "@whyframe/svelte";
import { defineConfig } from "vite";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
+ whyframe({ defaultSrc: "/other.html" }),
whyframeSvelte(),
svelte(),
],
});
ソースコードを抽出する
「このソースコードを書いたらこのUIが実現できるよ!」というようなことを示したい場合に、ソースコードを抽出して表示できたら便利です。
<iframe>
にdata-why-show-source
を追加して、getWhyframeSource()
を使えば取得できます。
<script>
import Popup from "./Popup.svelte";
import { getWhyframeSource } from "@whyframe/core/utils";
import { onMount } from "svelte";
const content = "Hoozah!";
let iframe = null;
let source = "";
onMount(() => {
source = getWhyframeSource(iframe);
});
</script>
<iframe bind:this={iframe} data-why data-why-show-source>
<Popup {content}>Open</Popup>
</iframe>
<p>Source:</p>
<pre>{source}</pre>
<iframe>
内のソースコードが取得できました! これを使えば、ドキュメントも簡単に作れそうです。
コンポーネント化して使い回す
複数箇所で使いたい場合、コンポーネント化して便利に使いまわしたいことがあると思います。
whyframe
の場合、ただコンポーネント化するだけではうまく動作せず、少し設定が必要なので説明します。
まず、コンポーネントを用意します。
<script>
export let title = 'iframe'
export let src = undefined
</script>
<p>{title}</p>
<iframe data-why {title} {src}>
<slot />
</iframe>
コンポーネント化したコンポーネント名を以下のようにvite.config.js
に追加します。
import { svelte } from "@sveltejs/vite-plugin-svelte";
import { whyframe } from "@whyframe/core";
import { whyframeSvelte } from "@whyframe/svelte";
import { defineConfig } from "vite";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
+ whyframe({ name: 'Story' }),
whyframeSvelte(),
svelte(),
],
});
Story.svelte
をApp.svelte
で呼び出して使用してみます。
<script>
import Popup from "./Popup.svelte";
import Story from "./Story.svelte";
const content = "Hoozah!";
</script>
<Story>
<p>This is a Story component</p>
<Popup {content}>Open</Popup>
</Story>
無事にレンダリングされました!
最後に
今回はiframe内にマークアップをレンダリングするときに使うライブラリのwhyframe
を紹介してみました!
ニッチなライブラリにはなりますが、知っていると使えるタイミングが意外とあるのでは?と思ったので是非、使ってみてください!