You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 22:53:11