Cloudflare上のRemixからTCPでデータベースへ直接接続する
目的
CloudflareからTCPで直接データベースに接続する機能は提供されている
ただ、node_compat
のオプションが必要なので、Remixで動作しないので、それの原因調査。
環境設定
Remixのインストール
まず、RemixはCloudflare PagesかCloudflare Workersのどちらかで動作が可能。しかし、node_compat
オプションを指定するにはCloudflare Pagesでは動作しない。なのでCloudflare Workersで作成する必要がある。
$ npx create-remix@latest
作成するのはCloudflare Workersを選択して作成する。
この段階での npm run dev
は特に問題なく動作する。
Pgのインストール
PostgreSQLに接続するためのライブラリを追加して、動作するか確認する。
$ npm install -D @types/pg
$ npm install pg
+ node_compat = true
import { Client } from 'pg'
export async function connection() {
const client = new Client(<database connection url>)
await client.connect()
return client
}
import { useLoaderData } from "@remix-run/react"
import { connection } from "~/lib/db.server"
export const loader = async () => {
const client = await connection()
const result = await client.query({
text: 'SELECT * FROM "tablename"'
})
return { result: JSON.stringify(result.rows[0]) }
}
export default function Test() {
const { result } = useLoaderData<typeof loader>()
return (
<>
test: {result}
</>
)
}
これで、npm run dev
するとエラーになった。
✘ [ERROR] Could not resolve "dns"
node_modules/pg/lib/connection-parameters.js:3:18:
3 │ var dns = require('dns')
╵ ~~~~~
The package "dns" wasn't found on the file system but is built into node. Are you trying to bundle for node? You can use "platform: 'node'" to do that, which will remove this error.
✘ [ERROR] Could not resolve "net"
node_modules/pg/lib/connection.js:3:18:
3 │ var net = require('net')
╵ ~~~~~
The package "net" wasn't found on the file system but is built into node. Are you trying to bundle for node? You can use "platform: 'node'" to do that, which will remove this error.
これで調査の土台が出来上がり?
原因
原因はそもそも remix build
が動かないのが原因だが、Cloudflareのドキュメントにある node_compat
オプションとはそもそも何をやってるかというと関係がある。
node_compat
オプションは wrangler deploy
する際にwranglerがesbuildでビルドする際のオプションに渡される。node_compat
オプションが有効にされていると、 NodeGlobalsPolyfills
と NodeModulesPolyfills
が差し込まれる。
Remixの場合は remix build
でRemixがesbuildでビルドするので、この wrangler deploy
のビルドではなく、Remix側のビルドで実行されるため、ビルドエラーが出る。なので対処としてはRemix側のビルドでwranglerが行っているビルドと同じことをしてあげないとダメ。問題はRemixのビルドに差し込むオプションはないので、これに頼らないとダメかもしれない(´・ω・`)
対処
仕方ないのでRemixのesbuildの設定を変えるためにremix-esbuild-overrideを入れる
$ npm install -D remix-esbuild-override @esbuild-plugins/node-globals-polyfill @esbuild-plugins/node-modules-polyfill
"scripts": {
"postinstall": "remix-esbuild-override",
...
}
import { withEsbuildOverride } from "remix-esbuild-override";
import NodeGlobalsPolyfills from "@esbuild-plugins/node-globals-polyfill";
import NodeModulesPolyfills from "@esbuild-plugins/node-modules-polyfill";
withEsbuildOverride((option, { isServer, isDev }) => {
// update the option
option.plugins = [
NodeGlobalsPolyfills['default']({ buffer: true }),
NodeModulesPolyfills['default'](),
...option.plugins,
];
return option;
});
/** @type {import('@remix-run/dev').AppConfig} */
export default {
...
}
こうやると npm run dev
でビルドと起動が出来て、Remixからデータベースに直接接続することが可能になった。
発展
そもそも node_compat
オプションがCloudflare Pagesでは使えないからCloudflare WorkersでRemix作ったけど、結局Remixのビルドいじって、ビルド済みファイルをアップロードするならCloudflare Pages版のRemixでいいんじゃね?て思ったので、もう1回作り直してみたら動いた。
なので、Cloudflare Workersの全機能が使えなくていいからCloudflare Pagesで作った方が静的ファイルの配信が楽なので、Cloudflare Pagesで作ったサンプルをここに残しておきます。