素直に 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.tsindex 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.jsindex 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";exportdefault 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);exportdefault app;
同様にしてクライアント側のエントリーポイントも設定する。
// src/client.tsimport{ 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>
あとはいつも通り開発環境を起動すると、もろもろが動く。終わり。
サンプル: