nx: Unable to Define Bi-directional Relationships using TypeORM (Circular dependency)

Expected Behavior

When using the Nest CLI, I can define bidirectional relationships such as:

menu.entity.ts

@ManyToOne((type) => Brand, brand=> brand.menus)
@JoinColumn()
brand: Brand;

brand.entity.ts

@OneToMany((type) => Menu, menu => menu.brand)
 menus: Menu;

Current Behavior

When you attempt this, you cannot serve the API and you get the errors outlined in Failure Information.

This works COMPLETELY in Nest CLI.

Failure Information (for bugs)

WARNING in Circular dependency detected:
apps/fourburner-api/src/resources/brands/models/brand.entity.ts -> apps/fourburner-api/src/resources/menus/models/menu.entity.ts -> apps/fourburner-api/src/resources/brands/models/brand.entity.ts

WARNING in Circular dependency detected:
apps/fourburner-api/src/resources/menu-item-modifiers/models/menu-item-modifier.entity.ts -> apps/fourburner-api/src/resources/menu-item-modifiers/models/menu-item-modifier.entity.ts

WARNING in Circular dependency detected:
apps/fourburner-api/src/resources/menus/models/menu.entity.ts -> apps/fourburner-api/src/resources/brands/models/brand.entity.ts -> apps/fourburner-api/src/resources/menus/models/menu.entity.ts

WARNING in Circular dependency detected:
apps/fourburner-api/src/resources/orders/models/order.entity.ts -> apps/fourburner-api/src/resources/orders/models/order.entity.ts

WARNING in Circular dependency detected:
apps/fourburner-api/src/resources/restaurants/models/restaurant.entity.ts -> apps/fourburner-api/src/resources/brands/models/brand.entity.ts -> apps/fourburner-api/src/resources/menus/models/menu.entity.ts -> apps/fourburner-api/src/resources/restaurants/models/restaurant.entity.ts

followed by:

ReferenceError: Cannot access 'Brand' before initialization
    at Module.Brand (/Users/leeharris/Desktop/Repos/fourburner/dist/apps/fourburner-api/main.js:1156:97)
    at Module../apps/fourburner-api/src/resources/menus/models/menu.entity.ts (/Users/leeharris/Desktop/Repos/fourburner/dist/apps/fourburner-api/webpack:/apps/fourburner-api/src/resources/menus/models/menu.entity.ts:49:10)
    at __webpack_require__ (/Users/leeharris/Desktop/Repos/fourburner/dist/apps/fourburner-api/webpack:/webpack/bootstrap:19:1)
    at Module../apps/fourburner-api/src/resources/brands/models/brand.entity.ts (/Users/leeharris/Desktop/Repos/fourburner/dist/apps/fourburner-api/main.js:1161:83)
    at __webpack_require__ (/Users/leeharris/Desktop/Repos/fourburner/dist/apps/fourburner-api/webpack:/webpack/bootstrap:19:1)
    at Module../apps/fourburner-api/src/resources/restaurants/models/restaurant.entity.ts (/Users/leeharris/Desktop/Repos/fourburner/dist/apps/fourburner-api/main.js:2664:85)
    at __webpack_require__ (/Users/leeharris/Desktop/Repos/fourburner/dist/apps/fourburner-api/webpack:/webpack/bootstrap:19:1)
    at Module../apps/fourburner-api/src/resources/assignedroles/models/assigned_role.entity.ts (/Users/leeharris/Desktop/Repos/fourburner/dist/apps/fourburner-api/main.js:979:95)
    at __webpack_require__ (/Users/leeharris/Desktop/Repos/fourburner/dist/apps/fourburner-api/webpack:/webpack/bootstrap:19:1)
    at Module../apps/fourburner-api/src/shared/auth/auth.service.ts (/Users/leeharris/Desktop/Repos/fourburner/dist/apps/fourburner-api/main.js:3864:110)

Steps to Reproduce

  1. Create an NX app with Nest.js
  2. Create two entities which have bi-directional relationships
  3. Serve the API using NX

Context

Please provide any relevant information about your setup:

NX Report output:

