Cloudflare Pagesの開発でVite使う
Cloudflare Pagesの開発にはwrangler pages dev
が使えるんだけど、引数にコマンドライン渡せるの知らなかった。引数に渡したコマンドが開いたポートをリバースプロキシしてくれる。つまり、vite
コマンドを渡せばViteのdevサーバーをバックエンドにしたWranglerが立ち上がり、裏側ではHMRが効く。これ何が嬉しいって、/functions
でAPIを作った場合にこれまでWranglerとVite2つ立ち上げていたのが1つで済むし、クライアントもAPIサーバーもホットリロード効くのでDXが良い。そして、これを利用すると例えば非常に少ないファイルでReactのSPAが作れる。
まずWranglerにコマンドライン渡せるやつはこんな感じ。
wrangler pages dev --local -- vite
以下のスクショだと、Viteのdevサーバーが5175
で立ったのを検出してWranglerがプロキシしている。
ではこれを利用して、簡単なAPIとそれを受け取って描画するReactアプリを作ってみる。
Pagesでは/functions
以下に置いたTypeScriptをAPIのようにすることができる。Next.jsのpages/api
みたいなの。onRequest
をexport
する。
export function onRequest(context) {
return new Response("Hello, world!")
}
素で書いてもいいが、Webフレームワークを使う。Honoの次期バージョンではCloudflare Pagesのアダプタが用意される。
import { Hono } from 'hono'
import { handle } from 'hono/cloudflare-pages'
const app = new Hono()
app.get('/api', (c) => {
return c.json({
message: 'Hello',
})
})
export const onRequest = handle(app)
これを /functions/api/[[route]].ts
に置けば、/api
以下をハンドリングして、Honoのアプリで扱うことができる。c.req
を使えばリクエストの値を取れるし、c.header()
でレスポンスヘッダを追加したりできる。ふつうにWorkersのアプリを書けるわけだ。
Bindingsも取れた。Pagesは.dev.vars
に環境変数を書く。
NAME=Hono
こうすると、いつものHonoアプリと同じようにc.env.NAME
でとれる。Honoに型を渡せば補完も効く。
Next.jsがPagesで動くけど、たしか環境変数とれないので、その点優れている。なにより、KVやD1も使える(はず)!
さてこれで/api
にAPIが生えたので、それをReactで受け取る。Viteはindex.html
をエントリポイントにするので、空のHTMLを置く。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title></title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
src/main.tsx
はコンポーネントを受け取って、レンダリングしているだけ。App
のように切り出さないとViteのFast Refreshが効かない。
import ReactDOM from 'react-dom/client'
import App from './App'
ReactDOM.createRoot(document.getElementById('root')).render(<App />)
src/App.tsx
ではふつうに/api
を叩ける。
import { useState, useEffect } from 'react'
const App = () => {
const [message, setMessage] = useState('')
useEffect(() => {
const fetchData = async () => {
const res = await fetch('/api')
const data = await res.json()
setMessage(data.message)
}
fetchData()
}, [])
return <h1>{message}</h1>
}
export default App
この開発環境だと、クライントはもちろんだし、サーバー側を変更してもリロードが効く。
フレームワークを使わずにWranglerとViteでできちゃうのがよい。
それで、HonoにはtRPC Serverミドルウェアもあるので、tRPCもふつーにうごく。最小限の構成で動く。
Honoのアプリ。
import { Hono } from 'hono'
import { handle } from 'hono/cloudflare-pages'
import { trpcServer } from '@hono/trpc-server'
import { appRouter } from '../../src/router'
const app = new Hono()
app.all(
'*',
trpcServer({
router: appRouter,
})
)
export const onRequest = handle(app)
クライントでは補完が効く。
これはよい。
ちなみにHonoのv3ではRPC機能が追加され、tRPCよりもっとカジュアルにRPC機能が使える予定。
脱線しましたが、Pages + Viteの開発環境はよさそうという話でした。
コードは以下に置いてあります。
Discussion
undocumentedですが
wrangler pages dev
でプロキシするコマンドは実はnode_modules/.bin
にパスが通ったような状態になっていてnpx
やyarn
なしで動きます.なので,wrangler pages dev -- vite
で十分でscripts
欄が大差ないですが僅かにすっきりします.まさに今回の記事の構成でHonoとPages Functionsを使って開発しているのですが,動いています!まだデプロイしたことなくてローカルのみでの確認ですが...
P.S.
hc
が入ったRCのリリース楽しみに待ってます!コマンドは、そうですね!修正しておきました。ありがとうございます。
hc
入ったRCはもうすぐ出します!そして、意見を募ろうと思ってます。試しました!...が環境変数NAMEがとれず、undefinedに。
ファイル名dev.envではなくdev.varsだと環境変数がとれましたのでご報告します!
うわー。時間を無駄にさせてしまいました。すいません><
記事を修正しておきました!ありがとうございます!