Skip to content

Commit

Permalink
fix(store): setup unhandled error handler during NGXS initialization (#…
Browse files Browse the repository at this point in the history
…2263)

In this commit, we override the RxJS `config.onUnhandledError` within the root store initializer,
but only after other code has already executed.
If users have a custom `config.onUnhandledError`, we might overwrite it too
early and capture the original `config.onUnhandledError` before it is properly set.
  • Loading branch information
arturovt authored Nov 20, 2024
1 parent 8fe2074 commit a4f3a7f
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 10 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ $ npm install @ngxs/store@dev
- Refactor: Allow tree-shaking of dev-only code [#2259](https://github.com/ngxs/store/pull/2259)
- Fix(store): Allow plain functions in `withNgxsPlugin` [#2255](https://github.com/ngxs/store/pull/2255)
- Fix(store): Run plugins in injection context [#2256](https://github.com/ngxs/store/pull/2256)
- Fix(store): Setup unhandled error handler during NGXS initialization [#2263](https://github.com/ngxs/store/pull/2263)
- Fix(websocket-plugin): Do not dispatch action when root injector is destroyed [#2257](https://github.com/ngxs/store/pull/2257)
- Refactor(store): Replace `exhaustMap` [#2254](https://github.com/ngxs/store/pull/2254)
- Refactor(store): Tree-shake development options token [#2260](https://github.com/ngxs/store/pull/2260)
Expand Down
29 changes: 19 additions & 10 deletions packages/store/src/internal/unhandled-rxjs-error-callback.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,26 @@ import { config } from 'rxjs';

const ɵɵunhandledRxjsErrorCallbacks = new WeakMap<any, VoidFunction>();

const existingHandler = config.onUnhandledError;
config.onUnhandledError = function (error: any) {
const unhandledErrorCallback = ɵɵunhandledRxjsErrorCallbacks.get(error);
if (unhandledErrorCallback) {
unhandledErrorCallback();
} else if (existingHandler) {
existingHandler.call(this, error);
} else {
throw error;
let installed = false;
export function installOnUnhandhedErrorHandler(): void {
if (installed) {
return;
}
};

const existingHandler = config.onUnhandledError;
config.onUnhandledError = function (error: any) {
const unhandledErrorCallback = ɵɵunhandledRxjsErrorCallbacks.get(error);
if (unhandledErrorCallback) {
unhandledErrorCallback();
} else if (existingHandler) {
existingHandler.call(this, error);
} else {
throw error;
}
};

installed = true;
}

export function executeUnhandledCallback(error: any) {
const unhandledErrorCallback = ɵɵunhandledRxjsErrorCallbacks.get(error);
Expand Down
7 changes: 7 additions & 0 deletions packages/store/src/standalone-features/initializers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,20 @@ import { StatesAndDefaults } from '../internal/internals';
import { SelectFactory } from '../decorators/select/select-factory';
import { InternalStateOperations } from '../internal/state-operations';
import { LifecycleStateManager } from '../internal/lifecycle-state-manager';
import { installOnUnhandhedErrorHandler } from '../internal/unhandled-rxjs-error-callback';

/**
* This function is shared by both NgModule and standalone features.
* When using `NgxsModule.forRoot` and `provideStore`, we can depend on the
* same initialization functionality.
*/
export function rootStoreInitializer(): void {
// Override the RxJS `config.onUnhandledError` within the root store initializer,
// but only after other code has already executed.
// If users have a custom `config.onUnhandledError`, we might overwrite it too
// early and capture the original `config.onUnhandledError` before it is properly set.
installOnUnhandhedErrorHandler();

const prebootFns = inject(NGXS_PREBOOT_FNS, { optional: true }) || [];
prebootFns.forEach(prebootFn => prebootFn());

Expand Down

0 comments on commit a4f3a7f

Please sign in to comment.