fresh v1.6がリリースされました。
この記事では主な変更点などについて解説します。
Tailwind CSSの公式サポート
fresh公式でTailwind CSSのサポートが導入されました。
Tailwind CSSプラグイン (plugins/tailwind.ts
)が追加されています。
// fresh.config.ts
import { defineConfig } from "$fresh/server.ts";
import tailwind from "$fresh/plugins/tailwind.ts";
export default defineConfig({
plugins: [tailwind()],
});
本番環境での利用について
このTailwind CSSプラグインをDeno Deployで利用する場合は、事前ビルドとの併用が必須になるためご注意ください。
このプラグインを導入した状態でdeno task build
を実行すると、_fresh/static
にCSSファイルが生成されるため、Deno Deployではこちらが利用される想定です。(_fresh/staticについては後述します。また、本番ビルド時に生成されるCSSファイルはcssnano
で最適化されます)
新規プロジェクトへの導入について
freshのinit.tsでプロジェクトを初期化する際に、Tailwind CSSの有効化がサポートされています。
既存プロジェクトへの導入方法
deno.json
で公式で推奨されるバージョンのTailwind CSSを読み込むよう設定します。 ($fresh/src/dev/imports.ts)
{
"imports": {
// ... 省略 ...
"tailwindcss": "npm:tailwindcss@3.3.5",
"tailwindcss/": "npm:/tailwindcss@3.3.5/",
"tailwindcss/plugin": "npm:/tailwindcss@3.3.5/plugin.js"
},
// ... 省略 ...
}
次にTailwind CSSの設定ファイルをルートディレクトリに配置します。ファイル名はtailwind.config.ts
/tailwind.config.js
/tailwind.config.mjs
のいずれかである必要があります。
// tailwind.config.ts
import type { Config } from "tailwindcss";
export default {
content: [
"{routes,islands}/**/*.{ts,tsx}",
],
} as Config;
次にstatic/styles.css
に配置します。
/* 必要に応じてカスタマイズします... */
@tailwind base;
@tailwind components;
@tailwind utilities;
このCSSファイルを読み込ませるため、routes/_app.tsx
などに<link>
を記載します。
import { PageProps } from "$fresh/server.ts";
export default function App({ Component }: PageProps) {
return (
<html>
<head>
<link rel="stylesheet" href="/styles.css" />
{/* ...省略... */}
</head>
{/* ...省略... */
</html>
);
}
次にfresh.config.ts
からTailwind CSSプラグインを読み込むよう設定をします。
// fresh.config.ts
import { defineConfig } from "$fresh/server.ts";
import tailwind from "$fresh/plugins/tailwind.ts";
export default defineConfig({
plugins: [tailwind()],
});
これでTailwind CSSが動作するようになるはずです。開発時はこれ以外には特に作業は不要で、本番環境(Deno Deploy)で使用する際は事前ビルド(deno task build
)の導入が必要になります。
型定義の単純化
FreshContext
の導入
FreshContext
という新しい型が導入されています。
これに伴い、Handler
やMiddlewareHandler
などのctx
引数に渡される型がFreshContext
に変更されています。
また、以下の各型がFreshContext
をベースに再定義されました。(以下のうちRouteContext
以外の型は非推奨化されていて、今後はFreshContext
の使用が推奨されます)
HandlerContext
RouteContext
AppContext
LayoutContext
UnknownHandlerContext
ErrorHandlerContext
MiddlewareHandlerContext
FreshContext
について
FreshContext
はconfig
プロパティを持っており、freshの設定を参照することができます。
また、FreshContext
のpattern
プロパティは非推奨化されており、今後はroute
プロパティの使用が推奨されます。
各コンポーネントのprops
の単純化
PageProps
が先程のFreshContext
をベースに再定義されています。(render
/next
/renderNotFound
プロパティは除外されています)
また、AppProps
/LayoutProps
/UnknownPageProps
/ErrorPageProps
の4つの型がPageProps
に統合されました。(これら4つの型は非推奨化されています)
Partials
fresh v1.5で導入されたPartialsに関する改善が実施されています。
<form>
のサポート
submit
イベントが発生したとき、対象の<form>
またはsubmitterでf-client-nav
が有効化されていれば、Partialによるクライアントサイドナビゲーションが適用されます。
この際、以下の優先度に従って、submit
を処理するためのエンドポイントが決定されます。
submitter
のf-partial
属性submitter
のformaction
属性<form>
のf-partial
属性<form>
のaction
属性
エンドポイントへHTTPリクエストを送信する際は、<form>
またはsubmitter
で指定されたHTTPメソッドに応じて、GET
またはPOST
のいずれかが送信されます。(GET
の場合はクエリパラメータ、POST
の場合はリクエストボディに<form>
の内容が設定されます)
<Partial>
のネストがサポート
<Partial>
をネストできるようになりました。親側の<Partial>
が更新されると、子側の<Partial>
も更新されます。
ただし、子側の<Partial>
が更新された際は、親側は<Partial>
は更新されないようです。
function Page() {
return (
<Partial name="outer">
<Partial name="inner">
{/* ... */}
</Partial>
</Partial>
);
}
isPartial
PageProps
などのFreshContext
をベースとした型にisPartial
プロパティが追加されています。
<Partial>
によるクライアントナビゲーション時のリクエストではtrue
が設定されるため、レスポンスの内容を最適化する際などに利用できそうです。
export default function DocPage(props: PageProps<Data>) {
if (props.isPartial) {
return <Content content={props.data.content} />;
} else {
return (
<>
<Head>
<link rel="stylesheet" href="/styles.css" />
</Head>
<Content content={props.data.content} />
</>
);
}
}
function Content(props: { content: string }) {
return (
<Partial name="docs-content">
<article
data-color-mode="auto"
data-dark-theme="dark"
class="p-4 mx-auto w-full markdown-body"
dangerouslySetInnerHTML={{ __html: props.content }}
/>
</Partial>
);
}
その他の改善
<Partial>
によるクライアントサイドナビゲーションの発生時に、リダイレクトが処理されるように改善されました (fetch()
の実行時にredirect: "follow"
が設定されます)- エラーページで
<Partial>
が動作するように改善されました。例えば、存在しないページにアクセスした際に、現在のページの<Partial name="xxx">
に該当する<Partial>
を_404.tsx
が返却していれば、その内容で差し替えられます。
プラグインシステム
プラグインからのIslandコンポーネントの提供がサポート
プラグインからIslandコンポーネントの提供がサポートされました。
islands
オプションにIslandコンポーネントのリンクを記載しておくことで、FreshがそれらのコンポーネントをIslandとして扱ってくれます。
import type { Plugin } from "$fresh/server.ts";
const counterPlugin: Plugin = {
name: "counter",
islands: {
baseLocation: "https://deno.land/x/fresh@1.6.0/demo/islands/",
paths: ["./islands/Counter.tsx"]
}
};
buildStart
/configResolved
フックにconfig
が渡されるように
PluginにconfigResolved
フックが追加されました。startに渡されたconfig
の内容を受け取ることができ、config
が解決されたタイミングで実行されます。また、事前ビルド時はbuildStart
よりも前のタイミングで呼ばれます。
また、buildStart
フックでも同様にconfig
を受け取れるように改善されています。
const somePlugin: Plugin = {
name: "some-plugin",
buildStart(config) {
console.info("buildStart", config);
},
configResolved(config) {
console.info("configResolved", config);
},
};
PluginRenderResult
にlinks
/htmlText
が追加
Plugin#render(Async)
が返却するPluginRenderResult
に以下のプロパティが追加されました。
プロパティ | 説明 |
---|---|
links | このプロパティが設定されていたら、その内容を元に<head> に<link> が挿入されます。 |
htmlText | このプロパティが設定されていた場合、最終的に返却される<body> がその内容で置き換わります。 |
事前ビルド (deno task build
)
_fresh/static
のサポート
freshが_fresh/static
に配置された静的なアセットを認識してくれるようになりました。
ここに置かれたファイルはstatic/
ディレクトリに置かれたファイルよりも優先して配信してくれます。
基本的にはプラグイン(Plugin#buildStart
)が静的ファイルを作成したい場合に利用されることが想定されているようで、前述したTailwind CSSプラグインでも、事前ビルド(deno task build
)を実行すると、Tailwind CSSの本番ビルドによって生成されたCSSファイルが_fresh/static
に生成されます。
Server
handler
などからDeno.errors.NotFound
がthrow
された際も404ページ(_404.tsx
)が表示されるように改善されました。- ルーティングのパフォーマンスが最適化されています。
URLPattern
ではなく正規表現を使用することなどにより改善されているようです。 - エラー発生時にfreshが表示するコードフレームを閉じられるように改善されました。(#2074)
- 開発時にユーザーが用意した
_500.tsx
がレンダリングされなくなってしまう課題があったようです。
- 開発時にユーザーが用意した
Islands
islands/
配下のファイルで関数以外の要素がexport
されていた際にエラーが発生する問題が解消されました。islands/
配下のファイルをバンドルする際に、各Islandコンポーネントごとにバンドルを作成するのではなく、各ファイルごとにバンドルを作成するように修正されました。
fresh.config.ts
router.basePath
オプションが追加
アプリケーションがserveされる基準となるパスを変更可能で、例えば、以下の場合は、/subdir
配下からアプリケーションが配信されます。
import { defineConfig } from "$fresh/server.ts";
export default defineConfig({
router: { basePath: "/subdir" },
});
Manifest (fresh.gen.ts
)
fresh.gen.ts
でのコンフリクトの発生を減らすように、routes
やislands
に設定されるキーの名前が改善されました。