目次を表示
進捗状況
0%
2025-02-10

標準のIframeを用いたレスポンスデザインプレビューの表示
ReactとLitのコンポーネントをIframeを用いて表示する
やりたいこと
ブラウザの検証ツールを使わなくても、ボタン1つでレスポンシブデザインを確認したい。
そのためにIframeを活用しPlayground上でうまく表示できるかどうかを確認することができるコンポーネントを作成する。
プレビュー

技術スタック
graph TD
A[Monorepo Root]
A --> B[packages/design]
A --> C[packages/lit]
A --> D[packages/react]
A --> E[packages/types]
A --> F[packages/playground]
B --> G[utility.css files]
C --> H[Lit Web Components
ex: my-test ] D --> I[React Components
ex: Test ] E --> J[Type Definitions
ex: TestProps ]
ex: my-test ] D --> I[React Components
ex: Test ] E --> J[Type Definitions
ex: TestProps ]
Iframe概要
graph TD
G[ComponentPlaygroundWrapper]
G --> H[ResponsivePreview]
H --> I[CustomIframe]
I --> J[iframe head
CSS &JS ] I --> K[iframe body
preview contents]
CSS &JS ] I --> K[iframe body
preview contents]
Iframeの作成
プレビューを構成する前に読み込む必要があるものはuseEffectを用いて必要なエレメントを挿入。
主にコアの機能部分を作成していく。
Litについてはデザイン含め包括的に作成できる。
CustomIframe.tsx
const CustomIframe = ({ children, style, head, litFilePath }) => {
const iframeRef = useRef<HTMLIFrameElement>(null);
const [mountNode, setMountNode] = useState<Element | null>(null);
const headRootRef = useRef<Root | null>(null);
useEffect(() => {
const iframe = iframeRef.current;
if (iframe) {
const doc = iframe.contentDocument;
if (doc) {
if (head) {
if (!headRootRef.current) {
headRootRef.current = createRoot(doc.head);
}
headRootRef.current.render(<>{head}</>);
}
// add litFilePath component integration
setMountNode(doc.body);
}
}
}, [head]);
return (
<>
<iframe ref={iframeRef} style={style} />
{mountNode && createPortal(children, mountNode)}
</>
);
};
export default CustomIframe;
プレビューの作成
Iframeのコンポーネントを利用してPlaygroundのためのデザインを形成。
Tailwindのファイルを読み込みReact側のスタイリング対応が完了できる。
ResponsivePreview.tsx
const ResponsivePreview: React.FC<ResponsivePreviewProps> = ({ width, children, litFilePath }) => {
return (
<div
style={{// styling here}}
>
<CustomIframe
style={// styling}
head={
<>
<link rel="stylesheet" href="path/to/tailwind.css" />
</>
}
litFilePath={litFilePath}
>
{children}
</CustomIframe>
</div>
);
};
export default ResponsivePreview;
Playground側での表示
レスポンシブ用のそれぞれのサイズの定義をしておき、それを利用。
完全にIframeをインポートすることのみに集中し、全体を包括的に定義できるように。
PlaygroundWrapper.tsx
// Lit
<ResponsivePreview width={previewWidth} litFilePath={litFilePath}>
{React.createElement(hogehoge // add lit component element )}
</ResponsivePreview>
// React
<ResponsivePreview width={previewWidth}>
<Hogehoge /> // add react component element
</ResponsivePreview>
Viteを用いた絶対パスの取得
window.locationオブジェクトと今回の場合であればViteを利用しているため?urlを利用することができればパスを取得することができるので、それを組み合わせて、絶対パスを表現できる。
import litFilePath from 'lit/hogehoge?url';