Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use the Angular compiler to compile @sentry/angular #4644

Closed
Lms24 opened this issue Feb 25, 2022 · 1 comment · Fixed by #4641
Closed

Use the Angular compiler to compile @sentry/angular #4644

Lms24 opened this issue Feb 25, 2022 · 1 comment · Fixed by #4641

Comments

@Lms24
Copy link
Member

Lms24 commented Feb 25, 2022

Problem Statement

As initially brought up in #3282, our Angular SDK currently causes a compiler error at application build time when TraceDirective or TraceModule are imported and used to trace the initialization spans of (custom) Angular components. While working on this issue it turned out that the fix requires a change to the build procedure of our Angular SDK which will a) fix this problem but b) also allow us to support Angular better in the future.

Currently, our Angular SDK is using tsc as a compiler like most of our JS SDKs. With tsc we can compile our current Angular SDK and it detects and compiles the Angular-specific decorators as (experimental) JS decorators (they are in proposal for JS according to TS docs). During compilation they are treated like JS decorators in the generated JS. In contrast, the Angular compiler, detects Angular specific decorators and compiles them differently s.t. the information in the decorators about components, directives, pipes, etc. is understood correctly by the NG runtime. Running ng build or similar aot compiles projects and libraries to this Angular specific JS that’s understood by the NG runtime.

Example

TraceDirective is an Angular directive and hence the @Directive decorator is used:

@Directive({ selector: '[trace]' })
export class TraceDirective implements OnInit, AfterViewInit {...}

The tsc-compiled output treats the @Directive like a "normal" decorator which is not what Angular expects at application compile time (or runtime):

var TraceDirective = /** @class */ (function () {
    ...
    tslib_1.__decorate([
        core_1.Input('trace')
    ], TraceDirective.prototype, "componentName", void 0);
    TraceDirective = tslib_1.__decorate([
        core_1.Directive({ selector: '[trace]' })
    ], TraceDirective);
    return TraceDirective;
}());
exports.TraceDirective = TraceDirective;

Instead, Angular expects Angular-specific JS syntax that treats the decorators differently. This syntax is even Angular version specific, as for Angular 10 (Ivy Off):

class TraceDirective {...}
TraceDirective.decorators = [
    { type: Directive, args: [{ selector: '[trace]' },] }
];
TraceDirective.propDecorators = {
    componentName: [{ type: Input, args: ['trace',] }]
};

or Angular 13:

class TraceDirective {...}
TraceDirective.ɵfac = i0.ɵɵngDeclareFactory(...);
TraceDirective.ɵdir = i0.ɵɵngDeclareDirective(...);
i0.ɵɵngDeclareClassMetadata(...);

Solution Brainstorm

The solution to this problem is to use the Angular compiler instead of tsc to compile our Angular SDK. After a successful PoC implementation, we're currently tracking the changes required for this in PR #4641. Given that this is a rather big change to our build procedure (possibly even breaking), this will be introduced with v7. It should be noted that this change does not only fix the original bug (#3282) but it also enables us to a) support Angular better in the future (e.g. with additional directives/components/etc.) and it aligns the compilation of our SDK with the recommendations for library creation from the Angular team.

Here's what will change:

  • Instead of tsc we will use the Angular 10 CLI and ng-packagr to build the SDK
    • The produced package conforms to the Angular Package Format (APF) for Angular 10
    • The package will contain the ESM2015, FESM2015 and UMD JS module formats which are all required for Angular 10 libraries.
    • In case an Angular application shall support ES5, the angular CLI will downlevel the ESM2015 JS to ES5 at application compile time.
    • Newer versions of Angular (11-13) will use ngcc or the Angular linker to make the library compatible at application build time.
  • Due to the forward compatibility of Angular libraries, this will limit the usage of the SDK to Angular >= 10, as we will be using Angular 10 to build the SDK. This enables compatibility with Angular 10-13.
    • So far we have not explicitly stated which Angular versions are supported by our SDK, although our peer dependencies also list Angular 10-13.
    • Therefore, people could be using the SDK with earlier versions than Angular 10 which as a result would break their applications if they update to v7. How to procede here remains TBD but one option would be to further offer a tsc-compiled "legacy" version of the SDK for Angular <10 users which will work but not support TraceDirective (and hence TraceModule).
  • Our Angular SDK documentation should be updated w.r.t. supported Angular versions and the usage of TraceDirective.
@AbhiPrasad
Copy link
Member

Updated #4240 (comment) to reflect this!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants