Node.js+TypeScript项目Sequelize迁移时出现import语句模块错误
问题:TypeScript Node.js项目执行Sequelize迁移时出现
Syntax Error: Cannot use import statement outside a module 目录结构
├── dist ├── src │ ├── config │ │ └── database.ts │ ├── connection │ │ └── connection.ts │ ├── controllers │ │ └── user.controller.ts │ ├── migrations │ │ └── 20231015073945-create-role.ts │ ├── models │ │ ├── index.ts │ │ └── role.ts │ ├── routes │ │ └── role.router.ts │ ├── seeders │ │ └── 20231015075720-role-data.ts │ └── server.ts ├── .sequelizerc └── package.json
错误原因
Sequelize-CLI默认以CommonJS模块规范执行脚本,但你的代码混用了ES模块(import)和CommonJS(module.exports)语法,同时TypeScript编译配置与运行环境不匹配,导致迁移脚本无法被正确解析。
解决方案
1. 统一配置文件模块语法
修改src/config/database.ts,改用ES模块导出:
import dotenv from 'dotenv'; dotenv.config(); export default { "development": { "username": process.env.DEV_DB_USERNAME, "password": process.env.DEV_DB_PASSWORD, "database": process.env.DEV_DB_NAME, "host": process.env.DEV_DB_HOST, "dialect": process.env.DEV_DB_DATABASE_TYPE, }, "test": { "username": process.env.TEST_DB_USERNAME, "password": process.env.TEST_DB_PASSWORD, "database": process.env.TEST_DB_NAME, "host": process.env.TEST_DB_HOST, "dialect": "mysql" }, "production": { "username": process.env.PROD_DB_USERNAME, "password": process.env.PROD_DB_PASSWORD, "database": process.env.PROD_DB_NAME, "host": process.env.PROD_DB_HOST, "dialect": "mysql" } };
2. 调整迁移文件适配CommonJS
Sequelize-CLI默认不编译TypeScript,迁移文件需改用CommonJS语法:
修改20231015073945-create-role.ts:
'use strict'; const { QueryInterface, DataTypes } = require('sequelize'); module.exports = { async up(queryInterface) { await queryInterface.createTable('roles', { id: { allowNull: false, autoIncrement: true, primaryKey: true, type: DataTypes.INTEGER }, role: { allowNull: false, type: DataTypes.STRING }, isActive: { type: DataTypes.BOOLEAN, defaultValue: true }, createdAt: { allowNull: true, type: DataTypes.DATE }, updatedAt: { allowNull: true, type: DataTypes.DATE } }); }, async down(queryInterface) { await queryInterface.dropTable('roles'); } };
3. 修改tsconfig编译配置
将module设为CommonJS,确保编译产物符合Sequelize-CLI预期:
{ "compilerOptions": { "forceConsistentCasingInFileNames": true, "strict": true, "target": "es2017", "module": "CommonJS", "lib": [ "dom", "es6", "es2017", "esnext.asynciterable" ], "skipLibCheck": true, "sourceMap": true, "outDir": "./dist", "moduleResolution": "node", "removeComments": true, "noImplicitAny": true, "strictNullChecks": true, "strictFunctionTypes": true, "noImplicitThis": true, "noUnusedLocals": true, "noUnusedParameters": true, "noImplicitReturns": true, "noFallthroughCasesInSwitch": true, "allowSyntheticDefaultImports": true, "esModuleInterop": true, "emitDecoratorMetadata": true, "experimentalDecorators": true, "resolveJsonModule": true, "baseUrl": "./src", "paths": { "@/*": ["*"] } }, "exclude": ["node_modules"], "include": ["src/**/*.ts", "server.ts"] }
4. 配置Sequelize-CLI通过ts-node运行
在package.json中添加迁移脚本,让CLI通过ts-node编译TypeScript:
{ "scripts": { "start": "nodemon server.ts", "dev": "nodemon server.ts", "test": "", "build": "tsc", "prestart": "yarn run build", "migrate": "ts-node ./node_modules/sequelize-cli/lib/sequelize db:migrate", "migrate:undo": "ts-node ./node_modules/sequelize-cli/lib/sequelize db:migrate:undo" } }
5. 统一模型文件模块语法
修改src/models/index.ts:
const fs = require('fs'); const path = require('path'); const { Sequelize, DataTypes } = require('sequelize'); const process = require('process'); const basename = path.basename(__filename); const env = process.env.NODE_ENV || 'development'; const config = require(__dirname + '/../config/database.ts')[env]; const db = {}; let sequelize; if (config.use_env_variable) { sequelize = new Sequelize(process.env[config.use_env_variable], config); } else { sequelize = new Sequelize(config.database, config.username, config.password, config); } fs .readdirSync(__dirname) .filter(file => { return ( file.indexOf('.') !== 0 && file !== basename && file.slice(-3) === '.ts' && file.indexOf('.test.ts') === -1 ); }) .forEach(file => { const model = require(path.join(__dirname, file))(sequelize, DataTypes); db[model.name] = model; }); Object.keys(db).forEach(modelName => { if (db[modelName].associate) { db[modelName].associate(db); } }); db.sequelize = sequelize; db.Sequelize = Sequelize; module.exports = db;
修改src/models/role.ts:
'use strict'; const { Model, DataTypes, Sequelize } = require('sequelize'); interface RoleAttributes { id: number; role: string; isActive: boolean; } module.exports = (sequelize) => { class Role extends Model { static associate() { // 定义关联逻辑 } } Role.init({ id: { type: DataTypes.INTEGER, autoIncrement: true, primaryKey: true, }, role: DataTypes.STRING, isActive: DataTypes.BOOLEAN, }, { sequelize, modelName: 'role', }); return Role; };
6. 调整数据库连接文件语法
修改src/connection/connection.ts:
const { Sequelize } = require('sequelize'); const dotenv = require('dotenv'); dotenv.config(); let env; if (process.env.NODE_ENV === 'test') { env = 'test'; } else if (process.env.NODE_ENV === 'production') { env = 'production'; } else { env = 'development'; } const config = require('../config/database.ts')[env]; const sequelize = new Sequelize(config.database, config.username, config.password, config); (async () => { try { await sequelize.authenticate(); console.log('Database connection has been established successfully.'); } catch (err) { console.error('Unable to connect to the database:', err.message); } })(); module.exports = sequelize;
执行迁移
完成以上修改后,运行以下命令执行迁移:
npm run migrate # 或 yarn migrate
内容的提问来源于stack exchange,提问作者Ramcharan
相关产品推荐
相关产品推荐

