Skip to content

Commit

Permalink
perf(store): tree-shake isAngularInTestMode() (ngxs#1739)
Browse files Browse the repository at this point in the history
  • Loading branch information
arturovt authored Apr 27, 2021
1 parent b75d1e6 commit d0a8d95
Show file tree
Hide file tree
Showing 6 changed files with 36 additions and 25 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ $ npm install @ngxs/store@dev

- Fix: Allow to inject the `Store` into the custom error handler [#1708](https://github.com/ngxs/store/pull/1708)
- Performance: Tree-shake errors and warnings [#1732](https://github.com/ngxs/store/pull/1732)
- Performance: Router Plugin - Tree-shake `isAngularInTestMode()` [#1733](https://github.com/ngxs/store/pull/1733)
- Performance: Router Plugin - Tree-shake `isAngularInTestMode()` [#1738](https://github.com/ngxs/store/pull/1738)
- Performance: Tree-shake `isAngularInTestMode()` [#1739](https://github.com/ngxs/store/pull/1739)
- Performance: Storage Plugin - Tree-shake `console.*` calls and expand error messages [#1727](https://github.com/ngxs/store/pull/1727)
- CI: Add bundlesize check for the latest integration app [#1710](https://github.com/ngxs/store/pull/1710)

Expand Down
2 changes: 1 addition & 1 deletion integrations/hello-world-ng11-ivy/bundlesize.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
{
"path": "./dist-integration/main.*.js",
"target": "es2015",
"maxSize": "251.35 kB",
"maxSize": "251.05 kB",
"compression": "none"
}
]
Expand Down
17 changes: 12 additions & 5 deletions packages/store/internals/src/angular.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import { getPlatform, COMPILER_OPTIONS, CompilerOptions, PlatformRef } from '@angular/core';
import { memoize } from './memoize';

// TODO: tree-shake this away in production since we're using it only to check whether
// NGXS is running in test mode!
function _isAngularInTestMode() {
/**
* @description Will be provided through Terser global definitions by Angular CLI
* during the production build. This is how Angular does tree-shaking internally.
*/
declare const ngDevMode: boolean;

function _isAngularInTestMode(): boolean {
const platformRef: PlatformRef | null = getPlatform();
if (!platformRef) return false;
const compilerOptions = platformRef.injector.get<any>(COMPILER_OPTIONS, null);
const compilerOptions = platformRef.injector.get(COMPILER_OPTIONS, null);
if (!compilerOptions) return false;
const isInTestMode = compilerOptions.some((item: CompilerOptions) => {
const providers = (item && item.providers) || [];
Expand All @@ -20,4 +24,7 @@ function _isAngularInTestMode() {
return isInTestMode;
}

export const isAngularInTestMode = memoize(_isAngularInTestMode);
export const isAngularInTestMode =
// Caretaker note: we have still left the `typeof` condition in order to avoid
// creating a breaking change for projects that still use the View Engine.
typeof ngDevMode === 'undefined' || ngDevMode ? memoize(_isAngularInTestMode) : () => false;
24 changes: 14 additions & 10 deletions packages/store/src/configs/messages.config.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
export enum VALIDATION_CODE {
INCORRECT_PRODUCTION = 'INCORRECT_PRODUCTION',
INCORRECT_DEVELOPMENT = 'INCORRECT_DEVELOPMENT',
SELECT_FACTORY_NOT_CONNECTED = 'SELECT_FACTORY_NOT_CONNECTED',
PATCHING_ARRAY = 'PATCHING_ARRAY',
PATCHING_PRIMITIVE = 'PATCHING_PRIMITIVE'
INCORRECT_DEVELOPMENT = 'INCORRECT_DEVELOPMENT'
}

// TODO: these messages might be tree-shaken away in the future.
Expand All @@ -14,12 +11,7 @@ export const CONFIG_MESSAGES = {
'NgxsModule.forRoot(states, { developmentMode: !environment.production })',
[VALIDATION_CODE.INCORRECT_DEVELOPMENT]: () =>
'RECOMMENDATION: Set developmentMode to true on the NgxsModule when Angular is running in development mode.\n' +
'NgxsModule.forRoot(states, { developmentMode: !environment.production })',
[VALIDATION_CODE.SELECT_FACTORY_NOT_CONNECTED]: () =>
'You have forgotten to import the NGXS module!',
// This can be a breaking change if we don't throw these errors even in production mode.
[VALIDATION_CODE.PATCHING_ARRAY]: () => 'Patching arrays is not supported.',
[VALIDATION_CODE.PATCHING_PRIMITIVE]: () => 'Patching primitives is not supported.'
'NgxsModule.forRoot(states, { developmentMode: !environment.production })'
};

// The below functions are decoupled from the `CONFIG_MESSAGES` object for now, since object properties
Expand Down Expand Up @@ -67,3 +59,15 @@ export function getZoneWarningMessage(): string {
export function getUndecoratedStateInIvyWarningMessage(name: string): string {
return `'${name}' class should be decorated with @Injectable() right after the @State() decorator`;
}

export function throwSelectFactoryNotConnectedError(): never {
throw new Error('You have forgotten to import the NGXS module!');
}

export function throwPatchingArrayError(): never {
throw new Error('Patching arrays is not supported.');
}

export function throwPatchingPrimitiveError(): never {
throw new Error('Patching primitives is not supported.');
}
7 changes: 3 additions & 4 deletions packages/store/src/decorators/select/symbols.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
import { Observable } from 'rxjs';

import { CONFIG_MESSAGES, VALIDATION_CODE } from '../../configs/messages.config';
import { propGetter } from '../../internal/internals';
import { SelectFactory } from './select-factory';
import { StateToken } from '../../state-token/state-token';
import { ExtractTokenType } from '../../state-token/symbols';
import { throwSelectFactoryNotConnectedError } from '../../configs/messages.config';

const DOLLAR_CHAR_CODE = 36;

export function createSelectObservable<T = any>(selector: any): Observable<T> {
// We're not adding `ngDevMode` guard since we have still to throw this error until we fix SSR issue.
if (!SelectFactory.store) {
throw new Error(CONFIG_MESSAGES[VALIDATION_CODE.SELECT_FACTORY_NOT_CONNECTED]());
throwSelectFactoryNotConnectedError();
}

return SelectFactory.store.select(selector);
return SelectFactory.store!.select(selector);
}

export function createSelectorFn(name: string, rawSelector?: any, paths: string[] = []): any {
Expand Down
8 changes: 4 additions & 4 deletions packages/store/src/internal/state-operators.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import {
CONFIG_MESSAGES as MESSAGES,
VALIDATION_CODE as CODE
throwPatchingArrayError,
throwPatchingPrimitiveError
} from '../configs/messages.config';
import { StateOperator } from '../symbols';

export function simplePatch<T>(val: Partial<T>): StateOperator<T> {
return (existingState: Readonly<T>) => {
if (Array.isArray(val)) {
throw new Error(MESSAGES[CODE.PATCHING_ARRAY]());
throwPatchingArrayError();
} else if (typeof val !== 'object') {
throw new Error(MESSAGES[CODE.PATCHING_PRIMITIVE]());
throwPatchingPrimitiveError();
}

const newState: any = { ...(existingState as any) };
Expand Down

0 comments on commit d0a8d95

Please sign in to comment.