mcpField
M
marko-run

marko-run

github.com/svallory開発5142 回インストール5 週間前に更新
リポジトリ

marko-run について

marko-run は Marko Run アプリを扱うエージェント向けの開発資料です。Vite のファイルベースルーティング、ストリーミング SSR、ハンドラー、検証、デプロイを解説します。

主な機能

  1. 01ファイルベースルーティングとレイアウト
  2. 02ストリーミング SSR とデータ読み込み
  3. 03型付きハンドラーと URL ヘルパー
  4. 04リクエスト検証とミドルウェア
  5. 05Vite 設定とデプロイアダプター

活用シーン

  1. 01ルートとネストしたレイアウトの実装
  2. 02検証付きリクエストハンドラーの追加
  3. 03データ読み込み中のストリーミング維持
  4. 04ビルドとデプロイの設定

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/svallory/marko-ui --skill marko-run

インストール後、Claude Code で/marko-runを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
deploy.md
handlers.md
routing.md

詳細

Marko Run

https://markojs.com/docs/marko-run から要点をまとめました。Vite 上のファイルベースルーティング、ストリーミング SSR、設定不要。references/routing.md(ファイル、パス、フラットルート、実行順序)、references/handlers.md(動詞ヘルパー、バリデーション、データ読み込み、コンテキスト、型付き URL、埋め込み)、references/deploy.md(Vite プラグイン、アダプター、CLI)。

