Fresh 1.3.0 でプラグインでミドルウェアを適用できるようになった。
これまでも Fresh 用のミドルウェアは作っていたが、これを機にプラグイン対応させたいので確認がてらメモ。
参考
確認 「参考」に記載しているプルリクを見ると、プラグインは次のような形式で記述する必要がありそう。
1 2 3 4 5 6 7 8 9 10 11 { name : "sameRoutePlugin" , middlewares : [{ middleware : { handler : sameHandler }, path : "/" , }], routes : [{ path : "/_app" , component : sameComponent }], }
これは、fresh の提供する インタフェース Plugin に拠るもの。
Plugin 自体は、次のような定義になっている。
1 2 3 4 5 6 7 8 export interface Plugin { name : string ; entrypoints?: Record <string , string >; render?(ctx : PluginRenderContext ): PluginRenderResult ; renderAsync?(ctx : PluginAsyncRenderContext ): Promise <PluginRenderResult >; routes?: PluginRoute []; middlewares?: PluginMiddleware []; }
これらのうち、routes と middlewares が今回のターゲット。
また、 PluginRoute と PluginMiddleware は次のような定義。
1 2 3 4 5 6 7 8 9 10 export interface PluginMiddleware { path : string ; middleware : Middleware ; } export interface PluginRoute { path : string ; component?: ComponentType <PageProps > | ComponentType <AppProps >; handler?: Handler <any , any > | Handlers <any , any >; }
実装 既存では、次のように使うモジュールだった。
_middleware.ts 1 2 3 4 5 import { loggerHandler } from "https://deno.land/x/fresh_logger@0.0.1/mod.ts" ;export const handler = [loggerHandler];
これを以下のようにプラグインにした。
src/loggerPlugin.ts 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 import { type Plugin , type MiddlewareHandlerContext , type MiddlewareHandler , } from "../deps.ts" ; import { LogModule , type Logger , type RemoteLogSenderFunction , } from "./loggerModule.ts" ; export function getLoggerHandler (logSender?: RemoteLogSenderFunction ): Plugin { const handler : MiddlewareHandler <Logger > = async function ( _req: Request, ctx: MiddlewareHandlerContext<Logger> ) { ctx.state .logger = new LogModule (logSender); return await ctx.next (); }; return { name : "loggerPlugin" , middlewares : [ { middleware : { handler : handler as MiddlewareHandler <Record <"logger" , unknown >>, }, path : "/" , }, ], }; }
middleware の中の handler の型が、MiddlewareHandler<State = Record<string, unknown>>
である。 ことため、元よりあるstateの型を設定できなかったので、しかたなく as を使っている。
きれいな書き方があれば直したい。
プラグイン使うFresh側は、次のよう記述する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import "$std/dotenv/load.ts" ;import { start } from "$fresh/server.ts" ;import manifest from "./fresh.gen.ts" ;import twindPlugin from "$fresh/plugins/twind.ts" ;import twindConfig from "./twind.config.ts" ;import { getLoggerHandler } from "https://deno.land/x/fresh-logger/mod.ts" ;await start (manifest, { plugins : [ getLoggerHandler (), twindPlugin (twindConfig), ], });
導入はこれだけ、説明のためにソースコードでは https://deno.land/x/~~
を書いているが、import-map に書くのが推奨になるはず。 Fresh のデフォルトのページでログを仕込むときは、次のように記述する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 import { Head } from "$fresh/runtime.ts" ;import { useSignal } from "@preact/signals" ;import Counter from "../islands/Counter.tsx" ;import {type Logger } from "https://deno.land/x/fresh-logger/mod.ts" ;export default function Home ({state}: {state: Logger} ) { const count = useSignal (3 ); state.logger .log ("Home" ); return ( <> <Head > <title > test419-fresh-plugin</title > </Head > <div class ="px-4 py-8 mx-auto bg-[#86efac]" > <div class ="max-w-screen-md mx-auto flex flex-col items-center justify-center" > <img class ="my-6" src ="/logo.svg" width ="128" height ="128" alt ="the fresh logo: a sliced lemon dripping with juice" /> <h1 class ="text-4xl font-bold" > Welcome to fresh</h1 > <p class ="my-4" > Try updating this message in the <code class ="mx-2" > ./routes/index.tsx</code > file, and refresh. </p > <Counter count ={count} /> </div > </div > </> ); }
実行時のログは、リクエスト単位でid を割り当てて、表示されるようになる。
1 2 3 4 5 6 7 8 9 10 11 12 $ deno task start Task start deno run -A --watch=static/,routes/ dev.ts Watcher Process started. The manifest has been generated for 5 routes and 1 islands. 🍋 Fresh ready Local: http://localhost:8000/ { log_id: "5a76vAfNDkRkCU_IulOhk" , level: "log" , body: "App" } { log_id: "5a76vAfNDkRkCU_IulOhk" , level: "log" , body: "Home" } { log_id: "h2RlWaAsTkAIT2s7iBowj" , level: "log" , body: "App" } { log_id: "h2RlWaAsTkAIT2s7iBowj" , level: "log" , body: "Home" }
Fresh 1.3.0 に対応して、ミドルウェアのプラグイン化を行った。 まだ、いくつか管理しているミドルウェアがあるので、これらも対応してゆきたい。
では。