ng-universal icon indicating copy to clipboard operation
ng-universal copied to clipboard

TypeError: Class constructor Type cannot be invoked without 'new' - nest runtime error when using angular library + mikro orm

Open rat-matheson opened this issue 2 years ago • 6 comments

Is there an existing issue for this?

  • [X] I have searched the existing issues

Current behavior

Runtime error when running a nest app. It appears to be related to mixing ES Modules with CommonJS modules but I am unable to deep dive to the point of resolving it on my own.

Minimum reproduction code

https://github.com/rat-matheson/nest-mikro-bug/

Steps to reproduce

I've created the following two repositories to demonstrate the issue.

  • angular library - https://github.com/rat-matheson/nest-mikro-bug-lib/
  • nest application - https://github.com/rat-matheson/nest-mikro-bug/

transformType.ts is in a separate library package generated through the angular cli. It is a simple implementation of the mikro orm Type class

app.service.ts is just a place in my nest application where I tried instantiating the class.

C:\Users\joelw\eclipse-workspace\tower-poi\packages\nest-bug-repo\projects\ngx-tmp\bug-repo\src\transformType.ts:3
export class TransformType<JsType = any, DbType = any> extends Type<JsType, DbType> {
^
TypeError: Class constructor Type cannot be invoked without 'new'
    at new TransformType (C:\Users\joelw\eclipse-workspace\tower-poi\packages\nest-bug-repo\projects\ngx-tmp\bug-repo\src\transformType.ts:3:1)
    at Function.TransformType.newTransform (C:\Users\joelw\eclipse-workspace\tower-poi\packages\nest-bug-repo\projects\ngx-tmp\bug-repo\src\transformType.ts:8:18)
    at Object.<anonymous> (C:\Users\joelw\eclipse-workspace\tower-poi\packages\nest-bug-repo\src\app.service.ts:5:15)
    at Module._compile (node:internal/modules/cjs/loader:1101:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1153:10)
    at Module.load (node:internal/modules/cjs/loader:981:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at Module.require (node:internal/modules/cjs/loader:1005:19)
    at require (node:internal/modules/cjs/helpers:102:18)
    at Object.<anonymous> (C:\Users\joelw\eclipse-workspace\tower-poi\packages\nest-bug-repo\src\app.controller.ts:2:1)

Expected behavior

The nest application should just start normally without throwing the runtime exception. If I move transformType.ts to the nest project and just reference it there, everything starts fine. So something is happening when the class is being packaged in a separate library and imported into the nest application.

I don't think the issue is really related to mikro orm as I've had similar problems trying to include other packages that did not involve mikro orm.

Package

  • [X] I don't know. Or some 3rd-party package
  • [ ] @nestjs/common
  • [ ] @nestjs/core
  • [ ] @nestjs/microservices
  • [ ] @nestjs/platform-express
  • [ ] @nestjs/platform-fastify
  • [ ] @nestjs/platform-socket.io
  • [ ] @nestjs/platform-ws
  • [ ] @nestjs/testing
  • [ ] @nestjs/websockets
  • [x] Other (see below)

Other package

@mikro-orm/core

NestJS version

8.4.4

Packages versions

package.json for the nest application package.json for the angular library

Angular info

Angular CLI: 12.2.17
Node: 16.13.2 (Unsupported)
Package Manager: npm 8.1.0
OS: win32 x64

Angular: 12.2.16
... common, compiler, compiler-cli, core

Package                         Version
---------------------------------------------------------
@angular-devkit/architect       0.1202.17
@angular-devkit/build-angular   12.2.17
@angular-devkit/core            12.2.17
@angular-devkit/schematics      12.2.17
@angular/cli                    12.2.17
@schematics/angular             12.2.17
ng-packagr                      12.2.7
rxjs                            6.6.7
typescript                      4.3.5

Nest Info

[System Information]
OS Version     : Windows 10
NodeJS Version : v16.13.2
NPM Version    : 8.1.0

[Nest CLI]
Nest CLI Version : 8.2.5

[Nest Platform Information]
platform-express version : 8.4.4
schematics version       : 8.0.10
testing version          : 8.4.4
common version           : 8.4.4
core version             : 8.4.4
cli version              : 8.2.5

Node.js version

v16.13.2

In which operating systems have you tested?

  • [ ] macOS
  • [X] Windows
  • [ ] Linux

Other

If I upgrade to angular 13, it only produces .mjs files which I've also had issues incorporating into a nest app, so I'm sticking with angular 12 for the moment. Although in this simple case, it seems a little strange for me to be using angular to create a library that extends Type, I have lots of libraries that are shared between the backend and front end and up until now, the angular cli has been great at managing them.

rat-matheson avatar Apr 28 '22 15:04 rat-matheson

I can't start you repo because I can't install @ngx-tmp/bug-repo. NPM says it is not found

jmcdo29 avatar Apr 28 '22 16:04 jmcdo29

Thanks so much for taking a look at this. I've updated the nest application repository ( nest-mikro-bug ) to use the paths config in the tsconfig.json rather than the private npm repository I was using. You will need to do the following:

  1. get the updated nest-mikro-bug code - it will update the tsconfig.json and the package.json
  2. npm install
  3. switch to nest-mikro-bug-lib and build it-> ng build @ngx-tmp/bug-repo
  4. update the tsconfig.json for nest-mikro-bug to point to your output (in case your workspace has a different name than mine). You need to change this line - tsconfig.json#L22
  5. run nest start to start up nest

rat-matheson avatar Apr 28 '22 16:04 rat-matheson

I tried something new. I built with nest, but than did the following:

  • installed module-alias so I could more clearly specify which bundle I wanted to use
  • ran using "node dist/main.js"

I was careful to use the umd module as this document says it is the format to use for node.js. The result was:

$ node dist/main.js
C:\Users\joelw\eclipse-workspace\tower-poi\packages\ngx-tmp\dist\ngx-tmp\bug-rep
o\bundles\ngx-tmp-bug-repo.umd.js:411
                var _this = _super.apply(this, __spreadArray([], __read(argument
s))) || this;
                                   ^

TypeError: Class constructor Type cannot be invoked without 'new'
    at new TransformType (C:\Users\joelw\eclipse-workspace\tower-poi\packages\ng
x-tmp\dist\ngx-tmp\bug-repo\bundles\ngx-tmp-bug-repo.umd.js:411:29)
    at Function.TransformType.newTransform (C:\Users\joelw\eclipse-workspace\tow
er-poi\packages\ngx-tmp\dist\ngx-tmp\bug-repo\bundles\ngx-tmp-bug-repo.umd.js:41
6:19)

Not sure if it helps much but it is something new. Here's some context around line 411

var TransformType = /** @class */ (function (_super) {
    __extends(TransformType, _super);
    function TransformType() {
        var _this = _super.apply(this, __spreadArray([], __read(arguments))) || this;
        _this.options = {};
        return _this;
    }

rat-matheson avatar Apr 29 '22 22:04 rat-matheson

I made a bit of progress. It seems nestjs was including the umd build from angular package. When I explicitly set the only build to be the esm2015 build in the package.json, nestjs was able to properly load the package at runtime.

//Went from this
{
  "name": "@ngx-tmp/bug-repo",
  "version": "0.0.1",
  "license": "UNLICENSED",
  "peerDependencies": {
    "@mikro-orm/core": "^5.1.3"
  },
  "dependencies": {
    "tslib": "^2.3.0"
  },
  "main": "bundles/ngx-tmp-bug-repo.umd.js",
  "module": "fesm2015/ngx-tmp-bug-repo.js",
  "es2015": "fesm2015/ngx-tmp-bug-repo.js",
  "esm2015": "esm2015/ngx-tmp-bug-repo.js",
  "fesm2015": "fesm2015/ngx-tmp-bug-repo.js",
  "typings": "ngx-tmp-bug-repo.d.ts",
  "sideEffects": false
}

// to this where I updated "main" to point to esm2015
{
  "name": "@ngx-tmp/bug-repo",
  "version": "0.0.1",
  "license": "UNLICENSED",
  "peerDependencies": {
    "@mikro-orm/core": "^5.1.3"
  },
  "dependencies": {
    "tslib": "^2.3.0"
  },
  "main": "esm2015/ngx-tmp-bug-repo.js",
  "module": "fesm2015/ngx-tmp-bug-repo.js",
  "es2015": "fesm2015/ngx-tmp-bug-repo.js",
  "esm2015": "esm2015/ngx-tmp-bug-repo.js",
  "fesm2015": "fesm2015/ngx-tmp-bug-repo.js",
  "typings": "ngx-tmp-bug-repo.d.ts",
  "sideEffects": false
}

Is there a way to somehow tell nestjs which target build to use in the package.json rather than having to manually update items in the node_modules folder?

rat-matheson avatar May 01 '22 17:05 rat-matheson

That generally should be something that typescript is determining, and how node is running, not anything specific to Nest

jmcdo29 avatar May 01 '22 19:05 jmcdo29

Yes, now that I've gone a bit deeper, I can see that you are right. Two possible solutions are:

  1. figuring out some way for angular to get angular to set "main" to the esm2015 build in the package.json
  2. figuring out some way to get nest to use the "esm2015" build instead of "main" from the package.json

For (1), I've looked and I don't see any easy way to do it. I probably have to create a post build script. Do you have any ideas on how to do (2)?

Feel free to close this issue if you have no ideas where to go from here. I was hoping you might know something about the nest build process such that I can either override the module import target or possible set which angular target to use.

rat-matheson avatar May 02 '22 14:05 rat-matheson

https://github.com/nestjs/ng-universal/issues/842#issuecomment-1118243358

kamilmysliwiec avatar Feb 09 '23 10:02 kamilmysliwiec