Skip to content

Commit

Permalink
feat: withDevTools disabled in prod, and tree-shaking docs - add inje…
Browse files Browse the repository at this point in the history
…ction token config and improve docs after review
  • Loading branch information
marcindz88 committed Sep 14, 2024
1 parent 27d146e commit a114fda
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 23 deletions.
18 changes: 16 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,27 @@ patchState(this.store, {loading: false});
updateState(this.store 'update loading', {loading: false});
```

`withDevtools()` is by default disabled in production mode, however if you want to tree-shake it from the application bundle you need to abstract it in your environment file.
### Configuration

You may configure this feature by setting up a provider in your application:

```typescript
providers: [
provideStoreDevtoolsConfig({
logOnly: !isDevMode(), // Restrict extension to log-only mode, default is false
})
]
```

When running in production you may opt to tree-shake it from the application bundle you need to abstract it in your environment file.

<details>

<summary>Devtools tree-shaking details</summary>

environment.ts:
If the environment files don't exist in your project you can use the `ng generate environments` command to create them.

environment.ts:
```typescript
import { withDevtools } from '@angular-architects/ngrx-toolkit';

Expand Down
7 changes: 1 addition & 6 deletions libs/ngrx-toolkit/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
export {
withDevtools,
patchState,
updateState,
Action,
} from './lib/with-devtools';
export * from './lib/with-devtools';
export * from './lib/with-redux';

export * from './lib/with-call-state';
Expand Down
7 changes: 7 additions & 0 deletions libs/ngrx-toolkit/src/lib/with-devtools/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export * from './with-devtools.config';
export {
withDevtools,
patchState,
updateState,
Action,
} from './with-devtools';
35 changes: 35 additions & 0 deletions libs/ngrx-toolkit/src/lib/with-devtools/with-devtools.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { InjectionToken } from '@angular/core';

export type DevtoolsConfig = {
logOnly: boolean;
};

export const DEFAULT_DEVTOOLS_CONFIG: DevtoolsConfig = {
logOnly: false,
};

export const DEVTOOLS_CONFIG = new InjectionToken<DevtoolsConfig>('DEVTOOLS_CONFIG');


/**
* Provide a custom configuration for the devtools.
* @param config The custom configuration.
*
* @example
* ```ts
* provideStoreDevtoolsConfig({
* logOnly: !isDevMode(), // Enable the log-only mode when not in production. (Default: false)
* });
* ```
*
* @returns The provider of the custom configuration.
*/
export const provideStoreDevtoolsConfig = (config: Partial<DevtoolsConfig>) => {
return {
provide: DEVTOOLS_CONFIG,
useValue: {
...DEFAULT_DEVTOOLS_CONFIG,
...config,
} satisfies DevtoolsConfig,
};
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
let isDevMode = true;
jest.mock('@angular/core', () => ({ ...jest.requireActual('@angular/core'), isDevMode: () => isDevMode }))

import { signalStore } from '@ngrx/signals';
import { withEntities } from '@ngrx/signals/entities';
import { Action, withDevtools } from './with-devtools';
import { TestBed } from '@angular/core/testing';
import { PLATFORM_ID } from '@angular/core';
import SpyInstance = jest.SpyInstance;
import Mock = jest.Mock;
import { reset } from './with-devtools';
import { Action, withDevtools, reset } from './with-devtools';
import { DevtoolsConfig, provideStoreDevtoolsConfig } from './with-devtools.config';

type Flight = {
id: number;
Expand All @@ -34,7 +31,7 @@ const createFlight = (flight: Partial<Flight> = {}) => ({
interface SetupOptions {
extensionsAvailable: boolean;
inSsr: boolean;
isDevMode: boolean
config: DevtoolsConfig | null;
}

interface TestData {
Expand All @@ -52,12 +49,10 @@ function run(
const defaultOptions: SetupOptions = {
inSsr: false,
extensionsAvailable: true,
isDevMode: true,
config: null,
};
const realOptions = { ...defaultOptions, ...options };

isDevMode = realOptions.isDevMode;

const sendSpy = jest.fn<void, [Action, Record<string, unknown>]>();
const connection = {
send: sendSpy,
Expand All @@ -71,6 +66,7 @@ function run(
provide: PLATFORM_ID,
useValue: realOptions.inSsr ? 'server' : 'browser',
},
...(realOptions.config ? [provideStoreDevtoolsConfig(realOptions.config)] : []),
],
});

Expand Down Expand Up @@ -124,12 +120,22 @@ describe('Devtools', () => {
);

it(
'should not connect if it runs in production',
'should not connect if it runs in logOnly mode',
run(
({ connectSpy }) => {
expect(connectSpy).toHaveBeenCalledTimes(0);
},
{ isDevMode: false }
{ config: { logOnly: true } }
)
);

it(
'should connect if it runs with config and logOnly=false',
run(
({ connectSpy }) => {
expect(connectSpy).toHaveBeenCalledTimes(1);
},
{ config: { logOnly: false } }
)
);

Expand Down Expand Up @@ -170,5 +176,4 @@ describe('Devtools', () => {
it.todo('should patchState with action name');
it.todo('should use patchState with default action name');
it.todo('should group multiple patchStates (glitch-free) in one action');
it.todo('should not run if in prod mode');
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ import {
SignalStoreFeature,
WritableStateSource,
} from '@ngrx/signals';
import { effect, inject, isDevMode, PLATFORM_ID, signal, Signal } from '@angular/core';
import { effect, inject, InjectionToken, isDevMode, PLATFORM_ID, signal, Signal } from '@angular/core';
import { isPlatformServer } from '@angular/common';
import { Prettify } from './shared/prettify';
import { Prettify } from '../shared/prettify';
import { DEFAULT_DEVTOOLS_CONFIG, DEVTOOLS_CONFIG } from './with-devtools.config';

declare global {
interface Window {
Expand Down Expand Up @@ -87,7 +88,8 @@ export function withDevtools<Input extends EmptyFeatureResult>(
): SignalStoreFeature<Input, EmptyFeatureResult> {
return (store) => {
const isServer = isPlatformServer(inject(PLATFORM_ID));
if (isServer || !isDevMode()) {
const { logOnly } = inject(DEVTOOLS_CONFIG, { optional: true }) || DEFAULT_DEVTOOLS_CONFIG;
if (isServer || logOnly) {
return store;
}

Expand Down

0 comments on commit a114fda

Please sign in to comment.