Fresh v1.1がリリースされました。

この記事では主な変更点などについて解説します。

アップデート用スクリプトの追加

Freshのアップデート用スクリプトが追加されています。

$ deno run -A https://fresh.deno.dev/update .

このスクリプトを実行すると、各種依存関係や後述するcompilerOptionsやTwindプラグインなどに関する変更が適用されます。

compilerOptions.jsxcompilerOptions.jsxImportSourceのサポート

Freshのプロジェクトの初期化時に、compilerOptions.jsxcompilerOptions.jsxImportSourceが自動で設定されるようになりました。

これにより、.jsx/.tsxファイルで以下2行の指定が不要になります。

/** @jsx h */
import { h } from "preact";

前述のアップデートスクリプトを実行すると、既存のプロジェクトにもこの設定が適用されます。

プラグインシステム

ユーザがFreshの挙動を拡張できるようにするために、プラグインシステムが実装されました。

現時点では、生成されたHTMLに対するスクリプトやスタイルの注入などがサポートされています。将来的には、プラグイン経由でRouteやMiddlewareなどを追加できるようにすることが予定されているようです。

例として、公式でTwindプラグインが提供されており、start()pluginsオプションで有効化できます。

// main.ts
import { start } from "$fresh/server.ts";
import twindPlugin from "$fresh/plugins/twind.ts";

import manifest from "./fresh.gen.ts";
import twindConfig from "./twind.config.ts";

await start(manifest, { plugins: [twindPlugin(twindConfig)] });

このTwindプラグインを有効化すると、twを使わずにclassを指定できるようになります (PreactのOption Hooksを使用して twが自動で適用されます)

<div class="font-bold">foobar</div>

前述のアップデートスクリプトを実行することで、twを使わずにclassを記述する形式へ自動で変換されます。

Preact Devtoolsのサポート

Preact Devtoolsのサポートが追加されています。

devモード(deno task start)時は自動で有効化されるため、特に設定などは不要です。

Flash(Deno.serve)の実験的サポート

Deno v1.25で実装されたFlashの実験的サポートが追加されています。

// main.ts
import { start } from "$fresh/server.ts";
import manifest from "./fresh.gen.ts";

await start(manifest, { experimentalDenoServe: true });

Deno.serveの利用には--unstableの指定が必要で、Deno Deployではまだ動作しないため、注意が必要です。

Preact Signalsのサポート

先日発表されたPreact Signalsのサポートが追加されています。

Freshのプロジェクトを初期化する際に、自動でセットアップされます。

以下のリポジトリで、Preact Signalsを使ったコード例が公開されています。

_middleware.tsで複数のミドルウェアがサポート

handlerにミドルウェアの配列を指定することで、複数のミドルウェアを有効化できるようになりました。

// routes/_middleware.ts
export const handler = [logger, requestID];

async function logger(
  req: Request,
  ctx: MiddlewareHandlerContext,
): Promise<Response> {
  const start = new Date();
  const res = await ctx.next();
  const end = new Date();
  console.log(`${req.method} ${req.url.href}: status: ${res.status}, latency: ${+end - +start}ms`);
  return res;
}

async function requestID(
  req: Request,
  ctx: MiddlewareHandlerContext,
): Promise<Response> {
  const id = crypto.randomUUID();
  ctx.state.requestID = id;
  const res = await ctx.next();
  res.headers.set("X-Request-Id", id);
  return res;
}

HandlerContext#renderNotFound

このAPIを利用すると、404ページ(routes/_404.tsx)を明示的にレンダリングできます。

export const handler: Handlers = {
  GET(req, ctx) {
    return ctx.renderNotFound();
  },
};

カスタムのstaticディレクトリのサポート

start()でカスタムのstaticディレクトリを指定できるようになりました。

以下の例だと、静的ファイルは./custom_static_dirから配信されるように挙動が変更されます。

// main.ts
await start(manifest, { staticDir: "./custom_static_dir" });

参考