Using sequelize-cli in Node 14 with type: module
Asked Answered
W

3

17

I'm trying to set up the project using Node v14.3 and sequelize.

I don't want to use babel-register. Instead of this I set "type": "module" in my package.json and use all ES6 - ES11 features out of the box.

I also want to use sequelize-cli for setting up and applying migrations. Everything works except the following command:

& sequelize db:migrate

Sequelize CLI [Node: 14.3.0, CLI: 5.5.1, ORM: 5.21.11]

Loaded configuration file "config/config.json".
Using environment "development".
== 20200530214311-create-user: migrating =======

ERROR: Must use import to load ES Module: /home/kasheftin/work/tests/chai-http-publication/migrations/20200530214311-create-user.js
require() of ES modules is not supported.
require() of /home/kasheftin/work/tests/chai-http-publication/migrations/20200530214311-create-user.js from /home/kasheftin/.nvm/versions/node/v14.3.0/lib/node_modules/sequelize-cli/node_modules/umzug/lib/migration.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.
Instead rename 20200530214311-create-user.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from /home/kasheftin/work/tests/chai-http-publication/package.json.

We see that under the hood sequelize-cli uses require(). That's not allowed for ES Module. It suggests 3 ways to solve this:

  • rename 20200530214311-create-user.js to end in .cjs - Can not be done, sequelize-cli does not find migrations that end with .cjs.

  • Change the requiring code to use import() - I don't want to touch sequelize-cli code.

  • Remove "type": "module" - I can not because everything stops working.

Is there any other way to make sequelize-cli work? I'm using tests heavily and I want the test database to be prepared automatically before running tests.

Weeden answered 31/5, 2020 at 19:14 Comment(8)
github.com/sequelize/cli/issues/861 is still open. Maybe you can use a workaround only?Comedic
Thanks, @Anatoly. Installing the babel-core package and adding require("babel-core/register"); to my config.cjs file did the trick for me, just like mentioned in the link. Besides that, I also needed to install babel-preset-env in order to get it working.Lentiginous
You're not a author of the original question. Can I copy my comment as an answer?Comedic
Yes. So the answer is it's not possible at the moment.Weeden
So I can't use sequelize-cli with Nodejs v14's ES6? Ok, now my whole project is officially screwed upDimorphous
Anatoly @Comedic that link isn’t working anymore? But the issue doesn’t appear to be resolved or has something changed. I have identical issue. Can someone confirm that if I use Babel as the work around that when I go live everything will work? I guess alternative is to refactor my backend code to es5 standard, which would be a shame I’d like to benefit from node 14 ability. ThanksManhood
There is babel-register mentioned in the official documentation: sequelize.org/master/manual/migrations.html. It seems this is the official way to use es6Comedic
thanks for replying, i'll look in toManhood
S
8

A solution is to add a package.json in your migrations folder to override the type: "module" from your main package.json

This package.json would look like this:

{
  "type": "commonjs"
}

and your migration file have to look like this:

module.exports = {
  up: async (queryInterface, Sequelize) => {

  },

  down: async (queryInterface, Sequelize) => {

  }
};

It works well with nodeJS 14.16.1 & Sequelize 6.6.2 & sequelize-cli 6.2.0

Slaughterhouse answered 5/5, 2021 at 9:39 Comment(3)
This works for me with NodeJS 18 and Sequelize 6.19.0Cleanthes
it works, but break other app functionalitiesVillain
@mohammadJavadGhasemy if you create the package.json in a specific folder it's not supposed to break anythingSlaughterhouse
T
2

I got this to work by creating a .sequelizerc file to let sequelize know that I am overriding the default paths:

// .sequelizerc
const path = require('path');

const db_path = './';

module.exports = {
  'config': path.resolve(db_path, 'config/config.cjs'),
  'models-path': path.resolve(db_path, 'models'),
  'seeders-path': path.resolve(db_path, 'seeders'),
  'migrations-path': path.resolve(db_path, 'migrations')
};

Notice that I am using a config.cjs file. Then just create a migration but change the extension to .cjs as well:

// 20211206164144-create_subjects_table.cjs
const tableName = 'subjects';

module.exports = {
  up: async (queryInterface, Sequelize) => {
    await queryInterface.createTable(tableName, {
      id: {
        type: Sequelize.UUID,
        defaultValue: Sequelize.UUIDV4,
        allowNull: false,
        primaryKey: true,
      },
      title: {
        type: Sequelize.STRING,
        required: true,
      },
      created_at: {
        type: Sequelize.DATE,
      },
      updated_at: {
        type: Sequelize.DATE,
      },
      deleted_at: {
        type: Sequelize.DATE,
      },
    });
  },

  down: async (queryInterface) => {
    await queryInterface.dropTable('subjects');
  },
};

This is working with Node.js version v16.13.1 and the following package.json:

{
  "type": "module",
  "dependencies": {
    "pg": "^8.7.1",
    "pg-hstore": "^2.3.4",
    "sequelize": "^6.12.0-beta.1"
  },
  "devDependencies": {
    "sequelize-cli": "^6.3.0"
  }
}
Tungting answered 6/12, 2021 at 17:14 Comment(1)
your sequelizerc file is using commonjs, now change that to esm and see the errors it popsSatiable
C
1

I've had the same issue for months now. Babel register would just not work while using ES module imports and Sequelize cli.

Here's how I eventually got everything to work properly. I had to copy src to a dist directory. Then override the type in package json. Hopefully this helps out 🍻

.sequelizerc

require('@babel/register')({
  presets: [
    ['@babel/preset-env', { targets: { node: 'current' } }]
  ]
});
const path = require('path');

const DB_PATH = 'dist/db'; // use dist instead of src directory

module.exports = {
  'config': path.resolve(DB_PATH, 'config.json'),
  'models-path': path.resolve(DB_PATH, 'models'),
  'seeders-path': path.resolve(DB_PATH, 'seeders'),
  'migrations-path': path.resolve(DB_PATH, 'migrations')
};

package.json

{
  "type": "module",
  "engines": {
    "node": ">=14.18",
    "yarn": ">=1.22"
  },
  "scripts": {
    "start": "node --experimental-specifier-resolution=node src",
    "db": "sequelize db:migrate && sequelize db:seed:all",
    "predb": "yarn dist",
    "dist": "cp -r src dist",
    "predist": "rm -rf dist",
    "postdist": "node setup-dist.js"
  },
  "dependencies": {
    "@babel/core": "^7.16.0",
    "@babel/preset-env": "^7.16.0",
    "@babel/register": "^7.16.0",
    "sequelize": "^6.8.0",
    "sequelize-cli": "^6.2.0"
  }
}

setup-dist.js

import { writeFileSync } from 'fs';

const file = './dist/package.json';
const data = '{ "type": "" }'; // to override ESM in main package.json

writeFileSync(file, data);

Reference: https://gist.github.com/elawad/c0af86ea37629ad0538c2b974b4ea0c1

Chiarra answered 1/11, 2021 at 19:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.