ng-packagr / ng-packagr

Compile and package Angular libraries in Angular Package Format (APF)
MIT License
1.84k stars 298 forks source link

Version 16 breaks class decorators #2612

Closed henryruhs closed 1 year ago

henryruhs commented 1 year ago

Type of Issue

[x] Bug Report
[ ] Feature Request

Description

My library ngx-crud@13 works perfect, since ngx-crud@16 the decorators stopped working. It seems there is an issue how the constructor has been transformed. I tried to use a copy/paste version of the library decorators on an existing project with the same negative results, that means the transformation of the decorators is not relevant.

Both decorator flags are enabled:

"emitDecoratorMetadata": true,
"experimentalDecorators": true,

Snapshot of the decorators:

export function ApiUrl(apiUrl : string) : Function
{
    return (constructor : Constructor) =>
    {
        constructor.prototype.setApiUrl(apiUrl);
    };
}

export function ApiRoute(apiRoute : string) : Function
{
    return (constructor : Constructor) =>
    {
        constructor.prototype.setApiRoute(apiRoute);
    };
}

Related issues:

https://github.com/ng-packagr/ng-packagr/issues/2487 https://github.com/henryruhs/ngx-crud/issues/51

How To Reproduce

Use ngx-crud 13 vs. 16 within an Angular project:

@Injectable()
@ApiUrl('https://api.chucknorris.io'l)
@ApiRoute('/jokes/random')
export class JokeService extends CrudService<unknown, unknown>
{
}
this.jokeService.getApiUrl(); // should not be undefined
this.jokeService.getApiRoute(); // should not be undefined
this.jokeService.find() // should return a response

Expected Behaviour

Decorator should call related methods to apply values to this.apiUrl and this.apiRoute of the service.

Version Information

$ node_modules/.bin/ng-packagr --version
ng-packagr:            16.0.0
@angular/compiler:     16.0.0
rollup:                3.21.1
typescript:            5.0.4
alan-agius4 commented 1 year ago

Same root cause as https://github.com/ng-packagr/ng-packagr/issues/2611

alan-agius4 commented 1 year ago

Oops, might not be.

Can you try to disable emitDecoratorMetadata, this should not be needed.

henryruhs commented 1 year ago

Do you mean the library or library consumer? I tried to tweak the ´tsconfig.json´ of the library but the generated dist files stay the same - I compared both directories.

I build with nodejs 18 - just tried to build with the Angular 15 dependencies and it works again.

alan-agius4 commented 1 year ago

I looked into this and indeed this is caused by the ECMA 2022 change. To retain the previous behaviour you need to update your tsconfig to set "useDefineForClassFields": false.

diff --git a/package.json b/package.json
index 1377baf..367ab50 100644
--- a/package.json
+++ b/package.json
@@ -61,7 +61,7 @@
        },
        "scripts":
        {
-               "build": "ng-packagr --project=ng-package.json",
+               "build": "ng-packagr --project=ng-package.json --config=tsconfig.json",
                "prepublishOnly": "exit 1",
                "lint": "eslint src tests --ext=.ts",
                "fix": "npm run lint -- --fix",
diff --git a/tsconfig.json b/tsconfig.json
index 1979399..bcd95cb 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,13 +1,7 @@
 {
-       "compilerOptions":
-       {
-               "module": "esnext",
-               "moduleResolution": "node",
-               "emitDecoratorMetadata": true,
-               "experimentalDecorators": true,
-               "lib":
-               [
-                       "esnext"
-               ]
+       "extends": "ng-packagr/lib/ts/conf/tsconfig.ngc.json",
+       "compilerOptions": {
+    "experimentalDecorators": false,
+               "lib": ["esnext"]
        }
 }

It is also worth mentioning, that Angular does not officially support decorators on component classes or other decorated members. See: https://github.com/angular/angular/issues/48276#issuecomment-1332611012

henryruhs commented 1 year ago

It was actual the missing useDefineForClassFields: false that broke it. Please consider to add it to your tsconfig.ngc.json.

Finally, I ended up with this setup:

tsconfig.build.json

{
    "extends": "ng-packagr/lib/ts/conf/tsconfig.ngc.json",
    "compilerOptions":
    {
        "useDefineForClassFields": false
    }
}

npm scripts

"build": "ng-packagr --project=ng-package.json --config=tsconfig.build.json",
github-actions[bot] commented 1 year ago

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

This action has been performed automatically by a bot.