Skip to content

Commit

Permalink
fix(store): provide NoopNgxsExecutionStrategy explicitly when the z…
Browse files Browse the repository at this point in the history
…one is nooped
  • Loading branch information
arturovt committed Feb 12, 2022
1 parent 90fdd58 commit 1753cb0
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 9 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ $ npm install @ngxs/store@dev
- Fix: Handle mixed async scenarios for action handlers [#1762](https://github.com/ngxs/store/pull/1762)
- Fix: An action with cancelUncompleted enabled should unsubscribe before the next action handler is called [#1763](https://github.com/ngxs/store/pull/1763)
- Fix: Do not run `Promise.then` within synchronous tests when decorating factory [#1753](https://github.com/ngxs/store/pull/1753)
- Fix: Provide `NoopNgxsExecutionStrategy` explicitly when the zone is nooped [#1819](https://github.com/ngxs/store/pull/1819)
- Fix: Devtools Plugin - Do not connect to devtools when the plugin is disabled [#1761](https://github.com/ngxs/store/pull/1761)
- Fix: Router Plugin - Cleanup subscriptions when the root view is destroyed [#1754](https://github.com/ngxs/store/pull/1754)
- Fix: WebSocket Plugin - Cleanup subscriptions and close the connection when the root view is destroyed [#1755](https://github.com/ngxs/store/pull/1755)
Expand Down
4 changes: 2 additions & 2 deletions bundlesize.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,14 @@
"path": "./@ngxs/store/fesm2015/ngxs-store.js",
"package": "@ngxs/store",
"target": "es2015",
"maxSize": "113.70KB",
"maxSize": "115.50KB",
"compression": "none"
},
{
"path": "./@ngxs/store/fesm5/ngxs-store.js",
"package": "@ngxs/store",
"target": "es5",
"maxSize": "132.60KB",
"maxSize": "134.60KB",
"compression": "none"
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { isPlatformServer } from '@angular/common';
import { NgxsExecutionStrategy } from './symbols';
import { getZoneWarningMessage } from '../configs/messages.config';

@Injectable()
@Injectable({ providedIn: 'root' })
export class DispatchOutsideZoneNgxsExecutionStrategy implements NgxsExecutionStrategy {
constructor(private _ngZone: NgZone, @Inject(PLATFORM_ID) private _platformId: string) {
// Caretaker note: we have still left the `typeof` condition in order to avoid
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Injectable } from '@angular/core';

import { NgxsExecutionStrategy } from './symbols';

@Injectable()
@Injectable({ providedIn: 'root' })
export class NoopNgxsExecutionStrategy implements NgxsExecutionStrategy {
enter<T>(func: () => T): T {
return func();
Expand Down
30 changes: 27 additions & 3 deletions packages/store/src/module.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import {
APP_BOOTSTRAP_LISTENER,
InjectionToken,
Injector,
ModuleWithProviders,
NgModule,
Provider
NgZone,
Provider,
Type
} from '@angular/core';
import {
INITIAL_STATE_TOKEN,
Expand All @@ -20,7 +23,7 @@ import {
NgxsModuleOptions,
ROOT_STATE_TOKEN
} from './symbols';
import { NGXS_EXECUTION_STRATEGY } from './execution/symbols';
import { NgxsExecutionStrategy, NGXS_EXECUTION_STRATEGY } from './execution/symbols';
import { StateFactory } from './internal/state-factory';
import { StateContextFactory } from './internal/state-context-factory';
import { Actions, InternalActions } from './actions-stream';
Expand All @@ -33,6 +36,7 @@ import { PluginManager } from './plugin-manager';
import { NgxsRootModule } from './modules/ngxs-root.module';
import { NgxsFeatureModule } from './modules/ngxs-feature.module';
import { DispatchOutsideZoneNgxsExecutionStrategy } from './execution/dispatch-outside-zone-ngxs-execution-strategy';
import { NoopNgxsExecutionStrategy } from './execution/noop-ngxs-execution-strategy';
import { InternalNgxsExecutionStrategy } from './execution/internal-ngxs-execution-strategy';
import { mergeDeep } from './utils/utils';

Expand Down Expand Up @@ -98,7 +102,8 @@ export class NgxsModule {
return [
{
provide: NGXS_EXECUTION_STRATEGY,
useClass: options.executionStrategy || DispatchOutsideZoneNgxsExecutionStrategy
useFactory: NgxsModule.ngxsExecutionStrategyFactory(options.executionStrategy),
deps: [NgZone, Injector]
},
{
provide: ROOT_STATE_TOKEN,
Expand Down Expand Up @@ -145,4 +150,23 @@ export class NgxsModule {
private static getInitialState() {
return InitialState.pop();
}

private static ngxsExecutionStrategyFactory(
executionStrategy: Type<NgxsExecutionStrategy> | undefined
) {
return (ngZone: NgZone, injector: Injector) =>
executionStrategy
? injector.get(executionStrategy)
: injector.get(
// `ngZone` might be an instanceof of `NgZone` either `NoopNgZone`. If the zone is nooped through
// bootstrap options (`{ ngZone: 'noop' })`, then we have to provide `NoopNgxsExecutionStrategy`
// explicitly. Providing `DispatchOutsideZoneNgxsExecutionStrategy` will cause a runtime exception
// `Zone is not defined`, since the `Zone` global will not be exposed by zone.js.
// The `DispatchOutsideZoneNgxsExecutionStrategy` uses `NgZone.isInAngularZone()` which tries to get
// the current zone through `Zone.current` (this will cause a runtime exception).
ngZone instanceof NgZone
? DispatchOutsideZoneNgxsExecutionStrategy
: NoopNgxsExecutionStrategy
);
}
}
2 changes: 1 addition & 1 deletion packages/store/tests/dispatch.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ describe('Dispatch', () => {
}
}

@Injectable()
@Injectable({ providedIn: 'root' })
class FakeExecutionStrategy implements NgxsExecutionStrategy {
enter<T>(func: () => T): T {
return func();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ApplicationRef, NgZone, Component, Type } from '@angular/core';
import { ApplicationRef, NgZone, Component, Type, NgModule } from '@angular/core';
import { TestBed, TestModuleMetadata } from '@angular/core/testing';
import { Observable } from 'rxjs';
import {
Expand All @@ -11,6 +11,11 @@ import {
Actions,
NoopNgxsExecutionStrategy
} from '@ngxs/store';
import { freshPlatform } from '@ngxs/store/internals/testing';
import { BrowserModule } from '@angular/platform-browser';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { NGXS_EXECUTION_STRATEGY } from '../../src/execution/symbols';

describe('NoopNgxsExecutionStrategy', () => {
class ZoneCounter {
Expand Down Expand Up @@ -86,6 +91,33 @@ describe('NoopNgxsExecutionStrategy', () => {
return { zone, store, ticks, get };
}

it(
'should provide NoopNgxsExecutionStrategy as an execution strategy if it is not specified explicitly',
freshPlatform(async () => {
// Arrange
@Component({
selector: 'app-root',
template: ''
})
class TestComponent {}

@NgModule({
imports: [BrowserModule, NgxsModule.forRoot()],
declarations: [TestComponent],
bootstrap: [TestComponent]
})
class TestModule {}

// Act
const { injector } = await platformBrowserDynamic().bootstrapModule(TestModule, {
ngZone: 'noop'
});

// Assert
expect(injector.get(NGXS_EXECUTION_STRATEGY)).toBeInstanceOf(NoopNgxsExecutionStrategy);
})
);

describe('[store.select]', () => {
it('should be performed outside Angular zone, when dispatched from outside zones', () => {
// Arrange
Expand Down

0 comments on commit 1753cb0

Please sign in to comment.