diff --git a/CHANGELOG.md b/CHANGELOG.md index 8187e167e..0d82d91dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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) diff --git a/integrations/hello-world-ng11-ivy/bundlesize.config.json b/integrations/hello-world-ng11-ivy/bundlesize.config.json index 7c7141534..094206240 100644 --- a/integrations/hello-world-ng11-ivy/bundlesize.config.json +++ b/integrations/hello-world-ng11-ivy/bundlesize.config.json @@ -3,7 +3,7 @@ { "path": "./dist-integration/main.*.js", "target": "es2015", - "maxSize": "251.35 kB", + "maxSize": "251.05 kB", "compression": "none" } ] diff --git a/packages/store/internals/src/angular.ts b/packages/store/internals/src/angular.ts index e455daaa3..6a15ad4ec 100644 --- a/packages/store/internals/src/angular.ts +++ b/packages/store/internals/src/angular.ts @@ -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(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) || []; @@ -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; diff --git a/packages/store/src/configs/messages.config.ts b/packages/store/src/configs/messages.config.ts index 0f416c674..48d6005ad 100644 --- a/packages/store/src/configs/messages.config.ts +++ b/packages/store/src/configs/messages.config.ts @@ -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. @@ -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 @@ -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.'); +} diff --git a/packages/store/src/decorators/select/symbols.ts b/packages/store/src/decorators/select/symbols.ts index 01d73be32..9133d87d0 100644 --- a/packages/store/src/decorators/select/symbols.ts +++ b/packages/store/src/decorators/select/symbols.ts @@ -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(selector: any): Observable { // 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 { diff --git a/packages/store/src/internal/state-operators.ts b/packages/store/src/internal/state-operators.ts index 809df5d0e..029258007 100644 --- a/packages/store/src/internal/state-operators.ts +++ b/packages/store/src/internal/state-operators.ts @@ -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(val: Partial): StateOperator { return (existingState: Readonly) => { 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) };