UNPKG

@ngxs/devtools-plugin

Version:

redux devtools plugin for @ngxs/store

174 lines (167 loc) 7.8 kB
import * as i0 from '@angular/core'; import { InjectionToken, inject, Injector, NgZone, ɵglobal as _global, Injectable, NgModule, makeEnvironmentProviders } from '@angular/core'; import { Store, withNgxsPlugin } from '@ngxs/store'; import { getActionTypeFromInstance, InitState } from '@ngxs/store/plugins'; import { catchError, tap } from 'rxjs/operators'; const NGXS_DEVTOOLS_OPTIONS = new InjectionToken('NGXS_DEVTOOLS_OPTIONS'); /** * Adds support for the Redux Devtools extension: * http://extension.remotedev.io/ */ class NgxsReduxDevtoolsPlugin { constructor() { this._injector = inject(Injector); this._ngZone = inject(NgZone); this._options = inject(NGXS_DEVTOOLS_OPTIONS); this.devtoolsExtension = null; this.globalDevtools = _global['__REDUX_DEVTOOLS_EXTENSION__'] || _global['devToolsExtension']; this.unsubscribe = null; this.connect(); } ngOnDestroy() { 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 === "DISPATCH" /* ReduxDevtoolsActionType.Dispatch */) { if (action.payload.type === "JUMP_TO_ACTION" /* ReduxDevtoolsPayloadType.JumpToAction */ || action.payload.type === "JUMP_TO_STATE" /* 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 && prevState.router.trigger) { prevState.router.trigger = 'devtools'; } this.store.reset(prevState); } else if (action.payload.type === "TOGGLE_ACTION" /* ReduxDevtoolsPayloadType.ToggleAction */) { console.warn('Skip is not supported at this time.'); } else if (action.payload.type === "IMPORT_STATE" /* 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 === "ACTION" /* 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 === "DISPATCH" /* ReduxDevtoolsActionType.Dispatch */ || action.type === "ACTION" /* ReduxDevtoolsActionType.Action */) { this.dispatched(action); } }); } /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: NgxsReduxDevtoolsPlugin, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); } /** @nocollapse */ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: NgxsReduxDevtoolsPlugin }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.0", 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 { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: NgxsReduxDevtoolsPluginModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); } /** @nocollapse */ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.0.0", ngImport: i0, type: NgxsReduxDevtoolsPluginModule }); } /** @nocollapse */ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: NgxsReduxDevtoolsPluginModule }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.0", 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