generated at
Fresh 入門
はじめに
Freshに関する概要などについては、Freshを参照ください🙇‍♂️

プロジェクトの初期化
init.ts を実行すると、プロジェクトが作成されます
shell
$ deno run -A -r https://fresh.deno.dev <ディレクトリ名>
deno.json routes/ ディレクトリなど、開発に必要なファイルが自動生成されます。

devサーバの起動
開発をする際は、devサーバを起動する必要があります。以下のコマンドによって起動することが可能です。(Freshでは開発に必要な各種コマンドはdeno task経由で提供されます)
shell
$ deno task start

ルーティング
FreshNext.jsライクなファイルシステムベースのルーティングを提供しています。
routesディレクトリ
Routeを配置するディレクトリです。
routes ディレクトリ内の構造を元に、最終的なパスが決定されます。
Dynamic routes
routes/users/[id].tsx のような形式でファイルを用意すると定義できます。
Route Groups
FreshではNext.jsライクにRoute Groupsを定義することができます。
Route Groupsを定義する際は、 routes/ 配下に (some-group) というような形式のディレクトリを用意します。
例)
text
routes ├── (_islands) │   └── Counter.tsx ├── (dashboard) # Route Groupの定義 │   ├── _layout.tsx # Route GroupごとにLayoutを適用できます │   ├── _middleware.ts # Route GroupごとにMiddlewareを適用できます │   └── account.tsx # /accountにマッピングされます (`(dashboard)`の部分はパスから取り除かれます) ├── _app.tsx ├── _layout.tsx └── index.tsx
例外として、 (_some-group) というように _ から始まるグループについてはFreshによってファイルシステムルーティングの対象から除外されます。
この性質を利用することで、例えば、 (_components) のようなディレクトリを用意し、そこで特定のページに関連するコンポーネントの一覧をまとめて管理することもできます。
さらに例外として、 (_islands) というディレクトリについてはFreshによって特別扱いされます。具体的には、このディレクトリ配下の各モジュールをFreshはIslandコンポーネントとして取り扱います。

Route
Routeとはページまたはハンドラのいずれかまたはその両方を定義したモジュールのことです。
ページ
RouteからPreactコンポーネントを default export すると、対応するパスにアクセスした際にそのコンポーネントがSSRされます。

ハンドラ
Request HandlerContext を受け取りResponseまたは Promies<Response> を返却する関数です。
後述するカスタムハンドラを定義することで、ページのレンダリング時の挙動のカスタマイズなどが可能です。
あるRouteでカスタムハンドラを定義していない場合、同一Route default export しているページコンポーネントをSSRするハンドラがデフォルトで実行されます。

カスタムハンドラ
APIエンドポイントの作成やなど様々な用途で活用できます。
カスタムハンドラを定義したいときは、Routeから下記いずれかの形式で handler export する必要があります。
(request: Request, ctx: HandlerContext) => Response | Promise<Response>
{ [httpMethod: string]: (request: Request, ctx: HandlerContext) => Response | Promise<Response> }
カスタムハンドラで ctx.render() を呼ぶと、同一Routeで定義されているページコンポーネントがレンダリングされます。
また、 ctx.render() に渡した引数は、対応するページコンポーネントの props.data 経由でアクセスできます。
typescript
// routes/users/[id].tsx import type { Handlers, PageProps } from "$fresh/server.ts"; export const handler: Handlers<Data> = { async GET(req, ctx) { const user = await findUserByID(ctx.params.id); if (user == null) { return ctx.renderNotFound(); } const resp = await ctx.render(user); return resp; }, }; export default async function User(props: PageProps<User>) { return <UserDetail user={props.data} />; }

Async route component
Freshが提供する独自形式のコンポーネントです。
Request オブジェクトと RouteContext を受け取り、Vnodeを返却する関数です。
typescript
// routes/users/[id].tsx import { defineRoute } from "$fresh/server.ts"; export default defineRoute(async (req, ctx) => { const user = await findUserByID(ctx.params.id); if (user == null) { return ctx.renderNotFound(); } return <UserDetail user={user} />; });

Islands
概要
FreshデフォルトでSSRされたPreactコンポーネントのHydrationを行いません。
Hydrationが必要な場合は、Islandコンポーネントを実装する必要があります。
Freshでは islands ディレクトリまたは routes/**/(_islands) ディレクトリに配置したコンポーネントは、Islandとして扱われます。
命名形式
Island コンポーネントのファイル名はパスカルケースまたはケバブケース形式で命名する必要があります。

ミドルウェア
ミドルウェアを定義することで、ハンドラの実行前後に任意の処理を挟めます。
routes ディレクトリ配下に _middleware.ts を配置し、 handler 関数を export することで定義できます。
handler は引数として Request MiddlewareHandlerContext を受け取り、 MiddlewareHandlerContext next を呼ぶことで、後続のハンドラが実行されます。

エラーページ
404エラー
routes/_404.tsx でコンポーネントをdefault exportすることで、404エラー用のページをカスタマイズできます (コンポーネントには UnknownPageProps が渡されます)
404ページを明示的にレンダリングしたいときは、 HandlerContext#renderNotFound を利用できます。
with-render-not-found.tsx
export const handler: Handlers = { GET(req, ctx) { return ctx.renderNotFound(); }, };
500エラー
routes/_500.tsx でコンポーネントをdefault exportすることで、500エラー用のページをカスタマイズできます (コンポーネントには ErrorPageProps が渡されます)

Custom App
routes/_app.tsx に配置します。
Custom Appコンポーネントに渡される props についてはAppProps型を参照

Layout
Custom App( routes/_app.tsx )はアプリケーションにつき一つしか配置できない制限があります。
それに対して、Layout routes 内の任意のディレクトリに _layout.tsx を配置することで定義できます。
typescript
// routes/admin/_layout.tsx import type { LayoutProps } from "$fresh/server.ts"; export default function AdminLayout({ params, Component }: LayoutProps) { return ( <section> <h2>Admin</h2> <div> <Component /> </div> </section> ); }

Freshで提供されるコンポーネント
<Head> - <head> タグの内容を組み立てる際に使用できます。 (将来的に非推奨化される予定です)

静的ファイル
static ディレクトリに配置したファイルは静的に配信されます
Freshが提供する asset 関数を利用することで、 static ディレクトリ内のファイルへの絶対パスをビルドID付きで取得することもできます。
また、Fresh <img> <source> src srcset 属性のパスに対して、自動でビルドIDを付与してくれます。(この挙動を無効化したいときは、 data-fresh-disable-lock を指定する必要があります)

事前ビルド (AOTコンパイル)
Freshでは deno task build コマンドによって、Islandコンポーネントなどを事前にビルドすることができます。
shell
$ deno task build
このコマンドを実行すると、esbuildによるバンドル結果が _fresh ディレクトリに出力されます。
Freshはもし _fresh ディレクトリが存在すれば、そこに格納されたバンドルを利用します。
これによりコールドスタート時間の短縮が期待されます。

注意点として、Freshにおいては事前ビルドはオプトインであり、導入は必須ではありません。
例えば、開発時は事前ビルドは使わずにJITレンダリング方式のみを使用して開発を進め、本番にデプロイするときだけ事前ビルド(AOTコンパイル)を行う、といったことも可能です。

プラグイン
Freshを拡張する仕組み
公式ではTwind v0.16向けのプラグインが提供されています。

テスト

アップデート
Fresh v1.1からアップデート用スクリプトが実装されています
shell
$ deno run -A -r https://fresh.deno.dev/update .