Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: allow tree-shaking of dev-only code #2259

Merged
merged 1 commit into from
Nov 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ $ npm install @ngxs/store@dev

### To become next patch version

- Refactor: Allow tree-shaking of dev-only code [#2259](https://github.com/ngxs/store/pull/2259)
- Refactor: Use field initializers for injectees [#2258](https://github.com/ngxs/store/pull/2258)
- Fix(store): Run plugins in injection context [#2256](https://github.com/ngxs/store/pull/2256)
- Fix(websocket-plugin): Do not dispatch action when root injector is destroyed [#2257](https://github.com/ngxs/store/pull/2257)
Expand Down
6 changes: 2 additions & 4 deletions packages/router-plugin/internals/src/symbols.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ import { InjectionToken } from '@angular/core';

declare const ngDevMode: boolean;

const NG_DEV_MODE = typeof ngDevMode !== 'undefined' && ngDevMode;

export const enum NavigationActionTiming {
PreActivation = 1,
PostActivation = 2
Expand All @@ -14,12 +12,12 @@ export interface NgxsRouterPluginOptions {
}

export const ɵUSER_OPTIONS = new InjectionToken<NgxsRouterPluginOptions | undefined>(
NG_DEV_MODE ? 'USER_OPTIONS' : '',
typeof ngDevMode !== 'undefined' && ngDevMode ? 'USER_OPTIONS' : '',
{ providedIn: 'root', factory: () => undefined }
);

export const ɵNGXS_ROUTER_PLUGIN_OPTIONS = new InjectionToken<NgxsRouterPluginOptions>(
NG_DEV_MODE ? 'NGXS_ROUTER_PLUGIN_OPTIONS' : '',
typeof ngDevMode !== 'undefined' && ngDevMode ? 'NGXS_ROUTER_PLUGIN_OPTIONS' : '',
{ providedIn: 'root', factory: () => ({}) }
);

Expand Down
10 changes: 4 additions & 6 deletions packages/storage-plugin/internals/src/symbols.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ export const ɵDEFAULT_STATE_KEY = '@@STATE';

declare const ngDevMode: boolean;

const NG_DEV_MODE = typeof ngDevMode !== 'undefined' && ngDevMode;

export const enum StorageOption {
LocalStorage,
SessionStorage
Expand Down Expand Up @@ -88,12 +86,12 @@ export interface ɵNgxsTransformedStoragePluginOptions extends NgxsStoragePlugin
}

export const ɵUSER_OPTIONS = new InjectionToken<NgxsStoragePluginOptions>(
NG_DEV_MODE ? 'USER_OPTIONS' : ''
typeof ngDevMode !== 'undefined' && ngDevMode ? 'USER_OPTIONS' : ''
);

// Determines whether all states in the NGXS registry should be persisted or not.
export const ɵALL_STATES_PERSISTED = new InjectionToken<boolean>(
NG_DEV_MODE ? 'ALL_STATES_PERSISTED' : '',
typeof ngDevMode !== 'undefined' && ngDevMode ? 'ALL_STATES_PERSISTED' : '',
{
providedIn: 'root',
factory: () => inject(ɵUSER_OPTIONS).keys === '*'
Expand All @@ -102,11 +100,11 @@ export const ɵALL_STATES_PERSISTED = new InjectionToken<boolean>(

export const ɵNGXS_STORAGE_PLUGIN_OPTIONS =
new InjectionToken<ɵNgxsTransformedStoragePluginOptions>(
NG_DEV_MODE ? 'NGXS_STORAGE_PLUGIN_OPTIONS' : ''
typeof ngDevMode !== 'undefined' && ngDevMode ? 'NGXS_STORAGE_PLUGIN_OPTIONS' : ''
);

export const STORAGE_ENGINE = new InjectionToken<StorageEngine>(
NG_DEV_MODE ? 'STORAGE_ENGINE' : ''
typeof ngDevMode !== 'undefined' && ngDevMode ? 'STORAGE_ENGINE' : ''
);

export interface StorageEngine {
Expand Down
6 changes: 2 additions & 4 deletions packages/storage-plugin/src/engines.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,16 @@ import { StorageEngine } from '@ngxs/storage-plugin/internals';

declare const ngDevMode: boolean;

const NG_DEV_MODE = typeof ngDevMode !== 'undefined' && ngDevMode;

export const LOCAL_STORAGE_ENGINE = /* @__PURE__ */ new InjectionToken<StorageEngine | null>(
NG_DEV_MODE ? 'LOCAL_STORAGE_ENGINE' : '',
typeof ngDevMode !== 'undefined' && ngDevMode ? 'LOCAL_STORAGE_ENGINE' : '',
{
providedIn: 'root',
factory: () => (isPlatformBrowser(inject(PLATFORM_ID)) ? localStorage : null)
}
);

export const SESSION_STORAGE_ENGINE = /* @__PURE__ */ new InjectionToken<StorageEngine | null>(
NG_DEV_MODE ? 'SESSION_STORAGE_ENGINE' : '',
typeof ngDevMode !== 'undefined' && ngDevMode ? 'SESSION_STORAGE_ENGINE' : '',
{
providedIn: 'root',
factory: () => (isPlatformBrowser(inject(PLATFORM_ID)) ? sessionStorage : null)
Expand Down
7 changes: 3 additions & 4 deletions packages/storage-plugin/src/storage.plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ import { ɵNgxsStoragePluginKeysManager } from './keys-manager';

declare const ngDevMode: boolean;

const NG_DEV_MODE = typeof ngDevMode !== 'undefined' && ngDevMode;

@Injectable()
export class NgxsStoragePlugin implements NgxsPlugin {
private _keysManager = inject(ɵNgxsStoragePluginKeysManager);
Expand Down Expand Up @@ -71,7 +69,8 @@ export class NgxsStoragePlugin implements NgxsPlugin {
const newVal = this._options.deserialize!(storedValue);
storedValue = this._options.afterDeserialize!(newVal, key);
} catch {
NG_DEV_MODE &&
typeof ngDevMode !== 'undefined' &&
ngDevMode &&
console.error(
`Error ocurred while deserializing the ${storageKey} store value, falling back to empty object, the value obtained from the store: `,
storedValue
Expand Down Expand Up @@ -120,7 +119,7 @@ export class NgxsStoragePlugin implements NgxsPlugin {
const newStoredValue = this._options.beforeSerialize!(storedValue, key);
engine.setItem(storageKey, this._options.serialize!(newStoredValue));
} catch (error: any) {
if (NG_DEV_MODE) {
if (typeof ngDevMode !== 'undefined' && ngDevMode) {
if (
error &&
(error.name === 'QuotaExceededError' ||
Expand Down
4 changes: 1 addition & 3 deletions packages/storage-plugin/src/with-storage-feature.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ import { ɵNgxsStoragePluginKeysManager } from './keys-manager';

declare const ngDevMode: boolean;

const NG_DEV_MODE = typeof ngDevMode !== 'undefined' && ngDevMode;

export function withStorageFeature(storageKeys: StorageKey[]): EnvironmentProviders {
return makeEnvironmentProviders([
{
Expand All @@ -21,7 +19,7 @@ export function withStorageFeature(storageKeys: StorageKey[]): EnvironmentProvid
const allStatesPersisted = inject(ɵALL_STATES_PERSISTED);

if (allStatesPersisted) {
if (NG_DEV_MODE) {
if (typeof ngDevMode !== 'undefined' && ngDevMode) {
const message =
'The NGXS storage plugin is currently persisting all states because the `keys` ' +
'option was explicitly set to `*` at the root level. To selectively persist states, ' +
Expand Down
4 changes: 1 addition & 3 deletions packages/store/internals/src/initial-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import { ɵPlainObject } from './symbols';

declare const ngDevMode: boolean;

const NG_DEV_MODE = typeof ngDevMode !== 'undefined' && ngDevMode;

export class ɵInitialState {
private static _value: ɵPlainObject = {};

Expand All @@ -21,7 +19,7 @@ export class ɵInitialState {
}

export const ɵINITIAL_STATE_TOKEN = new InjectionToken<ɵPlainObject>(
NG_DEV_MODE ? 'INITIAL_STATE_TOKEN' : '',
typeof ngDevMode !== 'undefined' && ngDevMode ? 'INITIAL_STATE_TOKEN' : '',
{
providedIn: 'root',
factory: () => ɵInitialState.pop()
Expand Down
6 changes: 2 additions & 4 deletions packages/store/internals/src/internal-tokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,12 @@ import { InjectionToken } from '@angular/core';

declare const ngDevMode: boolean;

const NG_DEV_MODE = typeof ngDevMode !== 'undefined' && ngDevMode;

// These tokens are internal and can change at any point.

export const ɵNGXS_STATE_FACTORY = /* @__PURE__ */ new InjectionToken<any>(
NG_DEV_MODE ? 'ɵNGXS_STATE_FACTORY' : ''
typeof ngDevMode !== 'undefined' && ngDevMode ? 'ɵNGXS_STATE_FACTORY' : ''
);

export const ɵNGXS_STATE_CONTEXT_FACTORY = /* @__PURE__ */ new InjectionToken<any>(
NG_DEV_MODE ? 'ɵNGXS_STATE_CONTEXT_FACTORY' : ''
typeof ngDevMode !== 'undefined' && ngDevMode ? 'ɵNGXS_STATE_CONTEXT_FACTORY' : ''
);
6 changes: 3 additions & 3 deletions packages/store/plugins/src/symbols.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import { InjectionToken } from '@angular/core';

declare const ngDevMode: boolean;

const NG_DEV_MODE = typeof ngDevMode !== 'undefined' && ngDevMode;

// The injection token is used to resolve to custom NGXS plugins provided
// at the root level through either `{provide}` scheme or `withNgxsPlugin`.
export const NGXS_PLUGINS = new InjectionToken(NG_DEV_MODE ? 'NGXS_PLUGINS' : '');
export const NGXS_PLUGINS = new InjectionToken(
typeof ngDevMode !== 'undefined' && ngDevMode ? 'NGXS_PLUGINS' : ''
);

export type NgxsPluginFn = (state: any, mutation: any, next: NgxsNextPluginFn) => any;

Expand Down
4 changes: 1 addition & 3 deletions packages/store/src/dev-features/symbols.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ import { InjectionToken } from '@angular/core';

import { ActionType } from '../actions/symbols';

const NG_DEV_MODE = typeof ngDevMode !== 'undefined' && ngDevMode;

export interface NgxsDevelopmentOptions {
// This allows setting only `true` because there's no reason to set `false`.
// Developers may just skip importing the development module at all.
Expand All @@ -15,7 +13,7 @@ export interface NgxsDevelopmentOptions {
}

export const NGXS_DEVELOPMENT_OPTIONS = new InjectionToken<NgxsDevelopmentOptions>(
NG_DEV_MODE ? 'NGXS_DEVELOPMENT_OPTIONS' : '',
typeof ngDevMode !== 'undefined' && ngDevMode ? 'NGXS_DEVELOPMENT_OPTIONS' : '',
{
providedIn: 'root',
factory: () => ({ warnOnUnhandledActions: true })
Expand Down
6 changes: 2 additions & 4 deletions packages/store/src/execution/symbols.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,21 @@ import { InjectionToken, inject, INJECTOR, Type, NgZone } from '@angular/core';
import { NoopNgxsExecutionStrategy } from './noop-ngxs-execution-strategy';
import { DispatchOutsideZoneNgxsExecutionStrategy } from './dispatch-outside-zone-ngxs-execution-strategy';

const NG_DEV_MODE = typeof ngDevMode !== 'undefined' && ngDevMode;

/**
* Consumers have the option to utilize the execution strategy provided by
* `NgxsModule.forRoot({executionStrategy})` or `provideStore([], {executionStrategy})`.
*/
export const CUSTOM_NGXS_EXECUTION_STRATEGY = new InjectionToken<
Type<NgxsExecutionStrategy> | undefined
>(NG_DEV_MODE ? 'CUSTOM_NGXS_EXECUTION_STRATEGY' : '');
>(typeof ngDevMode !== 'undefined' && ngDevMode ? 'CUSTOM_NGXS_EXECUTION_STRATEGY' : '');

/**
* The injection token is used internally to resolve an instance of the execution
* strategy. It checks whether consumers have provided their own `executionStrategy`
* and also verifies if we are operating in a zone-aware environment.
*/
export const NGXS_EXECUTION_STRATEGY = new InjectionToken<NgxsExecutionStrategy>(
NG_DEV_MODE ? 'NGXS_EXECUTION_STRATEGY' : '',
typeof ngDevMode !== 'undefined' && ngDevMode ? 'NGXS_EXECUTION_STRATEGY' : '',
{
providedIn: 'root',
factory: () => {
Expand Down
8 changes: 3 additions & 5 deletions packages/store/src/internal/internals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ import { NgxsConfig } from '../symbols';

declare const ngDevMode: boolean;

const NG_DEV_MODE = typeof ngDevMode !== 'undefined' && ngDevMode;

export type StateKeyGraph = ɵPlainObjectOf<string[]>;
export type StatesByName = ɵPlainObjectOf<ɵStateClassInternal>;

Expand Down Expand Up @@ -108,7 +106,7 @@ export function propGetter(paths: string[], config: NgxsConfig) {
// We've been trying to deprecate the `Select` decorator because it's unstable with
// server-side rendering and micro-frontend applications.
export const ɵPROP_GETTER = new InjectionToken<(paths: string[]) => (x: any) => any>(
NG_DEV_MODE ? 'PROP_GETTER' : '',
typeof ngDevMode !== 'undefined' && ngDevMode ? 'PROP_GETTER' : '',
{
providedIn: 'root',
factory: () =>
Expand Down Expand Up @@ -140,7 +138,7 @@ export function buildGraph(stateClasses: ɵStateClassInternal[]): StateKeyGraph
const findName = (stateClass: ɵStateClassInternal) => {
const meta = stateClasses.find(g => g === stateClass);

if (NG_DEV_MODE && !meta) {
if (typeof ngDevMode !== 'undefined' && ngDevMode && !meta) {
throw new Error(
`Child state not found: ${stateClass}. \r\nYou may have forgotten to add states to module`
);
Expand Down Expand Up @@ -258,7 +256,7 @@ export function topologicalSort(graph: StateKeyGraph): string[] {
visited[name] = true;

graph[name].forEach((dep: string) => {
if (NG_DEV_MODE && ancestors.indexOf(dep) >= 0) {
if (typeof ngDevMode !== 'undefined' && ngDevMode && ancestors.indexOf(dep) >= 0) {
throw new Error(
`Circular dependency '${dep}' is required by '${name}': ${ancestors.join(' -> ')}`
);
Expand Down
4 changes: 1 addition & 3 deletions packages/store/src/internal/lifecycle-state-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ import { MappedStore, StatesAndDefaults } from './internals';
import { NgxsLifeCycle, NgxsSimpleChange, StateContext } from '../symbols';
import { getInvalidInitializationOrderMessage } from '../configs/messages.config';

const NG_DEV_MODE = typeof ngDevMode !== 'undefined' && ngDevMode;

@Injectable({ providedIn: 'root' })
export class LifecycleStateManager implements OnDestroy {
private _store = inject(Store);
Expand All @@ -32,7 +30,7 @@ export class LifecycleStateManager implements OnDestroy {
action: InitState | UpdateState,
results: StatesAndDefaults | undefined
): void {
if (NG_DEV_MODE) {
if (typeof ngDevMode !== 'undefined' && ngDevMode) {
if (action instanceof InitState) {
this._initStateHasBeenDispatched = true;
} else if (
Expand Down
10 changes: 4 additions & 6 deletions packages/store/src/internal/state-factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,6 @@ import { assignUnhandledCallback } from './unhandled-rxjs-error-callback';
import { StateContextFactory } from './state-context-factory';
import { ofActionDispatched } from '../operators/of-action';

const NG_DEV_MODE = typeof ngDevMode !== 'undefined' && ngDevMode;

function cloneDefaults(defaults: any): any {
let value = defaults === undefined ? {} : defaults;

Expand Down Expand Up @@ -158,7 +156,7 @@ export class StateFactory implements OnDestroy {
* Add a new state to the global defs.
*/
add(stateClasses: ɵStateClassInternal[]): MappedStore[] {
if (NG_DEV_MODE) {
if (typeof ngDevMode !== 'undefined' && ngDevMode) {
ensureStatesAreDecorated(stateClasses);
}

Expand All @@ -182,7 +180,7 @@ export class StateFactory implements OnDestroy {
// `State` decorator. This check is moved here because the `ɵprov` property
// will not exist on the class in JIT mode (because it's set asynchronously
// during JIT compilation through `Object.defineProperty`).
if (NG_DEV_MODE) {
if (typeof ngDevMode !== 'undefined' && ngDevMode) {
ensureStateClassIsInjectable(stateClass);
}

Expand Down Expand Up @@ -289,7 +287,7 @@ export class StateFactory implements OnDestroy {

// The `NgxsUnhandledActionsLogger` is a tree-shakable class which functions
// only during development.
if (NG_DEV_MODE && !actionHasBeenHandled) {
if (typeof ngDevMode !== 'undefined' && ngDevMode && !actionHasBeenHandled) {
const unhandledActionsLogger = this._injector.get(NgxsUnhandledActionsLogger, null);
// The `NgxsUnhandledActionsLogger` will not be resolved by the injector if the
// `NgxsDevelopmentModule` is not provided. It's enough to check whether the `injector.get`
Expand All @@ -312,7 +310,7 @@ export class StateFactory implements OnDestroy {

for (const stateClass of stateClasses) {
const stateName = ɵgetStoreMetadata(stateClass).name!;
if (NG_DEV_MODE) {
if (typeof ngDevMode !== 'undefined' && ngDevMode) {
ensureStateNameIsUnique(stateName, stateClass, statesMap);
}
const unmountedState = !statesMap[stateName];
Expand Down
4 changes: 1 addition & 3 deletions packages/store/src/selectors/selector-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ import { CreationMetadata, RuntimeSelectorInfo } from './selector-models';

declare const ngDevMode: boolean;

const NG_DEV_MODE = typeof ngDevMode !== 'undefined' && ngDevMode;

export function createRootSelectorFactory<T extends (...args: any[]) => any>(
selectorMetaData: ɵSelectorMetaDataModel,
selectors: any[] | undefined,
Expand Down Expand Up @@ -45,7 +43,7 @@ export function createRootSelectorFactory<T extends (...args: any[]) => any>(
// We're logging an error in this function because it may be used by `select`,
// `selectSignal`, and `selectSnapshot`. Therefore, there's no need to catch
// exceptions there to log errors.
if (NG_DEV_MODE) {
if (typeof ngDevMode !== 'undefined' && ngDevMode) {
const message =
'The selector below has thrown an error upon invocation. ' +
'Please check for any unsafe property access that may result in null ' +
Expand Down
6 changes: 2 additions & 4 deletions packages/store/src/standalone-features/initializers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ import { SelectFactory } from '../decorators/select/select-factory';
import { InternalStateOperations } from '../internal/state-operations';
import { LifecycleStateManager } from '../internal/lifecycle-state-manager';

const NG_DEV_MODE = typeof ngDevMode !== 'undefined' && ngDevMode;

/**
* This function is shared by both NgModule and standalone features.
* When using `NgxsModule.forRoot` and `provideStore`, we can depend on the
Expand Down Expand Up @@ -78,14 +76,14 @@ export function featureStatesInitializer(): void {
* InjectionToken that registers the global Store.
*/
export const NGXS_ROOT_STORE_INITIALIZER = new InjectionToken<void>(
NG_DEV_MODE ? 'NGXS_ROOT_STORE_INITIALIZER' : ''
typeof ngDevMode !== 'undefined' && ngDevMode ? 'NGXS_ROOT_STORE_INITIALIZER' : ''
);

/**
* InjectionToken that registers feature states.
*/
export const NGXS_FEATURE_STORE_INITIALIZER = new InjectionToken<void>(
NG_DEV_MODE ? 'NGXS_FEATURE_STORE_INITIALIZER' : ''
typeof ngDevMode !== 'undefined' && ngDevMode ? 'NGXS_FEATURE_STORE_INITIALIZER' : ''
);

export const NGXS_ROOT_ENVIRONMENT_INITIALIZER: Provider[] = [
Expand Down
4 changes: 1 addition & 3 deletions packages/store/src/standalone-features/preboot.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import { InjectionToken, makeEnvironmentProviders } from '@angular/core';

const NG_DEV_MODE = typeof ngDevMode !== 'undefined' && ngDevMode;

/**
* InjectionToken that registers preboot functions (called before the root initializer).
*/
export const NGXS_PREBOOT_FNS = new InjectionToken<VoidFunction[]>(
NG_DEV_MODE ? 'NGXS_PREBOOT_FNS' : ''
typeof ngDevMode !== 'undefined' && ngDevMode ? 'NGXS_PREBOOT_FNS' : ''
);

/**
Expand Down
Loading
Loading