Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error applying migrations when using esm and latest LTS node v22.13 #458

Closed
pivotal-djoo opened this issue Jan 24, 2025 · 7 comments
Closed

Comments

@pivotal-djoo
Copy link

Describe the bug
Error message "ERROR: No url defined in config file! Error: No url defined in config file!" is shown when attempting to apply migrations when using esm and node v22.13. The error does not occur using previous versions of node such as v22.10.

To Reproduce
Steps to reproduce the behavior:
Sample repository demonstrating error scenario: /~https://github.com/pivotal-djoo/migrate-mongo-esm-sample

Alternatively, follow these steps:

  1. Run a local instance of mongodb
  2. Install node 22.13
  3. Enable esm by adding "type": "module" in package.json
  4. Initialize migrate-mongo via npx migrate-mongo init -m esm
  5. Configure connection to local MongoDb in migrate-mongo-config.js
  6. Create a migration via npx migrate-mongo create <migration-name>
  7. Run migration via npx migrate-mongo up

Expected behavior
Migrations should apply without any errors.

Additional context
Error message "ERROR: No url defined in config file! Error: No url defined in config file!" is shown.

@d00rsfan
Copy link

d00rsfan commented Jan 25, 2025

Made very fast fix (fork) because it blocking me: can't add migration in project with existing migrations.

lib/env/config.js:60
async read() {
if (customConfigContent) {
return customConfigContent;
}
const configPath = getConfigPath();
const loadedImport = await moduleLoader.import(url.pathToFileURL(configPath));
return loadedImport.default;
}

You may use
"migrate-mongo": "github:d00rsfan/migrate-mongo",
untill author will create new version of this very useful package!

@textbook
Copy link

textbook commented Jan 29, 2025

The problem is that Node 22.12 now requires ESM without an --experimental-... flag. E.g. given esm.js:

export default {
  some: "object",
};

using Node 22.12:

$ node -v
v22.12.0
$ node -p 'require("./esm.js")'
(node:13394) ExperimentalWarning: CommonJS module path/to/[eval] is loading ES Module path/to/esm.js using require().
Support for loading ES Module in require() is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
[Module: null prototype] {
  __esModule: true,
  default: { some: 'object' }
}

whereas 22.11 and before throw the ERR_REQUIRE_ESM that config#read relies on to switch to an import:

try {
return await Promise.resolve(moduleLoader.require(configPath));
} catch (e) {
if (e.code === 'ERR_REQUIRE_ESM') {
const loadedImport = await moduleLoader.import(url.pathToFileURL(configPath));
return loadedImport.default
}
throw e;
}

$ node -v
v22.11.0
$ node -p 'require("./esm.js")'
node:internal/modules/cjs/loader:1681
      throw err;
      ^

Error [ERR_REQUIRE_ESM]: require() of ES Module /Users/jonrsharpe/workspace/classplanner/esm.js from /Users/jonrsharpe/workspace/classplanner/[eval] not supported.
Instead change the require of esm.js in /Users/jonrsharpe/workspace/classplanner/[eval] to a dynamic import() which is available in all CommonJS modules.
    at TracingChannel.traceSync (node:diagnostics_channel:315:14)
    at [eval]:1:1 {
  code: 'ERR_REQUIRE_ESM'
}

The correct fix is to add this behaviour to the non-error path, e.g.:

     try {
-      return await Promise.resolve(moduleLoader.require(configPath));
+      const loadedRequire = await Promise.resolve(moduleLoader.require(configPath));
+      return loadedRequire.__esModule ? loadedRequire.default : loadedRequire;
     } catch (e) {
       if (e.code === 'ERR_REQUIRE_ESM') {
         const loadedImport = await moduleLoader.import(url.pathToFileURL(configPath));
         return loadedImport.default
       }
       throw e;
     }

It should also handle the fact that ERR_REQUIRE_ASYNC_MODULE can still be thrown when require-ing ESM.

@seppevs seppevs closed this as completed Jan 29, 2025
@seppevs
Copy link
Owner

seppevs commented Jan 29, 2025

Fixed in v12

@textbook
Copy link

Unfortunately this has just moved the error; now if you try to use ESM in Node >=22.12 you get:

ERROR: Could not migrate up <esm migration>.js: Expected a function TypeError: Expected a function

This is because the same logic is duplicated in env/migrationsDir#loadMigration:

async loadMigration(fileName) {
const migrationsDir = await resolveMigrationsDirPath();
const migrationPath = path.join(migrationsDir, fileName);
try {
return moduleLoader.require(migrationPath);
} catch (e) {
if (e.code === 'ERR_REQUIRE_ESM') {
return moduleLoader.import(url.pathToFileURL(migrationPath));
}
throw e;
}
},

@seppevs seppevs reopened this Jan 29, 2025
@seppevs
Copy link
Owner

seppevs commented Jan 29, 2025

Weird, I cannot reproduce the issue myself with Node.js v22.13.1 + migrate-mongo using ESM.
But I see that the same logic is present in env/migrationsDir#loadMigration, so I will apply the changes there as well.

seppevs added a commit that referenced this issue Jan 29, 2025
@seppevs
Copy link
Owner

seppevs commented Jan 29, 2025

I've just published v12.0.1, the issue should be resolved. Can you verify? I cannot reproduce the issue.

@seppevs
Copy link
Owner

seppevs commented Jan 29, 2025

I was able to reproduce the issue with this sample repo: /~https://github.com/pivotal-djoo/migrate-mongo-esm-sample
I can confirm that the issue is now resolved (with v12.0.1 or later). I'm closing this.

@seppevs seppevs closed this as completed Jan 29, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants