🔥

🔥HonoXをnodeで実行する

2024/02/11に公開

hono@v4がリリースされ、合わせてファイルベースルーティング機能を持ったHonoXもリリースされました
これによりSPA,SSG,SSRと好みの手法でウェブアプリケーションを作成できるフレームワークの選択肢が増えました

今記事はGoogle Cloud Runなどのコンテナイメージを実行するようなクラウドへデプロイできるようにしてみたメモです

公式READMEにもある@hono/vite-cloudflare-pagesでビルドしたものをそのままNodejsで実行することも可能ですが、Worker向けのコードが入っており動かないコードが混じっているのもと思い、自前で実装します

ポイントとしては @hono/vite-cloudflare-pages で行っている以下の処理を実装する必要があります
https://github.com/honojs/vite-plugins/blob/main/packages/cloudflare-pages/src/entry.ts#L39-L40

https://github.com/honojs/vite-plugins/blob/main/packages/cloudflare-pages/src/cloudflare-pages.ts#L43-L62

実装内容

  • production実行時に/static,/favicon.icoをserveする
  • production実行時にアプリケーションをnodeでserveする
  • productionビルド時にnodeでserveしたファイルをエントリーポイントとするようにvite.config.tsを修正する
app/server.ts
import { createApp } from 'honox/server'
import { showRoutes } from 'hono/dev'
import { serveStatic } from '@hono/node-server/serve-static'
import { Hono } from 'hono'

const base = new Hono<any>()

if (import.meta.env.PROD) {
  // static files
  base.use('/static/*', serveStatic({ root: './dist' }))
}

// favicon
base.use('/favicon.ico', serveStatic({root: import.meta.env.PROD ? './dist' : './public'}))

const app = createApp({
  app: base,
})

showRoutes(app)

export default app

production時に実行するエントリーポイントを新規作成

index.ts
import { serve } from '@hono/node-server'
import app from './app/server'

if (import.meta.env.PROD) {  
  serve({
    fetch: app.fetch,
    port: 3000,
    hostname: '0.0.0.0',
  })
}

export default app
vite.config.ts
import { defineConfig } from 'vite'
import honox from 'honox/vite'
import client from 'honox/vite/client'
import { builtinModules } from 'module'

const entry = './index.ts'
const external: string|string[] = []

export default defineConfig(({mode})=>{
  if (mode === 'client') {
    return {
      plugins: [client()]
    }
  } else {
    return {
      ssr: {
        external,
        noExternal: true,
      },
      build: {
        emptyOutDir: false,
        minify: true,
        ssr: true,
        rollupOptions: {
          external: [...builtinModules, /^node:/],
          input: entry,
          output: {
            entryFileNames: 'main.js',
          }
        }
      },
      plugins: [
        honox({ entry }),
      ]
    }
  }
})

この実装でvite build --mode client && vite buildを実行したときの成果物は以下のようになります

.
├── dist
    ├── .vite
    ├── static
    │   └── client-xxxx.js
    ├── favicon.ico
    └── main.js

あとはnode dist/main.jsを実行すればアプリケーションが起動します

デプロイするまではまだ試していないですが、ローカルのnodeで実行確認ができたのでDockerfileを作成すれば問題なくデプロイできるでしょう

Discussion