node-pg-migrate
node-pg-migrate copied to clipboard
Using ESM migration files causes `ERR_REQUIRE_ESM` error
When a project is set to be an ES module (by setting type
to module
in package.json), adding a migration file that ends in .js
extension in the migrations directory returns the following error when running migration. I suspect this is because the node-pg-migrate
package itself is not an ES module?
/code/node_modules/node-pg-migrate/dist/runner.js:35
throw new Error(`Can't get migration files: ${err.stack}`);
^
Error: Can't get migration files: Error [ERR_REQUIRE_ESM]: require() of ES Module /code/db/migrations/0000-instance-schema.js from /code/node_modules/node-pg-migrate/dist/runner.js not supported.
Instead change the require of 0000-instance-schema.js in /code/node_modules/node-pg-migrate/dist/runner.js to a dynamic import() which is available in all CommonJS modules.
at /code/node_modules/node-pg-migrate/dist/runner.js:24:21
at Array.map (<anonymous>)
at loadMigrations (/code/node_modules/node-pg-migrate/dist/runner.js:19:41)
at async Promise.all (index 0)
at async Object.exports.default (/code/node_modules/node-pg-migrate/dist/runner.js:151:40)
at loadMigrations (/code/node_modules/node-pg-migrate/dist/runner.js:35:15)
at async Promise.all (index 0)
at async Object.exports.default (/code/node_modules/node-pg-migrate/dist/runner.js:151:40)
Contents of migration file are just exporting async up and down functions:
export async function up() {
// do stuff here
}
export async function down() {
// do stuff here
}
Also note, I realize I can automatically create migration files with the node-pg-migrate create {migration-name}
command. But I already had migration files before installing package, and rather not have to rewrite them all from scratch.
Just tried a workaround by renaming all the file extensions in the migrations directory from .js
to .cjs
. But then I get the following error, due to use of import
/export
:
SyntaxError: Cannot use import statement outside a module
Hi @markcellus
I had the same error and this is how it works on my machine :) . My package.json has type: module and I use imports across the app. As yourself I changed the file extension to .cjs.
I generate the migrations with the migrate create cli command and my file will look something like:
exports.shorthands = undefined; exports.up = pgm => { pgm.createTable('tbl', { table properties .... }); }; exports.down = pgm => {};
When running migrate up the ESM complain will go away. Hope it will help you as well. Am not sure if this would be still an open issue and maybe a doc update will solve this.
For anyone wondering how to solve this without changing any file extensions or config. The only requirement is that you need to have ts-node
installed.
You can create a separate tsconfig.json
file that'll only be used for migrations with the following contents, you can call the file any name you want but here I'll be using tsconfig.migrations.json
// tsconfig.migrations.json
{
// Extend the original tsconfig.json
"extends": "./tsconfig.json",
"compilerOptions": {
// Use commonjs instead of esm when compiling the migration files
"module": "CommonJS",
"moduleResolution": "Node"
},
// Tell ts-node to treat any file under the migrations directory as cjs instead of esm
// this basically overrides the "type": "module" in your package.json file
"ts-node": {
"moduleTypes": {
// Change the "migrations" key here to match the path of your migrations folder
"migrations": "cjs"
}
},
// Add the path of your migrations folder and exclude everything else
"include": ["migrations"],
"exclude": ["src"]
}
And now in your package.json
file change your migrate
script to the following
"scripts": {
"migrate": "ts-node --project tsconfig.migrations.json node_modules/node-pg-migrate/bin/node-pg-migrate"
}
and voila.
For anyone else going down this rabbit hole, I was able to get past this and use typescript files with the following recipe. What it basically does is transpiles the ts file into commonjs format, which is compatible with node-pg-migrate
's runner.
- Create another top-level folder for migration stuff called
db
(this may not be strictly necessary but keeps things organized. - Add 2 files inside
db
: package.json:
tsconfig.migrations.json:{ "name": "project-migrations", "type": "commonjs" }
{ "extends": "../tsconfig.json", "compilerOptions": { "verbatimModuleSyntax": false, "module": "CommonJS", }, }
- Configure
node-pg-migrate
to use these files, using command line args, environment variables, orconfig
. I did the latter: config/default.json:{ "db": { "user": "postgres", "password": "password", "host": "localhost", "port": 5432, "database": "yourdb", "migration-filename-format": "utc", "migrations-dir": "./db/migrations", "tsconfig": "./db/tsconfig.migrations.json", "template-file-name": "./db/template.ts" }
That should do it. For reference, I'm using v6.2.2 and TS 5.
My main tsconfig file is this. I don't know if anything here is required, but I'm including it just in case.
{
"extends": "./.svelte-kit/tsconfig.json",
"compilerOptions": {
"allowJs": true,
"checkJs": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"sourceMap": true,
"strict": true,
"moduleResolution": "bundler"
}
}
Finally, template.ts
listed above isn't strictly necessary, but adds import type
to the import statement which quiets an error down in my editor.
Is this still an issue with 7.0.0-alpha.0?