Closed5

Cloudflare上のRemixからTCPでデータベースへ直接接続する

chimamechimame

環境設定

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
wrangler.toml
+ node_compat = true
lib/db.server.ts
import { Client } from 'pg'

export async function connection() {
  const client = new Client(<database connection url>)
  await client.connect()
  return client
}
app/routes/test.tsx
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.

これで調査の土台が出来上がり?

chimamechimame

原因

原因はそもそも remix build が動かないのが原因だが、Cloudflareのドキュメントにある node_compat オプションとはそもそも何をやってるかというと関係がある。
node_compat オプションは wrangler deploy する際にwranglerがesbuildでビルドする際のオプションに渡される。node_compat オプションが有効にされていると、 NodeGlobalsPolyfillsNodeModulesPolyfills が差し込まれる。

https://github.com/cloudflare/workers-sdk/blob/34f7f4decfa6e1185f3af097e1ac38aa47fa0fb7/packages/wrangler/src/deployment-bundle/bundle.ts#L367-L372

Remixの場合は remix build でRemixがesbuildでビルドするので、この wrangler deploy のビルドではなく、Remix側のビルドで実行されるため、ビルドエラーが出る。なので対処としてはRemix側のビルドでwranglerが行っているビルドと同じことをしてあげないとダメ。問題はRemixのビルドに差し込むオプションはないので、これに頼らないとダメかもしれない(´・ω・`)

https://github.com/aiji42/remix-esbuild-override

chimamechimame

対処

仕方ないのでRemixのesbuildの設定を変えるためにremix-esbuild-overrideを入れる

$ npm install -D remix-esbuild-override @esbuild-plugins/node-globals-polyfill @esbuild-plugins/node-modules-polyfill
package.json
  "scripts": {
    "postinstall": "remix-esbuild-override",
    ...
  }
remix.config.js
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からデータベースに直接接続することが可能になった。

chimamechimame

発展

そもそも node_compat オプションがCloudflare Pagesでは使えないからCloudflare WorkersでRemix作ったけど、結局Remixのビルドいじって、ビルド済みファイルをアップロードするならCloudflare Pages版のRemixでいいんじゃね?て思ったので、もう1回作り直してみたら動いた。

なので、Cloudflare Workersの全機能が使えなくていいからCloudflare Pagesで作った方が静的ファイルの配信が楽なので、Cloudflare Pagesで作ったサンプルをここに残しておきます。

https://github.com/chimame/remix-cloudflare-page-using-tcp-connection

このスクラップは2023/07/29にクローズされました