NESTJS中的TypeORM实体-无法在模块外部使用导入语句

时间:2019-12-21 10:11:35

标签: nestjs typeorm

使用“嵌套新”命令启动新项目。正常工作,直到我向其中添加实体文件。

出现以下错误:

  

从“ typeorm”导入{实体,列,PrimaryGeneratedColumn};

     

^^^^^^^

     

SyntaxError:无法在模块外部使用import语句

我想念什么?

将实体添加到模块:

import { Module } from '@nestjs/common';
import { BooksController } from './books.controller';
import { BooksService } from './books.service';
import { BookEntity } from './book.entity';
import { TypeOrmModule } from '@nestjs/typeorm';

@Module({
  imports: [TypeOrmModule.forFeature([BookEntity])],
  controllers: [BooksController],
  providers: [BooksService],
})
export class BooksModule {}

app.module.ts:

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Connection } from 'typeorm';
import { BooksModule } from './books/books.module';

@Module({
  imports: [TypeOrmModule.forRoot()],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

13 个答案:

答案 0 :(得分:28)

我的假设是您具有一个TypeormModule属性的entities配置,如下所示:

entities: ['src/**/*.entity.{ts,js}']

或喜欢

entities: ['../**/*.entity.{ts,js}']

您收到的错误是因为您试图在ts上下文中导入js文件。只要您不使用webpack,就可以使用它来获取正确的文件

entities: [join(__dirname, '**', '*.entity.{ts,js}`)]

其中join是从path模块导入的。现在__dirname将解析为srcdist,然后分别找到预期的tsjs文件。让我知道是否仍然存在问题。

编辑1/10/2020

以上内容假设配置是通过javascript兼容文件完成的(.js或在TypeormModule.forRoot()传递的参数中)。如果您使用的是ormconfig.json,则应使用

entities: ['dist/**/*.entity.js']

,以便您使用已编译的js文件,而没有机会在代码中使用ts文件。

答案 1 :(得分:14)

在TypeORM文档中,我找到了Typescript的特定部分。

本节说:

全局安装ts-node:

npm install -g ts-node

在package.json的脚本部分下添加typeorm命令

"scripts" {
    ...
    "typeorm": "ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js"    
}

然后您可以运行以下命令:

npm run typeorm migration:run

如果需要将带有破折号的参数传递给npm脚本,则需要 在-之后添加它们。例如,如果您需要生成, 命令是这样的:

npm run typeorm migration:generate -- -n migrationNameHere

这适用于我的文件配置:

{
    "type": "postgres",
    "host": "yourhost",
    "port": 5423,
    "username": "username",
    "password": "password",
    "database": "your_db",
    "synchronize": true,
    "entities": [
        "src/modules/**/*.entity.{ts,js}"
    ],
    "migrations": [
        "src/migrations/**/*.{ts,js}"
    ],
    "cli": {
        "entitiesDir": "src/modules",
        "migrationsDir": "src/migrations"
    }
}

然后您可以运行generate命令。

答案 2 :(得分:9)

正如Jay McDoniel在回答中解释的那样,问题似乎出在ormconfig.json文件中的实体文件的模式匹配:可能是从javascript文件(大概是先前编译的打字稿文件)导入了打字稿文件(模块) )。

删除ts中现有的ormconfig.json全局模式就足够了,以便TypeORM仅加载javascript文件。实体文件的路径应相对于执行节点的工作目录。

   "entities"   : [
      "dist/entity/**/*.js"
   ],
   "migrations" : [
      "dist/migration/**/*.js"
   ],
   "subscribers": [
      "dist/subscriber/**/*.js"
   ],

答案 3 :(得分:4)

这就是我设法修复它的方式。使用单个配置文件,我可以在应用程序 boostrap 或使用 TypeOrm 的 CLI 上运行迁移。

src/config/ormconfig.ts

import parseBoolean from '@eturino/ts-parse-boolean';
import { TypeOrmModuleOptions } from '@nestjs/typeorm';
import * as dotenv from 'dotenv';
import { join } from 'path';

dotenv.config();

export = [
  {
    //name: 'default',
    type: 'mssql',
    host: process.env.DEFAULT_DB_HOST,
    username: process.env.DEFAULT_DB_USERNAME,
    password: process.env.DEFAULT_DB_PASSWORD,
    database: process.env.DEFAULT_DB_NAME,
    options: {
      instanceName: process.env.DEFAULT_DB_INSTANCE,
      enableArithAbort: false,
    },
    logging: parseBoolean(process.env.DEFAULT_DB_LOGGING),
    dropSchema: false,
    synchronize: false,
    migrationsRun: parseBoolean(process.env.DEFAULT_DB_RUN_MIGRATIONS),
    migrations: [join(__dirname, '..', 'model/migration/*.{ts,js}')],
    cli: {
      migrationsDir: 'src/model/migration',
    },
    entities: [
      join(__dirname, '..', 'model/entity/default/**/*.entity.{ts,js}'),
    ],
  } as TypeOrmModuleOptions,
  {
    name: 'other',
    type: 'mssql',
    host: process.env.OTHER_DB_HOST,
    username: process.env.OTHER_DB_USERNAME,
    password: process.env.OTHER_DB_PASSWORD,
    database: process.env.OTHER_DB_NAME,
    options: {
      instanceName: process.env.OTHER_DB_INSTANCE,
      enableArithAbort: false,
    },
    logging: parseBoolean(process.env.OTHER_DB_LOGGING),
    dropSchema: false,
    synchronize: false,
    migrationsRun: false,
    entities: [],
  } as TypeOrmModuleOptions,
];

src/app.module.ts

import configuration from '@config/configuration';
import validationSchema from '@config/validation';
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';
import { LoggerService } from '@shared/logger/logger.service';
import { UsersModule } from '@user/user.module';
import { AppController } from './app.controller';
import ormconfig = require('./config/ormconfig'); //path mapping doesn't work here

@Module({
  imports: [
    ConfigModule.forRoot({
      cache: true,
      isGlobal: true,
      validationSchema: validationSchema,
      load: [configuration],
    }),
    TypeOrmModule.forRoot(ormconfig[0]), //default
    TypeOrmModule.forRoot(ormconfig[1]), //other db
    LoggerService,
    UsersModule,
  ],
  controllers: [AppController],
})
export class AppModule {}

package.json

  "scripts": {
    ...
    "typeorm": "ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js --config ./src/config/ormconfig.ts",
    "typeorm:migration:generate": "npm run typeorm -- migration:generate -n",
    "typeorm:migration:run": "npm run typeorm -- migration:run"
  },

项目结构

src/
├── app.controller.ts
├── app.module.ts
├── config
│   ├── configuration.ts
│   ├── ormconfig.ts
│   └── validation.ts
├── main.ts
├── model
│   ├── entity
│   ├── migration
│   └── repository
├── route
│   └── user
└── shared
    └── logger

答案 4 :(得分:2)

我接下来在 tsconfig.json 文件中进行了更改:

"module": "es6"

收件人:

"module": "commonjs",

对我有帮助

答案 5 :(得分:1)

您需要为应用程序的每个部分都具有一个something.module.ts。它的工作原理类似于Angular。这是使用GraphQL解析器和服务设置的。 REST与控制器有些不同。每个模块可能会有一个实体,如果是GraphQL,则可能有projects.schema.graphql。

projects.module.ts

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ProjectsService } from './projects.service';
import { Projects } from './projects.entity';

import { ProjectsResolvers } from './projects.resolvers';

@Module({
  imports: [
    TypeOrmModule.forFeature([Projects])],
  providers: [
    ProjectsService,
    ProjectsResolvers
  ],

})

export class ProjectsModule {}

答案 6 :(得分:1)

如官方文档中所述,在ormconfig.json中定义entities属性为我解决了这个问题。

// This is your ormconfig.json file

...
"entities": ["dist/**/*.entity{.ts,.js}"]
...

答案 7 :(得分:1)

这对我有用-无需更改您的ormconfig.js。从您的node_modules所在的根目录运行:

ts-node ./node_modules/typeorm/cli.js  migration:generate -n <MirgrationName> -c <ConnectionType>

示例:

ts-node ./node_modules/typeorm/cli.js  migration:create -n AuthorHasMultipleBooks -c development 

答案 8 :(得分:1)

实际上,默认情况下,typeorm旨在与javascript一起使用。

要使用typescript运行迁移,必须告诉typeorm进行。

只需在下面这一行的脚本部分中放入您的package.json:

"typeorm": "ts-node-dev ./node_modules/typeorm/cli.js"

,然后尝试再次迁移:

yarn typeorm migration:run

答案 9 :(得分:1)

与其他人的评论一致 - 实际上,必须依赖生成的代码才能使其工作似乎很愚蠢。我不相信这个解决方案,因为它是其他人的存储库,但它实际上只允许完整的 Typescript 迁移。它依赖于 .env 文件 Typeorm 值而不是 ormconfig.json 虽然我确信它可以被翻译。我发现它有助于我消除对 .js 文件的依赖。

这里是回购: https://github.com/mthomps4/next-now-test/tree/next-typeorm-example

工作原理说明:

除了通常的 .env 或 ormconfig.json 文件,其中包含正确的 localhost db 连接,您还需要在 ormconfig.json 或 .env 文件中正确指定以下内容

TYPEORM_ENTITIES="entities/*.ts"
TYPEORM_MIGRATIONS="migrations/*.ts"
TYPEORM_ENTITIES_DIR="entities"
TYPEORM_MIGRATIONS_DIR="migrations"

注意实体和迁移全局只有 *.ts。另一个非常重要的部分是如何设置您的 npm 脚本以与 ts-node 一起运行。

您需要一个扩展的 tsconfig,其中包含以下内容:

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "module": "commonjs"
  }
}

这就是允许 ts-node 在生成迁移时正确“拾取” .ts 文件的原因。

这个 npm 脚本(DOTENV 部分仅在使用 .env 文件而不是 ormconfig.json 时)指定使用 tsconfig.json

 "local": "DOTENV_CONFIG_PATH=./.env ts-node -P ./tsconfig.yarn.json -r dotenv/config"

它被用作“前体”脚本:

"typeorm:local": "yarn local ./node_modules/typeorm/cli.js"

我不是 100% 确定所有这些都是必要的(您可以全部内联完成),但它对我有用。基本上这表示“使用特定的 .env 文件和特定的 tsconfig 在 ts-node 的上下文中调用 typrorm cli。”在某些情况下,您可以跳过这些配置。

最后,这个脚本现在可以工作了:

"g:migration": "yarn typeorm:local migration:generate -n"

所以通过运行:

npm run g:migration -- User

您将获得基于您当前更改的实体自动生成的迁移文件!

所以 3 个嵌套的 npm 脚本之后,我们有一种非常具体的方法来运行“生成”迁移命令,并使用所有正确的配置来使用 TS 文件。是的 - 难怪有些人仍然反对打字稿,但幸运的是,这确实有效,如果您想尝试一下,看看它是如何“正常工作”的话,上面的示例存储库已经预先配置了所有内容。

答案 10 :(得分:0)

当我遇到此问题时,我正在将Node.js与Typescript和TypeORM一起使用。在ormconfig.json文件中进行配置对我有用。

entities: ['dist/**/*.entity.js']

我的ormconfig.json文件的完整代码:

{
  "type": "mysql",
  "host": "localhost",
  "port": 3306,
  "username": "xxxxxxxx",
  "password": "xxxxxxxx",
  "database": "typescript_orm",
  "synchronize": true,
  "logging": false,
  "migrationTableName": "migrations",
  "entities": [
    "dist/**/*.entity.js"
  ],
  "migrations": [
    "src/migration/**/*.{ts, js}"
  ],
  "suscribers": [
    "src/suscriber/**/*.{ts, js}"
  ],
  "cli": {
    "entitiesDir": "src/model",
    "migrationDir": "src/migration",
    "suscribersDir": "src/suscriber"
  }
}

答案 11 :(得分:0)

支持迁移的配置:

// FILE: src/config/ormconfig.ts

const connectionOptions: ConnectionOptions = {
  
  // Other configs here

  // My ormconfig isn't in root folder
  entities: [`${__dirname}/../**/*.entity.{ts,js}`],
  synchronize: false,
  dropSchema: false,
  migrationsRun: false,
  migrations: [getMigrationDirectory()],
  cli: {
    migrationsDir: 'src/migrations',
  }
}

function getMigrationDirectory() {
    const directory = process.env.NODE_ENV === 'migration' ? 'src' : `${__dirname}`;
    return `${directory}/migrations/**/*{.ts,.js}`;
}

export = connectionOptions;
// FILE package.json

{
  // Other configs here

  "scripts": {
    "typeorm": "NODE_ENV=migration ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js --config src/config/database.ts",
    "typeorm:migrate": "npm run typeorm migration:generate -- -n",
    "typeorm:run": "npm run typeorm migration:run",
    "typeorm:revert": "npm run typeorm migration:revert"
  }
}

答案 12 :(得分:0)

如果您使用 typescript 编写并使用 tsc 创建一个包含已翻译 js 文件的 dist 文件夹,那么您可能遇到了我的问题,它会在此处得到解决。

正如 docs 中提到的,如果您使用 nodemon server.js,那么您将从 js 的角度点击实体,并且它不会识别导入,因为它与 ts 和 es6 相关。但是,如果您想从 ts 文件中导入实体,您应该运行 ts-node server.ts!

我个人认为前者node server.js更安全,因为它更接近实际案例应用。

!!!然而 !!!请务必小心,因为如果更改实体名称,您必须删除 dist 文件夹并重建它,否则会引发错误或意外工作。 发生错误是因为 tsc 将尝试翻译更改和创建的 ts 文件并保留已删除的文件,以便它可以更快地运行!

我希望它有所帮助,因为它肯定会在未来帮助我,因为我几乎可以肯定我会再次忘记它!