Prismaのseedでimportのエラーが出たときの対処法

3

目次

Next.jsのAPIにORMのPrismaを載せてフルスタックReactをしているときにseedデータを投入しようとしたら依存周りでエラーが出た。

import { PrismaClient } from '@prisma/client';
^^^^^^

SyntaxError: Cannot use import statement outside a module

コード

prisma/seed.ts
import { PrismaClient, Prisma } from '.prisma/client'
import { v4 as uuidv4 } from 'uuid'

const prisma = new PrismaClient()

/** ダミーユーザーx100生成 */
const getUserData = (): Prisma.UserCreateInput[] => {
  const users = []
  for (let i = 0; i < 100; i++) {
    users.push({
      uid: uuidv4(),
      name: `ダミーユーザー${i}`,
      email: 'test@test.com',
    })
  }
  return users
}

const main = async () => {
  console.log(`Start seeding ...`)

  // ユーザーデータ投入
  console.time('INSERT user')
  const users = getUserData()
  users.forEach(async (user) => {
    await prisma.user.create({
      data: user,
    })
  })
  console.timeEnd('INSERT user')

  console.log(`Seeding finished.`)
}

// 処理開始
main()
  .catch((e) => {
    console.error(e)
  })
  .finally(async () => {
    await prisma.$disconnect()
  })
package.json
  // 略
  "prisma": {
    "seed": "ts-node prisma/seed.ts"
  },
  // 略
./tscofig.json
{
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "incremental": true,
    "baseUrl": "./",
    "paths": {
      "@/*": ["./src/*"]
    }
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
  "exclude": ["node_modules"]
}

seedデータの作り方もseedコマンドもPrismaのドキュメント通りで、何より以前ExpressでAPI建てたときにほぼ同じコードで動いてたので謎だった。最初はバージョン差による何かかと思ったが、Next.jsかExpressかというところが原因だった。

解決方法1

src内にprismaフォルダを移動する。

これが最も手取り早い。prismaはinitした段階でルートにできるのでそれをsrcに移動する。ただし、この方法をとるとprismaコマンド実行時にsrcを明示的にする又はsrcに移動する必要があるのでダルい。

解決方法2

package.jsonを新しく作る

原因としてはtsconfig.json内の"module": "esnext",で、これを"module": "commonjs",にすると解決する。

JavaScriptにはいくつかのモジュールパターン(CommonJSやAMD、ECMAScriptなど)がある。TypeScriptをJavaScriptに変換する際、どのモジュールパターンにするかをmoduleに指定する必要がある。 moduleには'none', 'commonjs', 'amd', 'system', 'umd', 'es6', 'es2015', 'esnext'などを指定できる。

参考: tsconfigのmoduleとtargetには何を設定すればいいか - TypeScript

本当はpackage.jsonの"seed": "ts-node prisma/seed.ts"のオプションで--module=commonjs的なものがあればいいのだがなかった。

https://github.com/TypeStrong/ts-node#options

だけどtsconfig.jsonのパスを指定できるものがあったので、元のtsconfigを複製したものを用意し、module指定部分だけ変更した。

./prisma/tscofig-seed.json
{
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "commonjs",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "incremental": true,
    "baseUrl": "./",
    "paths": {
      "@/*": ["./src/*"]
    }
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
  "exclude": ["node_modules"]
}

そしてpackage.json内のseedコマンドのts-nodeで複製したpackage.jsonを指定する。

package.json
{
  "name": "example",
  "private": true,
  "scripts": {
    // 略
  },
  "prisma": {
    "seed": "ts-node --project prisma/tsconfig-seed.json prisma/seed.ts"
  },

最後に

  • SNSでシェアしよう
  • Twitterでシェア
  • FaceBookでシェア
  • Lineでシェア
  • 記事タイトルとURLをコピー
トップへ戻るボタン

\ HOME /

トップへ戻る