@ngneat/elf-devtools
Version:
Redux devtools for elf store
94 lines (91 loc) • 2.69 kB
JavaScript
import { getRegistry, registry$, capitalize, getStoresSnapshot, getStore } from '@ngneat/elf';
import { Subject } from 'rxjs';
import { skip } from 'rxjs/operators';
const externalEvents$ = new Subject();
function send(action) {
externalEvents$.next(action);
}
function devTools(options = {}) {
if (!window.__REDUX_DEVTOOLS_EXTENSION__) return;
let lock = false;
const instance = window.__REDUX_DEVTOOLS_EXTENSION__.connect(options);
const subscriptions = new Map();
const send = action => {
instance.send(action, getStoresSnapshot());
};
subscriptions.set('externalSend', externalEvents$.subscribe(send));
const addStore = store => {
const name = store.name;
const displayName = capitalize(name);
send({
type: `[${displayName}] - @Init`
});
const update = store.pipe(skip(1)).subscribe(() => {
if (lock) {
lock = false;
return;
}
options.preAction?.();
send({
type: `[${displayName}] - Update`
});
});
subscriptions.set(name, update);
};
// There should be support for stores that were created before we initialized the `devTools`
getRegistry().forEach(addStore);
if (options.actionsDispatcher) {
subscriptions.set('actionsDispatcher', options.actionsDispatcher.subscribe(action => {
send(action);
}));
}
const subscription = registry$.subscribe(({
store,
type
}) => {
const name = store.name;
const displayName = capitalize(name);
if (options.logTrace) {
const msg = `[${displayName}] - ${type}`;
console.groupCollapsed(msg);
console.trace();
console.groupEnd();
}
if (type === 'add') {
addStore(store);
}
if (type === 'remove') {
subscriptions.get(name)?.unsubscribe();
subscriptions.delete(name);
send({
type: `Remove ${displayName}`
});
}
});
const devtoolsDispose = instance.subscribe(message => {
if (message.type === 'DISPATCH') {
const payloadType = message.payload.type;
if (payloadType === 'COMMIT') {
instance.init(getStoresSnapshot());
return;
}
if (payloadType === 'JUMP_TO_STATE' || payloadType === 'JUMP_TO_ACTION') {
const state = JSON.parse(message.state);
for (const [name, value] of Object.entries(state)) {
lock = true;
getStore(name)?.update(() => value);
}
options.postTimelineUpdate?.();
}
}
});
return {
unsubscribe() {
subscription.unsubscribe();
instance.unsubscribe();
subscriptions.forEach(sub => sub.unsubscribe());
devtoolsDispose();
}
};
}
export { devTools, send };