素直に app/
でやれば良いのだが、やんごとなき理由で app/
以外の、例えば src/
や my-worldest-strong-app/
などで開発したいことがある (かもしれない)。
そういうときにやると良いハック。 PR は送るべきか悩んで放置している。
まずは HonoX
にパッチを当てる必要があるので、パッチを当てます。お使いのパッケージマネージャーでできる方法で試しましょう。
$ pnpm patch honox
差分は以下のような形。単純に honopx/vite/client
に対して、 entry
を渡せるようにしただけ:
diff --git a/dist/vite/client.d.ts b/dist/vite/client.d.ts index 7d4b2c20a9fc97ad538d89c850d0517df41271a0..54f6a0f4383c78f4dd353ae7c4a28572148098e0 100644 --- a/dist/vite/client.d.ts +++ b/dist/vite/client.d.ts @@ -1,6 +1,7 @@ import { Plugin } from 'vite'; type Options = { + entry?: string; jsxImportSource?: string; assetsDir?: string; }; diff --git a/dist/vite/client.js b/dist/vite/client.js index 2beda22387a7506caafe9e4b961facc1af661b05..13935f18b3b72124d5227ae1c86f15fe113380e1 100644 --- a/dist/vite/client.js +++ b/dist/vite/client.js @@ -1,4 +1,5 @@ const defaultOptions = { + entry: "/app/client.ts", jsxImportSource: "hono/jsx/dom", assetsDir: "static" }; @@ -9,7 +10,7 @@ function client(options) { return { build: { rollupOptions: { - input: ["/app/client.ts"] + input: [options?.entry ?? defaultOptions.entry] }, assetsDir: options?.assetsDir ?? defaultOptions.assetsDir, manifest: true
適用したら、次の手順。
まず、 vite.config.ts
にて、クライアント/サーバーともにエントリーポイントを書き換える。
このとき、 server
側 (honox/vite
) も同様に app
にあることを前提としたコードがあるのだが、そこについてはオプションで対応できるので、あわせて指定している (islandComponents
)。
import pages from "@hono/vite-cloudflare-pages"; import honox from "honox/vite"; import client from "honox/vite/client"; import { defineConfig } from "vite"; import path from "node:path"; export default defineConfig(({ mode }) => { if (mode === "client") { return { plugins: [client({ entry: "/src/client.ts" })], }; } return { plugins: [ honox({ entry: "/src/server.ts", islandComponents: { isIsland: (id) => { return path .resolve(path.join(import.meta.dirname, "src", id)) .includes("islands"); }, }, }), pages(), ], }; });
次はサーバー側のエンドポイントにて、自動検索されるパスをすべて置き換える。
基本は次のようにすれば動くはず。 routes
も変えたい!という場合は良い感じに書き換えよう。
// src/server.ts mport { showRoutes } from "hono/dev"; import { createApp } from "honox/server"; const app = createApp({ root: "/src/routes", NOT_FOUND: import.meta.glob("/src/routes/**/_404.(ts|tsx)", { eager: true, }), ERROR: import.meta.glob("/src/routes/**/_error.(ts|tsx)", { eager: true, }), RENDERER: import.meta.glob("/src/routes/**/_renderer.tsx", { eager: true, }), MIDDLEWARE: import.meta.glob("/src/routes/**/_middleware.(ts|tsx)", { eager: true, }), ROUTES: import.meta.glob("/src/routes/**/!(_*|*.test|*.spec).(ts|tsx|mdx)", { eager: true, }), }); showRoutes(app); export default app;
同様にしてクライアント側のエントリーポイントも設定する。
// src/client.ts import { createClient } from "honox/client"; createClient({ island_root: "/src", ISLAND_FILES: { ...import.meta.glob("/src/islands/**/[a-zA-Z0-9[-]+.(tsx|ts)"), ...import.meta.glob("/src/routes/**/_[a-zA-Z0-9[-]+.island.(tsx|ts)"), }, });
最後に、 Renderer においてクライアント側エントリーポイントのパスを指定している場所があるので、書き換える。
--- a/app/routes/_renderer.tsx +++ b/src/routes/_renderer.tsx @@ -9,10 +9,10 @@ export default jsxRenderer(({ children, title }) => { <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>{title}</title> - <Script src="/app/client.ts" async /> + <Script src="/src/client.ts" async /> <Style /> </head> <body>{children}</body> </html>
あとはいつも通り開発環境を起動すると、もろもろが動く。終わり。
サンプル: