Skip to content

Commit

Permalink
fix(store): allow plain functions in withNgxsPlugin
Browse files Browse the repository at this point in the history
In this commit, we slightly revise the `PluginManager` functionality to a single function that
pushes values onto the `plugins` list. No additional functionality is needed, and we mark it as
a root provider.

We also allow passing a plain function into `withNgxsPlugin`, as the plugin can be a simple
function (not a class).
  • Loading branch information
arturovt committed Nov 16, 2024
1 parent aa4dd85 commit eca4f37
Show file tree
Hide file tree
Showing 10 changed files with 50 additions and 64 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ $ npm install @ngxs/store@dev

### To become next patch version

- ...
- Fix(store): Allow plain functions in `withNgxsPlugin` [#2255](https://github.com/ngxs/store/pull/2255)

### 18.1.5 2024-11-12

Expand Down
14 changes: 3 additions & 11 deletions docs/concepts/store/meta-reducer.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,13 @@ export function logoutPlugin(state, action, next) {
}
```

Then add it to `providers`:
Then add it to `provideStore` features:

```ts
import { NGXS_PLUGINS } from '@ngxs/store/plugins';
import { provideStore, withNgxsPlugin } from '@ngxs/store';

export const appConfig: ApplicationConfig = {
providers: [
provideStore([]),

{
provide: NGXS_PLUGINS,
useValue: logoutPlugin,
multi: true
}
]
providers: [provideStore([], withNgxsPlugin(logoutPlugin))]
};
```

Expand Down
7 changes: 1 addition & 6 deletions packages/devtools-plugin/src/devtools.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
makeEnvironmentProviders
} from '@angular/core';
import { withNgxsPlugin } from '@ngxs/store';
import { NGXS_PLUGINS } from '@ngxs/store/plugins';

import { NgxsDevtoolsOptions, NGXS_DEVTOOLS_OPTIONS } from './symbols';
import { NgxsReduxDevtoolsPlugin } from './devtools.plugin';
Expand All @@ -28,11 +27,7 @@ export class NgxsReduxDevtoolsPluginModule {
return {
ngModule: NgxsReduxDevtoolsPluginModule,
providers: [
{
provide: NGXS_PLUGINS,
useClass: NgxsReduxDevtoolsPlugin,
multi: true
},
withNgxsPlugin(NgxsReduxDevtoolsPlugin),
{
provide: USER_OPTIONS,
useValue: options
Expand Down
18 changes: 3 additions & 15 deletions packages/form-plugin/src/form.module.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
import {
NgModule,
ModuleWithProviders,
EnvironmentProviders,
makeEnvironmentProviders
} from '@angular/core';
import { NgModule, ModuleWithProviders, EnvironmentProviders } from '@angular/core';
import { withNgxsPlugin } from '@ngxs/store';
import { NGXS_PLUGINS } from '@ngxs/store/plugins';

import { NgxsFormPlugin } from './form.plugin';
import { NgxsFormDirective } from './directive';
Expand All @@ -18,17 +12,11 @@ export class NgxsFormPluginModule {
static forRoot(): ModuleWithProviders<NgxsFormPluginModule> {
return {
ngModule: NgxsFormPluginModule,
providers: [
{
provide: NGXS_PLUGINS,
useClass: NgxsFormPlugin,
multi: true
}
]
providers: [withNgxsPlugin(NgxsFormPlugin)]
};
}
}

export function withNgxsFormPlugin(): EnvironmentProviders {
return makeEnvironmentProviders([withNgxsPlugin(NgxsFormPlugin)]);
return withNgxsPlugin(NgxsFormPlugin);
}
7 changes: 1 addition & 6 deletions packages/logger-plugin/src/logger.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
makeEnvironmentProviders
} from '@angular/core';
import { withNgxsPlugin } from '@ngxs/store';
import { NGXS_PLUGINS } from '@ngxs/store/plugins';

import { NgxsLoggerPlugin } from './logger.plugin';
import { NgxsLoggerPluginOptions, NGXS_LOGGER_PLUGIN_OPTIONS } from './symbols';
Expand Down Expand Up @@ -35,11 +34,7 @@ export class NgxsLoggerPluginModule {
return {
ngModule: NgxsLoggerPluginModule,
providers: [
{
provide: NGXS_PLUGINS,
useClass: NgxsLoggerPlugin,
multi: true
},
withNgxsPlugin(NgxsLoggerPlugin),
{
provide: USER_OPTIONS,
useValue: options
Expand Down
7 changes: 1 addition & 6 deletions packages/storage-plugin/src/storage.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
makeEnvironmentProviders
} from '@angular/core';
import { withNgxsPlugin } from '@ngxs/store';
import { NGXS_PLUGINS } from '@ngxs/store/plugins';
import {
ɵUSER_OPTIONS,
STORAGE_ENGINE,
Expand All @@ -25,11 +24,7 @@ export class NgxsStoragePluginModule {
return {
ngModule: NgxsStoragePluginModule,
providers: [
{
provide: NGXS_PLUGINS,
useClass: NgxsStoragePlugin,
multi: true
},
withNgxsPlugin(NgxsStoragePlugin),
{
provide: ɵUSER_OPTIONS,
useValue: options
Expand Down
8 changes: 7 additions & 1 deletion packages/store/plugins/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
export { InitState, UpdateState } from './actions';
export { NGXS_PLUGINS, NgxsPlugin, NgxsPluginFn, NgxsNextPluginFn } from './symbols';
export {
NGXS_PLUGINS,
NgxsPlugin,
NgxsPluginFn,
NgxsNextPluginFn,
ɵisPluginClass
} from './symbols';
export { getActionTypeFromInstance, actionMatcher, setValue, getValue } from './utils';
27 changes: 21 additions & 6 deletions packages/store/plugins/src/symbols.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
import { InjectionToken } from '@angular/core';
import { InjectionToken, Type } 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 type NgxsNextPluginFn = (state: any, mutation: any) => any;

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

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

/**
* Plugin interface
*/
Expand All @@ -21,3 +17,22 @@ export interface NgxsPlugin {
*/
handle(state: any, action: any, next: NgxsNextPluginFn): any;
}

/**
* A multi-provider token used to resolve to custom NGXS plugins provided
* at the root and feature levels through the `{provide}` scheme.
*
* @deprecated from v18.0.0, use `withNgxsPlugin` instead.
*/
export const NGXS_PLUGINS = /* @__PURE__ */ new InjectionToken<NgxsPlugin[]>(
NG_DEV_MODE ? 'NGXS_PLUGINS' : ''
);

export function ɵisPluginClass(
plugin: Type<NgxsPlugin> | NgxsPluginFn
): plugin is Type<NgxsPlugin> {
// Determines whether the provided value is a class rather than a function.
// If it’s a class, its handle method should be defined on its prototype,
// as plugins can be either classes or functions.
return !!plugin.prototype.handle;
}
14 changes: 10 additions & 4 deletions packages/store/src/standalone-features/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
inject,
makeEnvironmentProviders
} from '@angular/core';
import { NGXS_PLUGINS, NgxsPlugin } from '@ngxs/store/plugins';
import { NGXS_PLUGINS, NgxsPlugin, NgxsPluginFn, ɵisPluginClass } from '@ngxs/store/plugins';

import { PluginManager } from '../plugin-manager';

Expand All @@ -23,12 +23,18 @@ import { PluginManager } from '../plugin-manager';
* });
* ```
*/
export function withNgxsPlugin(plugin: Type<NgxsPlugin>): EnvironmentProviders {
export function withNgxsPlugin(plugin: Type<NgxsPlugin> | NgxsPluginFn): EnvironmentProviders {
return makeEnvironmentProviders([
{ provide: NGXS_PLUGINS, useClass: plugin, multi: true },
ɵisPluginClass(plugin)
? { provide: NGXS_PLUGINS, useClass: plugin, multi: true }
: { provide: NGXS_PLUGINS, useValue: plugin, multi: true },
// We should inject the `PluginManager` to retrieve `NGXS_PLUGINS` and
// register those plugins. The plugin can be added from inside the child
// route, so the plugin manager should be re-injected.
{ provide: ENVIRONMENT_INITIALIZER, useValue: () => inject(PluginManager), multi: true }
{
provide: ENVIRONMENT_INITIALIZER,
useValue: () => inject(PluginManager),
multi: true
}
]);
}
10 changes: 2 additions & 8 deletions packages/store/tests/plugins.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { TestBed } from '@angular/core/testing';
import { NgxsModule, NGXS_PLUGINS, Store } from '@ngxs/store';
import { NgxsModule, Store, withNgxsPlugin } from '@ngxs/store';
import { tap } from 'rxjs/operators';
import { Observable } from 'rxjs';

Expand Down Expand Up @@ -31,13 +31,7 @@ describe('Plugins', () => {

TestBed.configureTestingModule({
imports: [NgxsModule.forRoot()],
providers: [
{
provide: NGXS_PLUGINS,
useValue: logPlugin,
multi: true
}
]
providers: [withNgxsPlugin(logPlugin)]
});

const store: Store = TestBed.inject(Store);
Expand Down

0 comments on commit eca4f37

Please sign in to comment.