このページ内容は2022年9月9日以降、再調査・再検証してません。実際に扱う際は最新の情報にアクセスしてください。
Deno FreshはDeno Deploy上に展開されるフルスタックフレームワークですdeno。UI部分はPreactで記述し、デフォルトでJavaScriptの使用量を最小限に抑えるようにIsland Architectureを採用しています。
Island ArchitectureとはサーバーレンダリングでWebページを生成するときに、個々のインタラクティブな部分 (JavaScriptを使う部分) 以外を静的なHTMLとして先に送信し、後から個々のインタラクティブな部分を活性化 (Hydrate) させるアーキテクチャですisland_architecture。
Deno DeployではIsland Architectureを採用しているため、最初のページ遷移時にJavaScriptを送らず、ページ読み込みが速くなります。その他にも、Deno FreshはDeno Deploy上でJITレンダリングされたものをクライアントに送信するため、ビルドステップがないなどの特徴があります。
初期テンプレート作成時のファイル構成は以下のようになります。islandsディレクトリはJavaScript (useStateやuseEffectなども含む) を利用したいコンポーネントを置く場所で、routesディレクトリはページのパスやそのページでの処理、見た目などを書く場所です (routesはNext.jsにおけるpagesディレクトリに相当してます)。
ちなみに、routes配下ではuseStateやuseEffectが無効化されます。
1islands/xxx.tsx2routes3├── api ─ xxx.tsx4├── index.tsx5└── xxx.tsx6static/7utils/8deno.json9dev.ts10fresh.gen.ts11import_map.json12main.ts13README.md
ボタンクリックで数値が上昇するサンプルを作るとこのようになります。islandsディレクトリにHydrateさせたいコンポーネントを作成し、使用したいページでコンポーネントを読み込んで使います。
ちなみに、islandsディレクトリ配下のコンポーネント間でstateを共有したいときは、PreactのSignals (不正確かもしれませんが、vue3におけるrefのようなもの) を使うと良さそうですpreact_signals。
islands/Counter.tsx1// ここでは useStateを使いたいため、islandsディレクトリにコンポーネントを作成してます23/** @jsx h */4import { h } from "preact";5import { useState } from "preact/hooks";67// IS_BROWSERでクライアント側かサーバー側か判断して動かす8import { IS_BROWSER } from "$fresh/runtime.ts";910interface CounterProps {11start: number;12}1314export default function Counter(props: CounterProps) {15const [count, setCount] = useState(props.start);1617return (18<div>19<p>{count}</p>20<button onClick={() => setCount(count - 1)} disabled={!IS_BROWSER}>-1</button>21<button onClick={() => setCount(count + 1)} disabled={!IS_BROWSER}>+1</button>22</div>23);24}
routes/counter.tsx1// ここでは /counterにアクセスしたときの見た目を作ります23/** @jsx h */4import { h } from "preact";5import Counter from "../islands/Counter.tsx";67export default function Home() {8return (9<Counter start={3} />10);11}