HonoをVercelで動かしてみた(API / SSR HTML編)

HonoはVercelで動作すると聞いていたが、実際に試したことはなかった。Vercel向けにHonoをセットアップする方法と、Vercelでホストするためのファイルの生成方法が説明されている。Vercelにデプロイすると、Honoからのレスポンスが返ってくることが確認できた。さらに、静的HTMLの配信やHonoでSSRした結果の配信も試した。ただし、ワイルドカード(’*’)を利用する場合は注意が必要で、設定の順番によって動作が変わることがある。

広告ここから
広告ここまで

目次

    HonoがVercelで動くらしいという認識はあったのですが、実際に動かしたことがなかったので試してみました。

    Vercel向けにHonoをセットアップする

    create honovercelを指定すればOKです。

    $ npm create hono@latest vercel-hono
    
    create-hono version 0.3.2
    ✔ Using target directory … vercel-hono
    ? Which template do you want to use? › - Use arrow-keys. Return to submit.
      ↑ cloudflare-pages
        cloudflare-workers
        deno
        fastly
        lagon
        lambda-edge
        netlify
        nextjs
        nodejs
    ❯   vercel

    vecel.jsonなど、Vercelでホストするためのファイルが含まれた状態で生成されてきます。

    drwxrwxr-x  8 hideokamoto  staff  256 12 21 14:21 .
    drwxr-xr-x  7 hideokamoto  staff  224 12 21 14:21 ..
    -rw-r--r--  1 hideokamoto  staff    8 12 20 19:31 .gitignore
    -rw-r--r--  1 hideokamoto  staff   34 12 20 19:31 README.md
    drwxrwxr-x  3 hideokamoto  staff   96 12 21 14:21 api
    -rw-r--r--  1 hideokamoto  staff  172 12 20 19:31 package.json
    -rw-r--r--  1 hideokamoto  staff  186 12 20 19:31 tsconfig.json
    -rw-r--r--  1 hideokamoto  staff   92 12 20 19:31 vercel.json

    vercel.jsonには、Honoのアプリケーションコードが配置されているディレクトリへのrewriteルールが設定されています。

    {
      "rewrites": [
        {
          "source": "/api/(.*)",
          "destination": "/api"
        }
      ]
    }

    そのままVercelにデプロイしてみる

    GitHubにコードをpushした後、Vercelにデプロイしてみましょう。Framework PresetOtherで、特にビルド設定などは変更せずに接続します。

    デプロイすると、/apiパスでちゃんとHonoからのレスポンスが返ってきます。

    $ curl https://YOUR-SPACE.vercel.app/api | jq .
      % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                     Dload  Upload   Total   Spent    Left  Speed
    100    25    0    25    0     0    189      0 --:--:-- --:--:-- --:--:--   196
    {
      "message": "Hello Hono!"
    }

    HTMLの配信も試してみる

    どうせならHTMLも配信してHono + Vercelでウェブサイトやアプリを出せるようにしてみましょう。

    静的HTMLだけなら、publicディレクトリに配置するだけ

    SPAのランディング用かSSGなどで生成したものを配置したい場合は、publicディレクトリにHTMLを置くだけで良さそうです。public/index.htmlを追加してみました。

    <!DOCTYPE html>
    <html>
        <body>
            <h1>Hell static page on Vercel</h1>
        </body>
    </html>

    これをVercelにデプロイすると、https://YOUR-SPACE.vercel.app/にこのページが表示されます。

    HonoでSSRした結果を返す

    HonoでHTMLを作って配信したい場合は、vercel.jsonを少し変更します。sourceからapiを除外することで、ルートへのアクセスも/apiディレクトリにあるHonoが動くようにしました。

    {
      "rewrites": [
        {
          "source": "/(.*)",
          "destination": "/api"
        },
      ]
    }

    あとはapi/index.tsにHTMLを返すパスを追加するだけです。

    import { Hono } from 'hono'
    import { handle } from 'hono/vercel'
    
    export const config = {
      runtime: 'edge',
    }
    
    const app = new Hono()
    app.get('/*', async c => {
      return c.html(`
      <!DOCTYPE html>
      <html>
          <body>
              <h1>Hell hono on Vercel</h1>
              <p>We're in the <code>${c.req.path}</code></p>
          </body>
      </html>
      `)
    })
    
    export default handle(app)
    

    これをデプロイすると、Honoで生成したHTMLが表示されます。

    publicディレクトリに配置した HTMLが優先される様子ですので、併用する場合はご注意ください。

    Hono (HTML and API)を使う時の注意点

    これはVercelに限った話ではなさそうですが、ワイルドカード(*)を利用する場合は、追加するタイミングを最後にしましょう。

    import { Hono } from 'hono'
    import { handle } from 'hono/vercel'
    
    export const config = {
      runtime: 'edge',
    }
    
    const app = new Hono()
    const apiApp = new Hono()
    
    apiApp.get('/test', (c) => c.json({ message: 'Hello Hono!!!' }))
    app.route('/api', apiApp)
    app.get('/*', async c => {
      return c.html(`
      <!DOCTYPE html>
      <html>
          <body>
              <h1>Hell hono on Vercel</h1>
              <p>We're in the <code>${c.req.path}</code></p>
          </body>
      </html>
      `)
    })
    
    export default handle(app)
    

    /*のパスを指定する前に、/apiパスを指定しています。逆にすると、/apiへのリクエストもapp.get('/*')側が動いてしまいます。

    HonoにはRouteのパスマッチパターンが何種類かあったはずなので、そちらを使うことで調整できるかもしれません。が、少なくともデフォルトではこのような挙動をしますのでご注意ください。

    広告ここから
    広告ここまで
    Home
    Search
    Bookmark