UNPKG

@ngxs/devtools-plugin

Version:

redux devtools plugin for @ngxs/store

186 lines (179 loc) 8.2 kB
import * as i0 from '@angular/core'; import { InjectionToken, inject, Injector, NgZone, ɵglobal as _global, DestroyRef, Injectable, NgModule, makeEnvironmentProviders } from '@angular/core'; import { Store, withNgxsPlugin } from '@ngxs/store'; import { getActionTypeFromInstance, InitState } from '@ngxs/store/plugins'; import { catchError, tap } from 'rxjs'; const NGXS_DEVTOOLS_OPTIONS = new InjectionToken('NGXS_DEVTOOLS_OPTIONS'); var ReduxDevtoolsActionType; (function (ReduxDevtoolsActionType) { ReduxDevtoolsActionType["Dispatch"] = "DISPATCH"; ReduxDevtoolsActionType["Action"] = "ACTION"; })(ReduxDevtoolsActionType || (ReduxDevtoolsActionType = {})); var ReduxDevtoolsPayloadType; (function (ReduxDevtoolsPayloadType) { ReduxDevtoolsPayloadType["JumpToAction"] = "JUMP_TO_ACTION"; ReduxDevtoolsPayloadType["JumpToState"] = "JUMP_TO_STATE"; ReduxDevtoolsPayloadType["ToggleAction"] = "TOGGLE_ACTION"; ReduxDevtoolsPayloadType["ImportState"] = "IMPORT_STATE"; })(ReduxDevtoolsPayloadType || (ReduxDevtoolsPayloadType = {})); /** * Adds support for the Redux Devtools extension: * http://extension.remotedev.io/ */ class NgxsReduxDevtoolsPlugin { _injector = inject(Injector); _ngZone = inject(NgZone); _options = inject(NGXS_DEVTOOLS_OPTIONS); devtoolsExtension = null; globalDevtools = _global['__REDUX_DEVTOOLS_EXTENSION__'] || _global['devToolsExtension']; unsubscribe = null; constructor() { this.connect(); inject(DestroyRef).onDestroy(() => { this.unsubscribe?.(); this.globalDevtools?.disconnect(); }); } /** * Lazy get the store for circular dependency issues */ get store() { return this._injector.get(Store); } /** * Middleware handle function */ handle(state, action, next) { if (!this.devtoolsExtension || this._options.disabled) { return next(state, action); } return next(state, action).pipe(catchError(error => { const newState = this.store.snapshot(); this.sendToDevTools(state, action, newState); throw error; }), tap(newState => { this.sendToDevTools(state, action, newState); })); } sendToDevTools(state, action, newState) { const type = getActionTypeFromInstance(action); // if init action, send initial state to dev tools const isInitAction = type === InitState.type; if (isInitAction) { this.devtoolsExtension.init(state); } else { this.devtoolsExtension.send({ ...action, action: null, type }, newState); } } /** * Handle the action from the dev tools subscription */ dispatched(action) { if (action.type === ReduxDevtoolsActionType.Dispatch) { if (action.payload.type === ReduxDevtoolsPayloadType.JumpToAction || action.payload.type === ReduxDevtoolsPayloadType.JumpToState) { const prevState = JSON.parse(action.state); // This makes the DevTools and Router plugins compatible with each other. // We check for the existence of the `router` state and ensure it has the // `trigger` property, confirming that it is our router state (coming from `@ngxs/router-plugin`). // This enables a time-traveling feature, as it not only restores the state but // also allows the `RouterState` to navigate back when the action is jumped. if (prevState.router?.trigger) { prevState.router.trigger = 'devtools'; } this.store.reset(prevState); } else if (action.payload.type === ReduxDevtoolsPayloadType.ToggleAction) { console.warn('Skip is not supported at this time.'); } else if (action.payload.type === ReduxDevtoolsPayloadType.ImportState) { const { actionsById, computedStates, currentStateIndex } = action.payload.nextLiftedState; this.devtoolsExtension.init(computedStates[0].state); Object.keys(actionsById) .filter(actionId => actionId !== '0') .forEach(actionId => this.devtoolsExtension.send(actionsById[actionId], computedStates[actionId].state)); this.store.reset(computedStates[currentStateIndex].state); } } else if (action.type === ReduxDevtoolsActionType.Action) { const actionPayload = JSON.parse(action.payload); this.store.dispatch(actionPayload); } } connect() { if (!this.globalDevtools || this._options.disabled) { return; } // The `connect` method adds a `message` event listener to communicate // with an extension through `window.postMessage` and handle message events. // Since we only handle two specific events, we aim to avoid unnecessary change // detections triggered by events that the extension sends, but we don't need to handle. this.devtoolsExtension = this._ngZone.runOutsideAngular(() => this.globalDevtools.connect(this._options)); this.unsubscribe = this.devtoolsExtension.subscribe(action => { if (action.type === ReduxDevtoolsActionType.Dispatch || action.type === ReduxDevtoolsActionType.Action) { this.dispatched(action); } }); } /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: NgxsReduxDevtoolsPlugin, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); /** @nocollapse */ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: NgxsReduxDevtoolsPlugin }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: NgxsReduxDevtoolsPlugin, decorators: [{ type: Injectable }], ctorParameters: () => [] }); function devtoolsOptionsFactory(options) { return { name: 'NGXS', ...options }; } const USER_OPTIONS = new InjectionToken('USER_OPTIONS'); class NgxsReduxDevtoolsPluginModule { static forRoot(options) { return { ngModule: NgxsReduxDevtoolsPluginModule, providers: [ withNgxsPlugin(NgxsReduxDevtoolsPlugin), { provide: USER_OPTIONS, useValue: options }, { provide: NGXS_DEVTOOLS_OPTIONS, useFactory: devtoolsOptionsFactory, deps: [USER_OPTIONS] } ] }; } /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: NgxsReduxDevtoolsPluginModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); /** @nocollapse */ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.2", ngImport: i0, type: NgxsReduxDevtoolsPluginModule }); /** @nocollapse */ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: NgxsReduxDevtoolsPluginModule }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: NgxsReduxDevtoolsPluginModule, decorators: [{ type: NgModule }] }); function withNgxsReduxDevtoolsPlugin(options) { return makeEnvironmentProviders([ withNgxsPlugin(NgxsReduxDevtoolsPlugin), { provide: USER_OPTIONS, useValue: options }, { provide: NGXS_DEVTOOLS_OPTIONS, useFactory: devtoolsOptionsFactory, deps: [USER_OPTIONS] } ]); } /** * The public api for consumers of @ngxs/devtools-plugin */ /** * Generated bundle index. Do not edit. */ export { NGXS_DEVTOOLS_OPTIONS, NgxsReduxDevtoolsPlugin, NgxsReduxDevtoolsPluginModule, withNgxsReduxDevtoolsPlugin }; //# sourceMappingURL=ngxs-devtools-plugin.mjs.map