@nrwl/angular : 9.2.3
  @nrwl/cli : 9.2.3
  @nrwl/cypress : 9.2.3
  @nrwl/eslint-plugin-nx : Not Found
  @nrwl/express : Not Found
  @nrwl/jest : 9.2.3
  @nrwl/linter : 9.2.3
  @nrwl/nest : 9.2.3
  @nrwl/next : Not Found
  @nrwl/node : 9.2.3
  @nrwl/react : Not Found
  @nrwl/schematics : Not Found
  @nrwl/tao : 9.2.3
  @nrwl/web : Not Found
  @nrwl/workspace : 9.2.3
  typescript : 3.8.3

3rd party versions:

"typeorm": "^0.2.24",
"pg": "^8.0.3",

Failure Logs

Included above.

Other

I’ve found this exact bug mentioned across several other products that use NX, but for some reason no bug report here. This is a common thing it seems for NX + NestJS users.

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 42
  • Comments: 36 (4 by maintainers)

Commits related to this issue

Most upvoted comments

Any updates on the issue?

@mmcxii already solved the issue, the answer is to set "module": "commonjs" in the "compilerOptions" of tsconfig

+1 just to keep this issue open

Bumping this. This is also an issue that occurs when using Mikro-ORM. Setting "module": "commonjs" in the "compilerOptions" for the tsconfig in a Nest app does allow the app to compile, but I still get warnings in the terminal.

Ok. After reading the following related issues:

https://github.com/nrwl/nx/issues/1667, https://github.com/typeorm/typeorm/issues/4526, https://github.com/typeorm/typeorm/issues/4190, and https://stackoverflow.com/questions/46589957/es6-modules-and-circular-dependency/46593566#46593566

I think I have a solution that doesn’t involve using interfaces and strings for the @ManyToOne and @OneToMany decorators. Meaning I believe to have figured it out such that you can use standard TypeORM conventions.

So this should work with my solution:

// menu.entity.ts
@ManyToOne((type) => Brand, brand=> brand.menus)
@JoinColumn()
brand: Brand;

//brand.entity.ts
@OneToMany((type) => Menu, menu => menu.brand)
menus: Menu[];

My solution might not work in all scenarios but for a specific scenario involving two files referencing each other, I believe this to work. (Meaning if there is a 3 or more file interlocking circular dependency wibbly-wobbly timey-wimey chain thing, then all bets are off because I didn’t test that). So I’m using nx mono repo with NestJs and TypeORM. The nx builder is using webpack to bundle this stuff up. I left the tsconfig module setting to point to the default (esnext).

BOTTOM LINE: everything is the way you want it to be: everything is default for Nx and NestJs and everything is standard TypeOrm convention.

The Solution

Make sure your entry point imports the @ManyToOne side first!

This produces the ReferenceError: Cannot access 'Brand' before initialization error:

// Main file somewhere
import { Brand } from '<somewhere>/brand.entity.ts'
import { Menu } from '<somewhere>/menu.entity.ts'

This does NOT produce the error:

// Main file somewhere
import { Menu } from '<somewhere>/menu.entity.ts'
import { Brand } from '<somewhere>/brand.entity.ts'

I suspect the reason for this is because the @OneToMany side of the relationship has an array of objects menus: Menu[]; rather than the type itself.

And so if I am correct, then in theory a bi-directional @OneToOne will still produce this issue. So stay tuned for when I encounter that problem. One idea that hasn’t been tested yet is here: https://github.com/typeorm/typeorm/issues/4526#issuecomment-518744567 but I’m not sure if TypeORM relies on the design:type metadata to create objects or not.

+1 I’m blocked from getting started with Nx because of this issue too. As described above the circular dependency works fine using the nest-cli way of building the project.

I fixed that error message by adding compiler option => “module”: “commonjs” in tsconfig.json which is under apps/yournestjsapp but still getting these warnings and i want to get rid of these warnings…

@webberwang circular dependency warnings do not prevent the TS transpiler from finishing transpilation. ReferenceError: Cannot access 'Foo' before initialization is another bug.

@JamesDelfini What’s the actual resolution? Use strings instead of classes like here? That’s a terrible “resolution”.

@bekos Nope, I believe those changes have resolved the issue from my end.

@sinnrrr Sorry for the late reaction. Setting "module": "commonjs" in your tsconfig.app.json and "showCircularDependencies": false" in your angular.json/workspace.json, solves your issue?

yes, but I believe others have issues anyway

I’m able to compile with these settings for tsconfig.app.json

"module": "CommonJS",
"target": "esnext"