使用Nest、TypeORM、Vitest和SWC时遇模块外import语法错误
解决Vitest+SWC环境下TypeORM Glob加载实体的模块语法错误
问题背景
从Jest+ts-node迁移到Vitest+SWC后,仅测试阶段出现SyntaxError: Cannot use import statement outside a module错误,报错指向所有TypeORM实体文件。构建和开发服务器运行正常,手动导入实体到entities数组则测试可正常执行。
核心原因
测试环境中,Vitest的线程池机制或SWC转换配置未覆盖到Glob匹配的实体文件,导致这些文件未被正确转译为兼容测试环境的模块格式,仍保留ES模块语法却被当作CommonJS处理。
解决方案
1. 优化Vitest配置,确保SWC处理所有TS文件
修改vitest.config.ts,调整SWC插件的覆盖范围并统一模块输出格式:
import { defineConfig } from 'vitest/config'; import swc from 'unplugin-swc'; import { config } from 'dotenv'; const env = config({ path: '../.env.test' }).parsed; export default defineConfig({ test: { globals: true, testTimeout: 0, pool: 'threads', poolOptions: { threads: { maxThreads: 1, minThreads: 1, }, }, include: ['**/*.e2e-spec.ts'], root: './..', env, environment: 'node', esbuild: false, // 禁用esbuild,确保所有文件由SWC处理 }, plugins: [ swc.vite({ sourceMaps: true, minify: false, include: ['../src/**/*.ts'], // 明确覆盖src下所有TS文件,包括实体 jsc: { parser: { syntax: 'typescript', decorators: true, dynamicImport: true, }, transform: { legacyDecorator: true, decoratorMetadata: true, }, baseUrl: './..', module: { type: 'es6', // 输出ES模块,匹配Vitest测试环境 }, }, }), ], });
2. 针对测试环境调整TypeORM实体路径
在typeormConfigFactory中,为测试环境单独指定实体路径,确保加载的是TS文件并由SWC实时转换:
export function typeormConfigFactory( configService: ConfigService, ): DataSourceOptions { const migrationsRun = !global.cli && (configService.get(AUTOMIGRATE) || configService.get(DYNO) === HEROKU_PRIMARY_DYNO_NAME); // 测试环境直接用TS实体路径,依赖SWC实时转换 const entitiesPath = IS_TEST_ENVIRONMENT ? [__dirname + '/../../**/*.entity.ts'] : [__dirname + '/../../**/*.entity{.ts,.js}']; return { type: 'mysql', host: configService.get(DB_HOST), port: configService.get(DB_PORT), username: configService.get(DB_USER), password: configService.get(DB_PASS), database: configService.get(DB_NAME), timezone: 'Z', entities: entitiesPath, namingStrategy: new NamingStrategy(), synchronize: false, charset: 'utf8mb4', migrationsRun, logging: IS_TEST_ENVIRONMENT ? [] : ['schema', 'error', 'warn'], migrations: [__dirname + '/../../migrations/**/*{.ts,.js}'], // 测试环境指定模块格式为ES ...(IS_TEST_ENVIRONMENT ? { module: 'es6' } : {}), }; }
3. 统一项目模块配置
确保项目根目录package.json设置ES模块类型:
{ "type": "module" }
4. 检查根目录SWC配置(若存在)
如果项目有.swcrc文件,确保配置与Vitest中的SWC插件一致:
{ "jsc": { "parser": { "syntax": "typescript", "decorators": true, "dynamicImport": true }, "transform": { "legacyDecorator": true, "decoratorMetadata": true }, "module": { "type": "es6" } }, "sourceMaps": true, "minify": false }
原理说明
- 通过SWC明确覆盖所有实体文件的转换流程,确保ES模块语法被正确转译为测试环境兼容格式
- 测试环境直接加载TS实体文件,利用Vitest+SWC的实时转换能力,避免加载未转译的JS文件导致模块冲突
- 统一模块类型为ES,消除CommonJS与ES模块之间的语法兼容问题
内容的提问来源于stack exchange,提问作者Finn Llewellyn
相关产品推荐
相关产品推荐

