💎

Prismaのenumがクライアントビルドに含まれるとモジュールの解決に失敗する

2024/09/23に公開

Prismaのenumをクライアントサイドで動作する箇所で参照していて、クライアントビルドに含まれるような場合、モジュールの解決に失敗します。

Viteのproduction用のビルドで発生するようです。(Remixで問題を確認しましたが、Nuxt.jsでも同じ内容の問題が報告されていました)
Viteの開発サーバだと発生しません。

下記Issueで報告されていますが、まだ直っていない問題になります。(設定による解決方法あり)

エラー内容

ビルド時には、下記のような警告が出ます。(ビルド自体は完了します)

> build
> remix vite:build

vite v5.3.3 building for production...
".prisma/client/index-browser" is imported by ".prisma/client/index-browser?commonjs-external", but could not be resolved – treating it as an external dependency.

この状態でサーバを起動し、ブラウザでアクセスすると、下記のようなエラーがブラウザ上で発生します。

Uncaught TypeError: Failed to resolve module specifier ".prisma/client/index-browser". Relative references must start with either "/", "./", or "../".

解決方法

npm や yarn を使っている場合

Viteのビルドの設定でailiasを指定することで回避できます。
vite.config.ts で、resolve > alias を指定する形です。

export default defineConfig({
  resolve: {
    alias: {
      ".prisma/client/index-browser": "./node_modules/.prisma/client/index-browser.js"
    }
  }
});

この方法は、PrismaのドキュメントにもNuxt.jsでのトラブルシューティングということで記載されていました。

pnpm を使っている場合

pnpmだと、モジュールの管理方法が異なるため、前述の方法だとうまく行きません。
(実際これで嵌りました、、)

alias先のパスに、Prismaのバージョン番号なども入ることになるため、@prisma/clientモジュールの解決パスを元に求める必要があります。

import { createRequire } from 'module'
import path from 'path'
import { defineConfig } from 'vite'

const { resolve } = createRequire(import.meta.url)

const prismaClient = `prisma${path.sep}client`

const prismaClientIndexBrowser = resolve('@prisma/client/index-browser').replace(`@${prismaClient}`, `.${prismaClient}`)

export default defineConfig(() => ({
   resolve: { alias: { '.prisma/client/index-browser': path.relative(__dirname, prismaClientIndexBrowser) } },
}))

この方法は、npmyarnでも使える方法なので、一律こちらを使うほうが間違えがないかもしれません。

Discussion