Closed4

Node.jsで作ったReactアプリをHonoで配信したい on DenoDeploy

lsadsfjlsadsfj

やりたいこと

Deno DeployでWebアプリを動かしたい
しかしDenoでフロントエンドやるのは面倒そうだったのでNode.jsで開発したい。

構成は表のとおり

ランタイム 技術スタック
フロントエンド Node.js React, Vite, Tailwind
バックエンド Deno Hono

フロントエンドはDenoで開発しない。
Node.jsで開発して得られた静的ファイルをHonoで配信する。
バックエンドはHonoでフロントエンド向けのAPIを開発する。

やること

  • Node.jsで開発して得られた静的ファイルをHonoで配信できるか
  • 静的ファイルからAPIコールできるか(オリジンを動的にできるか)
  • スムーズに開発するためのまとめ
lsadsfjlsadsfj

Node.jsで開発して得られた静的ファイルをHonoで配信できるか

作業の流れ

  1. 下記テンプレートをそのままビルドして静的ファイル生成
  2. DenoでHonoインストールし静的ファイル配信。ローカルで動作確認
  3. Deno Deploy上で動作確認

1. 下記テンプレートをそのままビルドして静的ファイル生成

下記テンプレートを使用する。
https://github.com/joaopaulomoraes/reactjs-vite-tailwindcss-boilerplate

npm run buildで実行するとdist/に静的ファイルが生成された。

2. DenoでHonoインストールし静的ファイル配信。ローカルで動作確認

下記の流れに沿ってHonoインストール
https://hono.dev/docs/getting-started/deno

静的ファイルをバックエンドのプロジェクト配下に配置

~/tmp/deno-hono-webapp0629$ ls
README.md  deno.json  deno.lock  main.ts  static
~/tmp/deno-hono-webapp0629$ ls static/
assets  favicon.svg  index.html  robots.txt

static/配下の静的ファイル配信するよう設定

import { Hono } from 'hono'
import { serveStatic } from 'hono/deno'

const app = new Hono()

app.use('/*', serveStatic({ root: './static/' }))

Deno.serve(app.fetch)

すると問題なく表示された。

  1. Deno Deploy上で動作確認
    deployctlコマンドでそのままデプロイ
~/tmp/deno-hono-webapp0629$ deployctl deploy --project=hono-webapp0629 --entrypoint=main.ts
~省略~

該当ページにアクセスすると問題なく表示された。

ということで、API叩かない静的ファイルをHonoで配信することはできた。

lsadsfjlsadsfj

静的ファイルからAPIコールできるか(オリジンを動的にできるか)

作業の流れ

  1. バックエンドで簡単なAPI作る
  2. フロントエンドでAPIコールするようにする
  3. ローカルで動かす
  4. Deno Deployで動かす

1. バックエンドで簡単なAPI作る

3パターンの名前をランダムに返すAPIを作った。

app.get('/api/random_name', (c) => {
  const num = Math.floor(Math.random() *3);
  let name;
  switch (num) {
    case 0:
      name = "Alice"
      break
    case 1:
      name = "Bob"
      break
    default:
      name = "Eve"
      break
  }
  return c.json({"name": name})
})

2. フロントエンドでAPIコールするようにする

ロード時にAPIを叩いて取得した名前をコンポーネントに表示するようにした

  const [data, setData] = useState<string>('')

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch(`${APISERVER}/api/random_name`)
        if (!response.ok) {
          throw new Error('Network response was not ok')
        }
        const jsonData = (await response.json()) as RandomNameResponse
        setData(jsonData.name)
      } catch (error) {
        console.error('Error fetching data:', error)
      }
    }

    fetchData()
  }, [])

  return (
    <div className="relative overflow-hidden bg-white">
      <div className="h-screen sm:pb-40 sm:pt-24 lg:pb-48 lg:pt-40">
        <div className="relative mx-auto max-w-7xl px-4 sm:static sm:px-6 lg:px-8">
          <div className="sm:max-w-lg">
            <div className="my-4">
              <Avatar size="large" src={logo} />
            </div>
            <h1 className="text-4xl font-bold tracking-tight text-gray-900 sm:text-6xl">
              Welcome! {data}
            </h1>
~省略~

このとき、APIのオリジンは静的ファイルがホスティングされているサーバのオリジンとしている。
const APISERVER = location.origin

3. ローカルで動かす

  1. フロントエンドのソースをビルド
  2. バックエンドのstatic/に配置
  3. 実行

名前が表示されること確認できた

4. Deno Deployで動かす

deployctlで実行
deployctl deploy --prod --project=hono-webapp0629 --entrypoint=main.

ちゃんと動いた

lsadsfjlsadsfj

まとめ

Node.jsで開発して得られた静的ファイルをHonoで配信することができた。
DBがDeno KVになることさえ許せば趣味程度のWebアプリは作れそう。

すぐ開発できるようテンプレートのようなものを作った。
https://github.com/towa1204/hono-react-webapp

このスクラップは2ヶ月前にクローズされました