Skip to content

Commit cca2514

Browse files
authored
feat(angular): Add Ivy-compatible Angular SDK package (#7264)
Add a new SDK package to our monorepo: `@sentry/angular-ivy`. While this is technically a new SDK, its content and functionality is identical to `@sentry/angular`. Only the build configuration differs: * The Ivy SDK is built with Angular 12, allowing for a compatibility of NG12-15 * The Ivy SDK is built with `compilationMode: partial`, enabeling a build format that is compatible with Angular's Ivy rendering engine. * This means that `ngcc` no longer needs to step in at initial build time to up-compile the SDK. Which is good because `ngcc` will be removed in Angular 16 (angular/angular-cli#24720) * The Ivy SDK's build output follows the Angular Package Format (APF) v12 standard ([spec](https://docs.google.com/document/d/1CZC2rcpxffTDfRDs6p1cfbmKNLA6x5O-NtkJglDaBVs/preview)) which is very similar to APF 10 which we used before (see #4641 for more details) Because functionality-wise there's no difference to `@sentry/angular`, I opted to symlink the source files instead of duplicating them. The only exception is `sdk.ts` which needed some adaption for the new package, like setting the SDK name and adjusting the min version check. For the same reason, this new package currently doesn't contain tests. We'll need to reconsider this approach (symlinking and testing) if we ever need to make package-specific adjustments.
1 parent 4b95c04 commit cca2514

24 files changed

+3309
-129
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
},
3737
"workspaces": [
3838
"packages/angular",
39+
"packages/angular-ivy",
3940
"packages/browser",
4041
"packages/core",
4142
"packages/e2e-tests",

packages/angular-ivy/.eslintrc.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
module.exports = {
2+
env: {
3+
browser: true,
4+
},
5+
extends: ['../../.eslintrc.js'],
6+
ignorePatterns: ['scripts/**/*'],
7+
};

packages/angular-ivy/LICENSE

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
Copyright (c) 2023 Sentry (https://sentry.io) and individual contributors. All rights reserved.
2+
3+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
4+
documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
5+
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
6+
persons to whom the Software is furnished to do so, subject to the following conditions:
7+
8+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
9+
Software.
10+
11+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
12+
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
13+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
14+
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

packages/angular-ivy/README.md

Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
<p align="center">
2+
<a href="https://sentry.io/?utm_source=github&utm_medium=logo" target="_blank">
3+
<img src="https://sentry-brand.storage.googleapis.com/sentry-wordmark-dark-280x84.png" alt="Sentry" width="280" height="84">
4+
</a>
5+
</p>
6+
7+
# Official Sentry SDK for Angular with Ivy Compatibility
8+
9+
## Links
10+
11+
- [Official SDK Docs](https://docs.sentry.io/platforms/javascript/angular/)
12+
13+
## Angular Version Compatibility
14+
15+
**Note**: This SDK is still experimental and not yet stable.
16+
We do not yet make guarantees in terms of breaking changes, version compatibilities or semver.
17+
Please open a Github issue if you experience bugs or would like to share feedback.
18+
19+
This SDK officially supports Angular 12-15 with Angular's new rendering engine, Ivy.
20+
21+
If you're using Angular 10, 11 or a newer Angular version with View Engine instead of Ivy, please use [`@sentry/angular`](https://github.com/getsentry/sentry-javascript/blob/develop/packages/angular/README.md).
22+
23+
If you're using an older version of Angular and experience problems with the Angular SDK, we recommend downgrading the SDK to version 6.x.
24+
Please note that we don't provide any support for Angular versions below 10.
25+
26+
## General
27+
28+
This package is a wrapper around `@sentry/browser`, with added functionality related to Angular. All methods available
29+
in `@sentry/browser` can be imported from `@sentry/angular-ivy`.
30+
31+
To use this SDK, call `Sentry.init(options)` before you bootstrap your Angular application.
32+
33+
```javascript
34+
import { enableProdMode } from '@angular/core';
35+
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
36+
import { init } from '@sentry/angular-ivy';
37+
38+
import { AppModule } from './app/app.module';
39+
40+
init({
41+
dsn: '__DSN__',
42+
// ...
43+
});
44+
45+
// ...
46+
47+
enableProdMode();
48+
platformBrowserDynamic()
49+
.bootstrapModule(AppModule)
50+
.then(success => console.log(`Bootstrap success`))
51+
.catch(err => console.error(err));
52+
```
53+
54+
### ErrorHandler
55+
56+
`@sentry/angular-ivy` exports a function to instantiate an ErrorHandler provider that will automatically send Javascript errors
57+
captured by the Angular's error handler.
58+
59+
```javascript
60+
import { NgModule, ErrorHandler } from '@angular/core';
61+
import { createErrorHandler } from '@sentry/angular-ivy';
62+
63+
@NgModule({
64+
// ...
65+
providers: [
66+
{
67+
provide: ErrorHandler,
68+
useValue: createErrorHandler({
69+
showDialog: true,
70+
}),
71+
},
72+
],
73+
// ...
74+
})
75+
export class AppModule {}
76+
```
77+
78+
Additionally, `createErrorHandler` accepts a set of options that allows you to configure its behavior. For more details
79+
see `ErrorHandlerOptions` interface in `src/errorhandler.ts`.
80+
81+
### Tracing
82+
83+
`@sentry/angular-ivy` exports a Trace Service, Directive and Decorators that leverage the `@sentry/tracing` Tracing
84+
integration to add Angular related spans to transactions. If the Tracing integration is not enabled, this functionality
85+
will not work. The service itself tracks route changes and durations, where directive and decorators are tracking
86+
components initializations.
87+
88+
#### Install
89+
90+
Registering a Trace Service is a 3-step process.
91+
92+
1. Register and configure the `BrowserTracing` integration from `@sentry/tracing`, including custom Angular routing
93+
instrumentation:
94+
95+
```javascript
96+
import { init, instrumentAngularRouting } from '@sentry/angular-ivy';
97+
import { Integrations as TracingIntegrations } from '@sentry/tracing';
98+
99+
init({
100+
dsn: '__DSN__',
101+
integrations: [
102+
new TracingIntegrations.BrowserTracing({
103+
tracingOrigins: ['localhost', 'https://yourserver.io/api'],
104+
routingInstrumentation: instrumentAngularRouting,
105+
}),
106+
],
107+
tracesSampleRate: 1,
108+
});
109+
```
110+
111+
2. Register `SentryTrace` as a provider in Angular's DI system, with a `Router` as its dependency:
112+
113+
```javascript
114+
import { NgModule } from '@angular/core';
115+
import { Router } from '@angular/router';
116+
import { TraceService } from '@sentry/angular-ivy';
117+
118+
@NgModule({
119+
// ...
120+
providers: [
121+
{
122+
provide: TraceService,
123+
deps: [Router],
124+
},
125+
],
126+
// ...
127+
})
128+
export class AppModule {}
129+
```
130+
131+
3. Either require the `TraceService` from inside `AppModule` or use `APP_INITIALIZER` to force-instantiate Tracing.
132+
133+
```javascript
134+
@NgModule({
135+
// ...
136+
})
137+
export class AppModule {
138+
constructor(trace: TraceService) {}
139+
}
140+
```
141+
142+
or
143+
144+
```javascript
145+
import { APP_INITIALIZER } from '@angular/core';
146+
147+
@NgModule({
148+
// ...
149+
providers: [
150+
{
151+
provide: APP_INITIALIZER,
152+
useFactory: () => () => {},
153+
deps: [TraceService],
154+
multi: true,
155+
},
156+
],
157+
// ...
158+
})
159+
export class AppModule {}
160+
```
161+
162+
#### Use
163+
164+
To track Angular components as part of your transactions, you have 3 options.
165+
166+
_TraceDirective:_ used to track a duration between `OnInit` and `AfterViewInit` lifecycle hooks in template:
167+
168+
```javascript
169+
import { TraceModule } from '@sentry/angular-ivy';
170+
171+
@NgModule({
172+
// ...
173+
imports: [TraceModule],
174+
// ...
175+
})
176+
export class AppModule {}
177+
```
178+
179+
Then inside your components template (keep in mind that directive name attribute is required):
180+
181+
```html
182+
<app-header trace="header"></app-header>
183+
<articles-list trace="articles-list"></articles-list>
184+
<app-footer trace="footer"></app-footer>
185+
```
186+
187+
_TraceClassDecorator:_ used to track a duration between `OnInit` and `AfterViewInit` lifecycle hooks in components:
188+
189+
```javascript
190+
import { Component } from '@angular/core';
191+
import { TraceClassDecorator } from '@sentry/angular-ivy';
192+
193+
@Component({
194+
selector: 'layout-header',
195+
templateUrl: './header.component.html',
196+
})
197+
@TraceClassDecorator()
198+
export class HeaderComponent {
199+
// ...
200+
}
201+
```
202+
203+
_TraceMethodDecorator:_ used to track a specific lifecycle hooks as point-in-time spans in components:
204+
205+
```javascript
206+
import { Component, OnInit } from '@angular/core';
207+
import { TraceMethodDecorator } from '@sentry/angular-ivy';
208+
209+
@Component({
210+
selector: 'app-footer',
211+
templateUrl: './footer.component.html',
212+
})
213+
export class FooterComponent implements OnInit {
214+
@TraceMethodDecorator()
215+
ngOnInit() {}
216+
}
217+
```
218+
219+
You can also add your own custom spans by attaching them to the current active transaction using `getActiveTransaction`
220+
helper. For example, if you'd like to track the duration of Angular boostraping process, you can do it as follows:
221+
222+
```javascript
223+
import { enableProdMode } from '@angular/core';
224+
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
225+
import { init, getActiveTransaction } from '@sentry/angular-ivy';
226+
227+
import { AppModule } from './app/app.module';
228+
229+
// ...
230+
231+
const activeTransaction = getActiveTransaction();
232+
const boostrapSpan =
233+
activeTransaction &&
234+
activeTransaction.startChild({
235+
description: 'platform-browser-dynamic',
236+
op: 'ui.angular.bootstrap',
237+
});
238+
239+
platformBrowserDynamic()
240+
.bootstrapModule(AppModule)
241+
.then(() => console.log(`Bootstrap success`))
242+
.catch(err => console.error(err));
243+
.finally(() => {
244+
if (bootstrapSpan) {
245+
boostrapSpan.finish();
246+
}
247+
})
248+
```

packages/angular-ivy/angular.json

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/* To learn more about this file see: https://angular.io/guide/workspace-config */
2+
{
3+
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
4+
"version": 1, // version of angular.json
5+
"projects": {
6+
"sentry-angular-ivy": {
7+
"projectType": "library",
8+
"root": ".",
9+
"sourceRoot": "src",
10+
"architect": {
11+
"build": {
12+
"builder": "@angular-devkit/build-angular:ng-packagr",
13+
"options": {
14+
"project": "ng-package.json"
15+
},
16+
"configurations": {
17+
"production": {
18+
"tsConfig": "tsconfig.ngc.json"
19+
},
20+
"development": {
21+
"tsConfig": "tsconfig.ngc.json"
22+
}
23+
},
24+
"defaultConfiguration": "production"
25+
}
26+
}
27+
}
28+
},
29+
"defaultProject": "sentry-angular-ivy"
30+
}

packages/angular-ivy/ng-package.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"$schema": "node_modules/ng-packagr/ng-package.schema.json",
3+
"dest": "build",
4+
"lib": {
5+
"entryFile": "src/index.ts",
6+
"umdModuleIds": {
7+
"@sentry/browser": "Sentry",
8+
"@sentry/utils": "Sentry.util"
9+
}
10+
},
11+
"allowedNonPeerDependencies": ["@sentry/browser", "@sentry/utils", "@sentry/types", "tslib"],
12+
"assets": ["README.md", "LICENSE"]
13+
}

packages/angular-ivy/package.json

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
{
2+
"name": "@sentry/angular-ivy",
3+
"version": "7.38.0",
4+
"description": "Official Sentry SDK for Angular with full Ivy Support",
5+
"repository": "git://github.com/getsentry/sentry-javascript.git",
6+
"homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/angular-ivy",
7+
"author": "Sentry",
8+
"license": "MIT",
9+
"engines": {
10+
"node": ">=12"
11+
},
12+
"main": "build/bundles/sentry-angular.umd.js",
13+
"module": "build/fesm2015/sentry-angular.js",
14+
"publishConfig": {
15+
"access": "public"
16+
},
17+
"peerDependencies": {
18+
"@angular/common": ">= 12.x <= 15.x",
19+
"@angular/core": ">= 12.x <= 15.x",
20+
"@angular/router": ">= 12.x <= 15.x",
21+
"rxjs": "^6.5.5 || ^7.x"
22+
},
23+
"dependencies": {
24+
"@sentry/browser": "7.38.0",
25+
"@sentry/types": "7.38.0",
26+
"@sentry/utils": "7.38.0",
27+
"tslib": "^2.3.0"
28+
},
29+
"devDependencies": {
30+
"@angular-devkit/build-angular": "~12.2.18",
31+
"@angular/cli": "~12.2.18",
32+
"@angular/common": "~12.2.0",
33+
"@angular/compiler": "~12.2.0",
34+
"@angular/compiler-cli": "~12.2.0",
35+
"@angular/core": "~12.2.0",
36+
"@angular/platform-browser": "~12.2.0",
37+
"@angular/platform-browser-dynamic": "~12.2.0",
38+
"@angular/router": "~12.2.0",
39+
"ng-packagr": "^12.1.1",
40+
"typescript": "~4.3.5",
41+
"zone.js": "~0.11.4"
42+
},
43+
"scripts": {
44+
"build": "yarn build:syncSymlinks && yarn build:transpile",
45+
"build:transpile": "ng build",
46+
"build:dev": "yarn build",
47+
"build:watch": "yarn build:syncSymlinks && yarn build:transpile:watch",
48+
"build:dev:watch": "yarn build:watch",
49+
"build:transpile:watch": "ng build --watch",
50+
"build:tarball": "npm pack ./build",
51+
"build:syncSymlinks": "ts-node ./scripts/syncSourceFiles.ts",
52+
"circularDepCheck": "madge --circular src/index.ts",
53+
"clean": "rimraf build coverage sentry-angular-ivy-*.tgz",
54+
"fix": "run-s fix:eslint fix:prettier",
55+
"fix:eslint": "eslint . --format stylish --fix",
56+
"fix:prettier": "prettier --write \"{src,test,scripts}/**/**.ts\"",
57+
"lint": "run-s lint:prettier lint:eslint",
58+
"lint:eslint": "eslint . --format stylish",
59+
"lint:prettier": "prettier --check \"{src,test,scripts}/**/**.ts\""
60+
},
61+
"volta": {
62+
"extends": "../../package.json"
63+
},
64+
"sideEffects": false
65+
}

0 commit comments

Comments
 (0)