Murasaki
ガイド

ミドルウェア

すべてのクライアントサイドナビゲーションの前に実行されるルートガード。

src/middleware.ts は、すべてのナビゲーション — 初回マウント、push/replace、ブラウザの戻る/進む — の前に実行され、それをリダイレクトできるデフォルト関数をエクスポートできます:

src/middleware.ts
import type { Middleware } from 'murasaki'

const middleware: Middleware = ({ pathname }) => {
  if (pathname === '/admin') return { redirect: '/' }
}

export default middleware

<AppRouter>(スキャフォールドのエントリがマウントします)は、この関数を仮想ルートテーブルから自動的に読み込みます — 手動で登録する必要はなく、このファイルが存在しなくても何も起こりません。

シグネチャ

export interface MiddlewareContext {
  pathname: string
  search: string
}

export type MiddlewareResult = { redirect: string } | void | undefined

export type Middleware = (
  ctx: MiddlewareContext,
) => MiddlewareResult | Promise<MiddlewareResult>

ctx は意図的に小さく保たれています — ナビゲーション先の pathname と、そのクエリ文字列(searchlocation.search 形式: ''、または ? で始まる文字列)だけです。request/response もヘッダーも cookie もありません — これは完全にクライアントサイドで、あなたのルートと同じ WebView の中で実行され、エッジやサーバーランタイムではありません。リダイレクトせずに早期リターンするには、何も返さない(undefined)だけです。

非同期でも構いません — <AppRouter> はマッチしたルートをレンダリングする前にそれを await し、その間は何もレンダリングしないため、ガードされたルートが一瞬でも表示されることはありません。

middleware は pathname が変わったときに再実行され、クエリだけのナビゲーションでは再実行されません — ?tab=... のような更新は、再度 await でページをゲートする代わりに前回の判定をそのまま使い回します。クエリ文字列自体を読みたい場合は、ルート側で useSearchParams() を使ってください。

ルートをガードする

もっとも一般的な形は、クライアントサイドの状態(ストア、localStorage、あるいは document.cookie 経由の cookie)を読んで、未認証の訪問者を保護されたパスから遠ざける認証チェックです:

src/middleware.ts
import type { Middleware } from 'murasaki'
import { useAuth } from '@/lib/auth'

const PROTECTED = ['/settings', '/billing']

const middleware: Middleware = ({ pathname }) => {
  const isProtected = PROTECTED.some((p) => pathname.startsWith(p))
  if (isProtected && !useAuth.getState().isSignedIn) {
    return { redirect: '/login' }
  }
}

export default middleware

リダイレクトなしの副作用

middleware は必ずしもリダイレクトする必要はありません — void を返せばナビゲーションはそのまま通過するため、すべてのナビゲーションで副作用を実行する場所(例えば分析用のページビュー計測)としても便利です:

src/middleware.ts
import type { Middleware } from 'murasaki'
import { trackPageview } from '@/lib/analytics'

const middleware: Middleware = ({ pathname }) => {
  trackPageview(pathname)
}

export default middleware

リダイレクトループ(5 回以上連続したリダイレクト)は自動的に検出されます: Murasaki は警告をログに出力し、ハングする代わりに現在のパスをそのままレンダリングします。

どのパスでミドルウェアを実行するかを絞り込む matcher/config のようなエクスポートはありません — Next.js と異なり、middleware は常にすべてのナビゲーションで実行されるため、上の例のように関数の中で pathname に応じて自分で分岐します。

これは Next.js のミドルウェアに相当する Murasaki のクライアントサイド版です — あなたのルートと同じ WebView の中で実行されるため、エッジランタイムは関与しません。

次へ

GitHub でこのページを改善

On this page