Skip to content

Allow lazy-loading AppSignal in Angular#668

Open
arturovt wants to merge 1 commit intoappsignal:mainfrom
arturovt:refactor/angular
Open

Allow lazy-loading AppSignal in Angular#668
arturovt wants to merge 1 commit intoappsignal:mainfrom
arturovt:refactor/angular

Conversation

@arturovt
Copy link
Copy Markdown

@arturovt arturovt commented Mar 16, 2026

The previous implementation required an instantiated AppSignal object to be passed directly into the error handler, which meant the entire AppSignal bundle had to be eagerly loaded upfront — even if no errors ever occurred.

This change replaces the direct instance with a factory/loader pattern (() => AppSignal | Promise<AppSignal>). The AppSignal instance is now resolved lazily via a defer() observable that only invokes the factory on the first error, with shareReplay ensuring the factory is called exactly once and the result reused for all subsequent errors.

The practical benefit is that consumers can now pass a dynamic import as the loader:

createErrorHandlerFactory(() => import("@appsignal/javascript").then(m => m.default))

This keeps AppSignal out of the main bundle entirely and lets the browser load it on demand, only when something actually goes wrong. For apps where errors are rare or never occur in normal usage, this avoids the network and parse cost of the AppSignal bundle altogether.

Additionally, error reporting is now run outside Angular's zone (NgZone.runOutsideAngular) to prevent the async resolution from triggering unnecessary change detection cycles.

@tombruijn tombruijn requested review from lipskis and unflxw March 17, 2026 10:18
@unflxw
Copy link
Copy Markdown
Contributor

unflxw commented Mar 17, 2026

Hi @arturovt, thanks for the contribution. Could you provide more context? What does this change fix or improve on and how?

@unflxw
Copy link
Copy Markdown
Contributor

unflxw commented Mar 17, 2026

After reading the changes to the README.md (thanks for updating it!) I believe that this lazy-loading approach would break usage patterns in which, for example, you attach breadcrumbs to the Appsignal instance during your application's functioning: https://docs.appsignal.com/front-end/breadcrumbs.html

I don't think that means we cannot merge these changes, but it does mean we'd need to still support the non-lazy-loaded approach alongside the lazy one. That said, it's still unclear to me what the benefit of lazy-loading it is -- the Appsignal instance is a very light plain JavaScript object and does not do any CPU or I/O-bound work upon instantiation.

@arturovt
Copy link
Copy Markdown
Author

@unflxw I have an off-topic question, how do I build appsignal/javascript locally? Because I ain't able to run mono build on Linux (even tho I installed Mono).

@unflxw
Copy link
Copy Markdown
Contributor

unflxw commented Mar 17, 2026

appsignal/mono (this Mono, not the C# interpreter!) should work on Linux just fine, but it should also be possible to manually run the same npm commands that mono would run for you: https://github.com/appsignal/appsignal-javascript/blob/main/packages/javascript/package.json#L13

The previous implementation required an instantiated `AppSignal` object to be passed directly into the error handler, which meant the entire AppSignal bundle had to be eagerly loaded upfront — even if no errors ever occurred.

This change replaces the direct instance with a factory/loader pattern (`() => AppSignal | Promise<AppSignal>`). The AppSignal instance is now resolved lazily via a `defer()` observable that only invokes the factory on the first error, with `shareReplay` ensuring the factory is called exactly once and the result reused for all subsequent errors.

The practical benefit is that consumers can now pass a dynamic import as the loader:

```ts
createErrorHandlerFactory(() => import("@appsignal/javascript").then(m => m.default))
```

This keeps AppSignal out of the main bundle entirely and lets the browser load it on demand, only when something actually goes wrong. For apps where errors are rare or never occur in normal usage, this avoids the network and parse cost of the AppSignal bundle altogether.

Additionally, error reporting is now run outside Angular's zone (`NgZone.runOutsideAngular`) to prevent the async resolution from triggering unnecessary change detection cycles.
@backlog-helper

This comment has been minimized.

4 similar comments
@backlog-helper

This comment has been minimized.

@backlog-helper

This comment has been minimized.

@backlog-helper

This comment has been minimized.

@backlog-helper

This comment has been minimized.

@arturovt
Copy link
Copy Markdown
Author

@unflxw ping me if you need anything to be clarified, I've updated git commit description (see PR description). The docs would need to be fixed too, idk if they're public.

@backlog-helper

This comment has been minimized.

1 similar comment
@backlog-helper

This comment has been minimized.

@unflxw
Copy link
Copy Markdown
Contributor

unflxw commented Mar 30, 2026

Thanks @arturovt, and thanks again so much for proposing this improvement! As someone who's admittedly not deeply familiar with Angular, my main question is still this:

That said, it's still unclear to me what the benefit of lazy-loading it is -- the Appsignal instance is a very light plain JavaScript object and does not do any CPU or I/O-bound work upon instantiation.

That is, by accepting this change, we'd be adding the complexity of an alternative initialisation approach, with the necessary-to-document caveat that it would break certain usage patterns (breadcrumbs, as mentioned above, and also decorators; any usage pattern that is applied before an error is reported to AppSignal) -- so the question is, what is gained in return? I'm interested to know why lazy-loading AppSignal is valuable, what use cases would it enable.

@backlog-helper

This comment has been minimized.

3 similar comments
@backlog-helper

This comment has been minimized.

@backlog-helper

This comment has been minimized.

@backlog-helper
Copy link
Copy Markdown

backlog-helper bot commented Apr 3, 2026


This is a message from the daily scheduled checks.

New issue guide | Backlog management | Rules | Feedback

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants