Prismaのseedでimportのエラーが出たときの対処法
3分目次
Next.jsのAPIにORMのPrismaを載せてフルスタックReactをしているときにseedデータを投入しようとしたら依存周りでエラーが出た。
import { PrismaClient } from '@prisma/client';
^^^^^^
SyntaxError: Cannot use import statement outside a module
コード
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()
})
// 略
"prisma": {
"seed": "ts-node prisma/seed.ts"
},
// 略
{
"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
指定部分だけ変更した。
{
"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を指定する。
{
"name": "example",
"private": true,
"scripts": {
// 略
},
"prisma": {
"seed": "ts-node --project prisma/tsconfig-seed.json prisma/seed.ts"
},
最後に