Skip to content

Commit

Permalink
[WIP] redux extension integration
Browse files Browse the repository at this point in the history
  • Loading branch information
lifeart committed May 15, 2024
1 parent 9891ffd commit c9f501c
Show file tree
Hide file tree
Showing 2 changed files with 226 additions and 0 deletions.
26 changes: 26 additions & 0 deletions src/utils/reactive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/
import { scheduleRevalidate } from '@/utils/runtime';
import { isFn, isTag, isTagLike, debugContext } from '@/utils/shared';
import { supportChromeExtension } from './redux-devtools';

export const asyncOpcodes = new WeakSet<tagOp>();
// List of DOM operations for each tag
Expand Down Expand Up @@ -340,3 +341,28 @@ export function getTracker() {
export function setTracker(tracker: Set<Cell> | null) {
currentTracker = tracker;
}

supportChromeExtension({
get() {
const cells = {};
DEBUG_CELLS.forEach((cell, index) => {
cells[`${cell._debugName}:${index}`] = cell._value;
});
return cells;
},
skipDispatch: 0,
set() {
console.log('set', ...arguments);
},
on(timeLine: string, fn: () => any) {
console.log('on', timeLine, fn);
setTimeout(() => {
// debugger;
fn.call(this, 'updates', {})

}, 2000);
},
trigger() {
console.log('trigger', ...arguments);
}
});
200 changes: 200 additions & 0 deletions src/utils/redux-devtools.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
// inspired by https://www.npmjs.com/package/freezer-redux-devtools?activeTab=code
var ActionTypes = {
INIT: '@@INIT',
PERFORM_ACTION: 'PERFORM_ACTION',
TOGGLE_ACTION: 'TOGGLE_ACTION'
};

type Listener = () => void;

/**
* Redux middleware to make freezer and devtools
* talk to each other.
* @param {Freezer} State Freezer's app state.
*/
export function FreezerMiddleware( State ){
return function( next ){
return function StoreEnhancer( someReducer, someState ){
var commitedState = State.get(),
lastAction = 0,
/**
* Freezer reducer will trigger events on any
* devtool action to synchronize freezer's and
* devtool's states.
*
* @param {Object} state Current devtool state.
* @param {Object} action Action being dispatched.
* @return {Object} Freezer state after the action.
*/
reducer = function( state, action ){
if( action.type == ActionTypes.INIT ){
State.set( state || commitedState );
}
else if( lastAction != ActionTypes.PERFORM_ACTION ) {
// Flag that we are dispatching to not
// to dispatch the same action twice
State.skipDispatch = 1;
State.trigger.apply( State, [ action.type ].concat( action.arguments || [] ) );
}
// The only valid state is freezer's one.
return State.get();
},
store = next( reducer ),
liftedStore = store.liftedStore,
dtStore = store.devToolsStore || store.liftedStore,

toolsDispatcher = dtStore.dispatch
;

// Override devTools store's dispatch, to set commitedState
// on Commit action.
dtStore.dispatch = function( action ){
lastAction = action.type;

// If we are using redux-devtools we need to reset the state
// to the last valid one manually
if( liftedStore && lastAction == ActionTypes.TOGGLE_ACTION ){
var states = dtStore.getState().computedStates,
nextValue = states[ action.id - 1].state
;

State.set( nextValue );
}

toolsDispatcher.apply( dtStore, arguments );

return action;
};

// Dispatch any freezer "fluxy" event to let the devTools
// know about the update.
State.on('afterAll', function( reactionName ){
if( reactionName == 'update')
return;

// We don't dispatch if the flag is true
if( this.skipDispatch )
this.skipDispatch = 0;
else {
var args = [].slice.call( arguments, 1 );
store.dispatch({ type: reactionName, args: args });
}
});

return store;
};
};
}

/**
* Binds freezer store to the chrome's redux-devtools extension.
* @param {Freezer} State Freezer's app state
*/
export function supportChromeExtension( State ){
var devtools = window.__REDUX_DEVTOOLS_EXTENSION__
? window.__REDUX_DEVTOOLS_EXTENSION__()
: (f) => f;

compose(
FreezerMiddleware( State ),
devtools
)(createStore)( function( state ){
return state;
});
}


/**
* Creates a valid redux store. Copied directly from redux.
* https://github.com/rackt/redux
*/
function createStore(reducer: any, initialState: any) {


if (typeof reducer !== 'function') {
throw new Error('Expected the reducer to be a function.');
}

var currentReducer = reducer;
var currentState = initialState;
var listeners: Listener[] = [];
var isDispatching = false;
var ActionTypes = {
INIT: '@@redux/INIT'
};

function getState() {
return currentState;
}

function subscribe(listener: Listener) {
listeners.push(listener);
var isSubscribed = true;

return function unsubscribe() {
if (!isSubscribed) {
return;
}

isSubscribed = false;
var index = listeners.indexOf(listener);
listeners.splice(index, 1);
};
}

function dispatch(action: { type: string | undefined }) {
if (typeof action.type === 'undefined') {
throw new Error('Actions may not have an undefined "type" property. ' + 'Have you misspelled a constant?');
}

if (isDispatching) {
throw new Error('Reducers may not dispatch actions.');
}

try {
isDispatching = true;
currentState = currentReducer(currentState, action);
} finally {
isDispatching = false;
}

listeners.slice().forEach(function (listener) {
return listener();
});
return action;
}

function replaceReducer(nextReducer: any) {
currentReducer = nextReducer;
dispatch({ type: ActionTypes.INIT });
}

// When a store is created, an "INIT" action is dispatched so that every
// reducer returns their initial state. This effectively populates
// the initial state tree.
dispatch({ type: ActionTypes.INIT });

return {
dispatch: dispatch,
subscribe: subscribe,
getState: getState,
replaceReducer: replaceReducer
};
}

/**
* Composes single-argument functions from right to left.
* Copied directly from redux.
* https://github.com/rackt/redux
*/
function compose() {
for (var _len = arguments.length, funcs = Array(_len), _key = 0; _key < _len; _key++) {
funcs[_key] = arguments[_key];
}

return function (arg: any) {
return funcs.reduceRight(function (composed, f) {
return f(composed);
}, arg);
};
}

0 comments on commit c9f501c

Please sign in to comment.