Twitter @sigumataityoudaGitHub @maguro-alternative
← Articles に戻る
🐟 Blog2026年7月26日·約7分で読めます

VercelにHonoXをデプロイする

はじめに

どうしてもHonoXをVercelで動かしたかったのでメモ程度に

やったこと

3行で表すと

  • Vercelでビルドせず、Vite側でビルドする
  • dist/assets.vercel/output/static/にコピーする
  • ビルドしたものをVercelに--prebuiltでアップロードする

VercelのHonoビルドは使えない

VercelにはHonoのデプロイ基盤がありますが、HonoXはHono+Viteという組み合わせで構成されています。 ドキュメントを見ると根本としてHonoのプリセットではViteを実行しないので、そのまま使うことはできません。 加えてエントリファイルの置き場所も決まっていて、プロジェクトルートかsrc/配下を探します。 HonoXのエントリはapp/server.tsなので、ここも噛み合いません。HonoX側が/app/をハードコードしているため、規約に合わせて移動することもできません。

https://vercel.com/docs/frameworks/backend/hono

なので、プリセットに頼らずViteでビルドする必要があります。

じゃあどうするか

とはいえそこまでやることは難しくないです。 (Node.js使うこと想定してます。)

  • vite.config.ts
import build from '@hono/vite-build/vercel'
import adapter from '@hono/vite-dev-server/node'
import honox from 'honox/vite'
import { defineConfig } from 'vite'

export default defineConfig(({ mode }) => {
  if (mode === 'client') {
    return {
      build: {
        rollupOptions: {
          input: ['./app/client.ts', './app/style.css'],
        },
        manifest: true,
      },
    }
  }

  return {
    plugins: [
      honox({
        devServer: { adapter },
      }),
      build(),
    ],
  }
})

ビルドする際、クライアント側とサーバー側は分けてやります。

HonoXはapp/islands/配下のものはクライアントとして扱われ、これをブラウザが扱える形式に変換する必要があります。(cssも同様) 出力されたファイルはclient-qR_IxzNI.jsという風にハッシュが付くため、manifestがないと名前解決ができなくなるため有効にします。

サーバー側は特段設定することはありません。 @hono/vite-build/vercelを使ってVercel用にbuildを行います。

これでクライアント、サーバーそれぞれにdist/,.vercel/output/が出力されます。

  • package.json
{
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "rm -rf dist .vercel/output && vite build --mode client && vite build && cp -r dist/assets .vercel/output/static/",
    "deploy": "npm run build && vercel deploy --prebuilt --prod"
  },
  "engines": {
    "node": "22.x"
  }
}

HonoXではクライアント側のビルドの出力先はdist/に固定されてます。

https://github.com/honojs/honox/blob/v0.1.40/src/server/components/script.tsx#L19

しかしVercelの場合、静的ファイルは.vercel/output/static/配下に置くことがBuild Output APIで規定されています。

https://vercel.com/docs/build-output-api/primitives#static-files

この2つが噛み合わないので、橋渡しのcpが必要になります。

deployでは、すでにビルド済みのファイルをアップロードするだけです。 そのため--prebuiltをつけてます。

https://vercel.com/docs/cli/deploy#prebuilt

  • vercel.json
{
  "$schema": "https://openapi.vercel.sh/vercel.json",
  "framework": null,
  "buildCommand": "npm run build"
}

framework: nullでフレームワークの自動検出を無効化します。

以上です。 ビルドとデプロイしてみましょう。

npm run build
npm run deploy

DEMO https://maguro-portfolio-honox.vercel.app/

個人的にハマった点

ほぼ蛇足ですが書きます。

  • ビルドするNode.jsのバージョンが20/22/24以外だと弾かれる VercelがサポートしているNode.jsのランタイムは20.x/22.x/24.xの3つです。手元のNode.jsのバージョンが25だったのでデプロイに失敗しました。
16:07:34.879 Running build in Washington, D.C., USA (East) – iad1
16:07:34.879 Build machine configuration: 2 cores, 8 GB
16:07:34.912 Retrieving list of deployment files...
16:07:35.231 Downloading 52 deployment files...
16:07:36.412 Using prebuilt build artifacts from .vercel/output
16:07:36.412 Learn more: https://vercel.link/build-output-api
16:07:36.418 Deploying outputs...
16:07:36.810 The following Serverless Functions contain an invalid "runtime":
16:07:36.810   - __hono (nodejs25.x)

Nodeのバージョン切り替えるってのも考えましたが、正直動けば良いのでビルド後にruntimeを直接書き換えることにしました。 ここややこしいんですが@hono/vite-build/vercelが、ビルドしたマシンのNode.jsバージョンをそのまま.vc-config.jsonに書き込んでいて、そこを見て実行するruntimeを決めているようです。 なのでここのバージョンを書き換えればそのバージョンで動きます。

https://github.com/vercel/vercel/blob/main/packages/build-utils/src/collect-build-result/validate-build-result.ts

と言うわけでnodejs22.xで動かすように書き換えます。

  • scripts/fix-vercel-runtime.mjs
import { readFileSync, writeFileSync } from 'node:fs'

const path = '.vercel/output/functions/__hono.func/.vc-config.json'
const config = JSON.parse(readFileSync(path, 'utf8'))
config.runtime = 'nodejs22.x'
writeFileSync(path, JSON.stringify(config))
console.log(`runtime: ${config.runtime}`)

合わせてpackage.jsonのbuildの部分も書き換えます。 node scripts/fix-vercel-runtime.mjsを追加します。

"build":"rm -rf dist .vercel/output && vite build --mode client && vite build && cp -r dist/assets .vercel/output/static/ && node scripts/fix-vercel-runtime.mjs",

中身がNode.js22で動くことが前提となりますが、デプロイは通るようになります。

終わりに

色々コード読みながら進めてみましたが、謎解きみたいで楽しいですね。 間違いあればご報告いただけるとありがたいです。

© 2025 Maguro Alternative. All rights reserved.