【问题标题】:How to dynamically create the models for Sequelize in Node 14 / Sequelize 6如何在 Node 14 / Sequelize 6 中为 Sequelize 动态创建模型
【发布时间】:2021-06-18 19:54:17
【问题描述】:

我有一个在后端使用 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 删除了导入选项。所以我能够想出一个技巧来让“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"。

【问题讨论】:

    标签: javascript node.js ecmascript-6 sequelize.js


    【解决方案1】:

    那里的错误很明显,

    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);
        }
      });
    }
        
    

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


    .cjs 看起来也不错,但就是不禁觉得它看起来很奇怪!


    为什么会发生这种情况: 因为更新到节点 14 使节点中的 es 模块系统作为一个稳定的、可操作的特性生效。 package.json type 设置是错误的实际原因。见here

    【讨论】:

    • 这似乎奏效了!我收到此错误:TypeError: (intermediate value) is not a function 在线 )(sequelize, Sequelize.DataTypes);。任何想法为什么?
    • 在那个 lil sn-p 中有一个小错误:在 promise 解决之前你不能调用导入的函数,所以只需将实际的函数调用移到 forEach 循环之后所有的承诺。该示例已更改以反映这一点。
    猜你喜欢
    • 2020-01-29
    • 2020-09-19
    • 2014-01-05
    • 2019-08-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-02
    • 1970-01-01
    相关资源
    最近更新 更多