基本的な考え方

  • src/routes/** — + で始まるファイルのみルーティング対象です。それ以外はすべて無視されます(コンポーネントやテストは自由に同じ場所に配置できます)。
  • リクエスト → ミドルウェア(ルートから末端)→ ハンドラー → レイアウト(ルートから末端)→ ページ。レイアウトとページは 1 つのコンポーネントにコンパイルされます。
  • ctx(ハンドラー/ミドルウェア)=== $global(テンプレート)。ctx.params と ctx.url はデフォルトでブラウザーにシリアライズされます。それ以外は ctx.serializedGlobals で追加します。
  • データは next({ ... }) を通じて ctx.data / $global.data へ下方向に渡されます(浅いマージ)。プロミスを渡し、ページで <await> します — next の前に await するとストリーミングが無効になります。
  • Run はグローバルです(インポート不要):Run.GET/HEAD/POST/PUT/DELETE/PATCH/OPTIONS/QUERY/ALL、Run.href、型 Run.Context、Run.Platform。

クイックリファレンス

ファイル(routes 以下の任意の階層)
ファイル役割
+page.markoGET → HTML。パスごとに 1 つ。
+layout.marko入れ子になったレイアウト/ページをラップします。input.content = 子要素。$global = ctx。
+handler.tsexport const GET/POST/... = Run.X(...)。パスごとに 1 つ。Response を返すか、undefined を返すと next() が自動的に呼び出されます。HEAD がない場合は、GET から本文を除いたものになります。
+middleware.tsexport default Run.ALL(...)(すべての動詞)または Run.POST(...)(1 つの動詞)。ハンドラーの前に実行されます。オプションのみの形式 Run.ALL({ search }) は、以下のバリデーションを適用します。
+meta.json / +meta.ts静的な ctx.meta。動詞キー("POST": {...})はメソッドごとに浅く上書きします。
+404.marko、+500.markoルートのみ。Accept に text/html が含まれる場合に使用されます。ルートレイアウトでラップされます。
パスセグメント

users は静的 · _admin はパスなし(URL では無視され、レイアウト/ミドルウェアの適用範囲を定めます) · $id はパラメーター($ のみの場合はマッチしますが、キャプチャしません) · $$rest は末尾までのキャッチオール($$ はキャプチャせず、その内側には何もネストできません)。 フラットルート:projects.$projectId.members+page.marko。ディレクトリでも使用できます(projects.$projectId/members+page.marko)。ネストされたディレクトリとマージされます。複数パスは members,people+page.marko、グループは (members,people)、オプションは (home,) または (home,_x)。制御文字はバッククォートでエスケープします:`sitemap.xml`/+handler.ts。

ハンドラーとバリデーション
export const POST = Run.POST({ json: NoteSchema }, async (ctx, next) => {
  const [note, issues] = await ctx.body;          // Standard Schema → [value, issues]; fn validator → its return
  if (issues) return Response.json({ issues }, { status: 422 });
  return ctx.redirect("/thanks");                 // PRG on success; next({ issues }) to re-render form with errors
});
  • オプション:params、search(関数または同期 Standard Schema。遅延実行され、初回アクセス時にキャッシュされます)、json(validator、maxBytes 1MiB)、form(validator、maxBytes、maxParts 1000、maxFiles 20、maxFileBytes 1MiB、onFile(ctx, file)。繰り返しフィールドは配列になります)。フォームでは Run.POST(options, [auth, handler]) のように配列で合成できます。
  • ctx.body はプロミスです(await ctx.body)。遅延実行され、json/form オプションがない場合は undefined になります。ctx.request.json() は呼び出さないでください — バリデーションと制限を迂回します。
  • オプションはミドルウェアとハンドラー間でマージされます(最後のバリデーターが優先され、オブジェクトは浅くマージされます)。
  • ctx のメソッド:fetch(url, init)(内部で再リクエストし、parent を設定します)、render(template, input, init)、redirect(to, status=302)、back(fallback="/", status)。
  • Run.href("/projects/$projectId/members", { params: { projectId: 42 }, search: {...}, hash }) — .marko-run/routes.d.ts が tsconfig の include に含まれている場合、実際のルートに基づいて型付けされます。クライアントではコンパイル時に書き換えられます。
型

生成される .marko-run/routes.d.ts(ルートに tsconfig が必要です。include に追加してください)により、ファイルごとに Run.Context が絞り込まれます(params、meta、search、body、上流の data)。グローバルに拡張するには:declare module "@marko/run" { interface Context { db: DB } interface Platform { ... } } — アプリ全体で使うプロパティ用に限定してください。ルートごとのデータは next() で渡します。

設定/デプロイ
  • vite.config は不要です。必要な場合は、import marko from "@marko/run/vite"; plugins: [marko({ adapter, routesDir, trailingSlashes })] を指定します(すべての @marko/vite オプションも使用できます)。trailingSlashes:RedirectWithout(デフォルト)|RedirectWith|RewriteWithout|RewriteWith|Ignore。
  • アダプターの解決順序:オプション → @marko/run-adapter*/*marko-run-adapter* という名前の最初の依存関係 → 組み込みの Node。パッケージ:@marko/run-adapter-node(Express ミドルウェア:routerMiddleware()、matchMiddleware() → req.route.invoke)、@marko/run-adapter-static(urls: [...] | async fn、リンクをクロール)、@marko/run-adapter-netlify({ edge: true } と netlify.toml の functions/edge_functions = "dist"、dist/public を公開)。
  • 埋め込み:import * as router from "@marko/run/router" → router.fetch(request, platform)、router.match(method, path) と router.invoke(route, request, platform)。
  • CLI(marko-run、bun run/bunx で実行):dev(デフォルト、-p)、build(-o)、preview(-o -p -f)。すべて -c config、-e dotenv を指定できます。

よくある間違い

  • next() の前に GET でデータを await する → レスポンス全体がブロックされます。プロミスを渡してください。
  • 成功した POST から next() を返す → 更新時に再送信され、URL を共有できません。代わりにリダイレクトしてください。
  • 非同期の Standard Schema バリデーターは実行時にエラーになります。同期処理のみ使用してください。
  • ctx.body() — これは関数ではなく、プロミスです。
  • 常に独自の Response を返すハンドラーではページがレンダリングされません(そのハンドラーの HTTP メソッドはページの型付きコンテキストから除外されます)。
  • $$catch-all ディレクトリ内にルートファイルをネストする — 探索されません。
  • クライアントで $global.session を使えると思い込む — デフォルトでシリアライズされるのは params/url のみです。ctx.serializedGlobals に追加してください(シークレットは絶対に追加しないでください)。

コメント