sequelize / sequelize-typescript

Decorators and some other features for sequelize

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Cannot require() generated Models as ES modules

nemx opened this issue · comments

Issue

I'm having trouble getting my models to be imported correctly by sequelize-typescript. The error is:

Error [ERR_REQUIRE_ESM]: require() of ES Module <root>/packages/api/dist/models/my_model.js from <root>/node_modules/sequelize-typescript/dist/sequelize/sequelize/sequelize-service.js not supported.
Instead change the require of access_method.js in <root>/node_modules/sequelize-typescript/dist/sequelize/sequelize/sequelize-service.js to a dynamic import() which is available in all CommonJS modules.
    at <root>/node_modules/sequelize-typescript/dist/sequelize/sequelize/sequelize-service.js:45:32
    at Array.map (<anonymous>)
    at <root>/node_modules/sequelize-typescript/dist/sequelize/sequelize/sequelize-service.js:43:18
    at Array.reduce (<anonymous>)
    at getModels (<root>/node_modules/sequelize-typescript/dist/sequelize/sequelize/sequelize-service.js:35:20)
    at Sequelize.addModels (<root>/node_modules/sequelize-typescript/dist/sequelize/sequelize/sequelize.js:36:58)
    at new Sequelize (<root>/node_modules/sequelize-typescript/dist/sequelize/sequelize/sequelize.js:20:22)
    at file://<root>/packages/api/dist/db.js:12:26
    at async Promise.all (index 0) {
  code: 'ERR_REQUIRE_ESM'
}

I can see in the sequelize-typescript source that it's trying to require() my models (as opposed to a dynamic import).

Versions

  • sequelize: 6.30.0
  • sequelize-typescript: 2.1.5
  • typescript: 5.0.3
  • node: 16.15.1

Issue type

  • bug report
  • feature request

Actual behavior

After compiling with: npx tsc -p tsconfig.json
And running with: node --experimental-specifier-resolution=node dist/index.js
I'll get the above error.

Expected behavior

No error

Related code

I'm using the models config option to load models like so:

export const sequelize = new Sequelize(svcConfig.databaseURL, {
  // other config
  models: [path.join(__dirname, '/models')],
});

My models are in the format of

@Table({ timestamps: true, tableName: 'MyModel' })
export default class MyModel extends Model {
  @Column({ primaryKey: true, type: DataType.UUIDV4, defaultValue: DataType.UUIDV4 })
  declare id: string;

  @Column
  name!: string;
}

My models get generated (by tsc) like so:

var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var MyModel_1;
import { Column, DataType, ForeignKey, IsUUID, Table, Model, AllowNull } from 'sequelize-typescript';
let MyModel= MyModel_1 = class MyModel extends Model {
    name;
};
__decorate([
    Column({ primaryKey: true, type: DataType.UUIDV4, defaultValue: DataType.UUIDV4 }),
    __metadata("design:type", String)
], MyModel.prototype, "id", void 0);
__decorate([
    Column,
    __metadata("design:type", String)
], MyModel.prototype, "name", void 0);
MyModel = MyModel_1 = __decorate([
    Table({ timestamps: true })
], MyModel);
export default MyModel;

My tsconfig is:

{
  "compilerOptions": {
    "incremental": true,                           
    "target": "es2022",                               
    "experimentalDecorators": true,                
    "emitDecoratorMetadata": true,                 
    "module": "es2022",                             
    "moduleResolution": "node",                  
    "types": ["node"],                                   
    "sourceMap": true,                             
    "outDir": "./dist",                                
    "esModuleInterop": true,                          
    "forceConsistentCasingInFileNames": true,         
    "noImplicitAny": false,                         
    "strictPropertyInitialization": false,          
    "skipLibCheck": true                              
  },
  "include": ["./src/**/*.ts"],
  "exclude": ["node_modules", "**/node_modules/*", "./src/test"],
}
commented

Did you set up "type": "module" in package.json?

Thanks @loss-and-quick. I do have that set. In the end, I think the issue is similar to what this PR is attempting to solve: #1206
I have a few cyclical dependencies arising from, for example, ModelA importing ModelB for a belongsTo declaration, and ModelB hasMany ModelA.
Using models: [path.join(__dirname, '/models')] config, the loader gets stuck when trying to import Model A, which transitively imports B, which will wait until A resolves (it never does, as it's still waiting for B).

I worked around this by importing all the DB models directly in my sequelize config/setup file and passing the Model imports directly to the models option like so: models: [ModelA, ModelB, ModelC]

It's not ideal (as I like the idea of sequelize auto-discovering, importing new models, and not having to explicitly declare them all in a long list), but it does work around using sequelize's module loader code which seems to get stuck on dynamic imports.