如何在 Node 14 / Sequelize 6 中为 Sequelize 动态创建模型

How to dynamically create the models for Sequelize in Node 14 / Sequelize 6

我有一个在后端使用 Node 和 Sequelize 的项目。它工作正常,直到我不得不将 Node 和 Sequelize 升级到最新版本。我知道我可以降级,但是我的其他项目中使用了 Node 14,我不想弄清楚如何同时使用多个 Node 版本。

我的模型文件夹中有我的索引文件,读取所有模型 js 文件并自动生成模型。

这是我的代码:

'use strict';

import fs from 'fs';
import path from 'path';
import Sequelize from 'sequelize';
// import DataTypes from 'sequelize/lib/data-types';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
import { dirname } from 'path';
const __dirname = dirname(__filename);
const basename = path.basename(__filename);
import config from '../config/config.js';
import { createRequire } from 'module';
const require = createRequire(import.meta.url);
const db = {};

const sequelize = new Sequelize(config);

fs.readdirSync(__dirname)
    .filter((file) => {
        return (
            file.indexOf('.') !== 0 &&
            file !== basename &&
            file.slice(-3) === '.js'
        );
    })
    .forEach((file) => {
        // const model = sequelize['import'](path.join(__dirname, file));
        const model = require(path.join(__dirname, file))(
            sequelize,
            Sequelize.DataTypes
        );
        db[model.name] = model;
    });

Object.keys(db).forEach((modelName) => {
    if (db[modelName].associate) {
        db[modelName].associate(db);
    }
});

注释掉的那一行是我之前用的。但现在 Sequelize 6 删除了导入选项。所以我能够想出一个 hack 来让“require”在那个文件中工作。但是现在的问题是,当我尝试 运行 我的应用程序时,出现此错误:

Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: C:\....\models\Chemicals.js require() of ES modules is not supported. require() of C:\....\models\Chemicals.js from C:\....\models\index.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 Chemicals.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from C:\....\package.json.

如果不需要,我不想将所有模型重命名为“.cjs”。我也不想删除 "type":"module"。

那里的错误就目前而言已经很清楚了,

Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: C:\....\models\Chemicals.js 
require() of ES modules is not supported. 

require() of C:\....\models\Chemicals.js from C:\....\models\index.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 Chemicals.js to end in .cjs, change the requiring 
code to use import(), or remove "type": "module" from C:\....\package.json.

最后一行有三个建议:

  • 重命名 Chemicals.js 以 .cjs 结尾,
  • 更改需要的代码以使用 import(),
  • 从 C:....\package.json.
  • 中删除 "type": "module"

这些建议的一些注意事项:

import() 调用是异步的,因此您需要考虑到这一点,而不是真正的替换下降。 (我觉得很奇怪,如果这大概是一些生产级别的后端代码,那么您正在对任何东西使用同步调用!)。这里的快速重构可能看起来像

'use strict';

import fs from 'fs';
import path from 'path';
import Sequelize from 'sequelize';
// import DataTypes from 'sequelize/lib/data-types';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
import { dirname } from 'path';
const __dirname = dirname(__filename);
const basename = path.basename(__filename);
import config from '../config/config.js';
// no need for these bits any more, always nice
// import { createRequire } from 'module';
// const require = createRequire(import.meta.url);
const db = {};

const sequelize = new Sequelize(config);
fs.readdir(__dirname, (err, files) => {
  if (err)
    console.log(err);
  else {
    const promise_arr = files
          .filter((file) => {
            return (
              file.indexof('.') !== 0 &&
                file !== basename &&
                file.slice(-3) === '.js'
            );
          })
          .map((file) => {
            // const model = sequelize['import'](path.join(__dirname, file));
            return import(path.join(__dirname, file))
          });
    Promise.all(promise_arr).then((models)=>{
      models.forEach((model)=>db[model.name] = model(sequelize,Sequelize.DataTypes)) 
      associateCB()
    })
  }
})

function associateCB(){
  Object.keys(db).forEach((modelName) => {
    if (db[modelName].associate) {
      db[modelName].associate(db);
    }
  });
}
    

修改你的包 json 如果这是作为 npm 库发布的东西,其他东西需要的东西,可能会产生其他后果。看起来不像,所以这个可能是你最好的选择!


.cjs好像也不错,就是忍不住觉得怪怪的!


你为什么会这样: 因为更新到节点 14 后,节点中的 es 模块系统作为一个稳定的、可操作的功能开始生效。 package.json type 设置是此处错误的实际原因。参见 here