Skip to content

Commit 0430fda

Browse files
fix(overmind): change to new hot reloading strategy
1 parent c419b60 commit 0430fda

File tree

7 files changed

+101
-30
lines changed

7 files changed

+101
-30
lines changed

packages/node_modules/overmind/src/index.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ import {
6161
getFunctionName,
6262
isPromise,
6363
processState,
64+
getChangeMutations
6465
} from './utils'
6566

6667
export * from './types'
@@ -190,6 +191,7 @@ export class Overmind<ThisConfig extends IConfiguration>
190191
private nextExecutionId: number = 0
191192
private mode: DefaultMode | TestMode | SSRMode
192193
private reydrateMutationsForHotReloading: IMutation[] = []
194+
private originalConfiguration
193195
initialized: Promise<any>
194196
eventHub: EventEmitter<Events>
195197
devtools: Devtools
@@ -238,6 +240,7 @@ export class Overmind<ThisConfig extends IConfiguration>
238240
eventHub,
239241
mode.mode === MODE_SSR ? false : process.env.NODE_ENV === 'development'
240242
)
243+
this.originalConfiguration = configuration
241244
this.state = proxyStateTree.state
242245
this.effects = configuration.effects || {}
243246
this.proxyStateTree = proxyStateTree
@@ -945,12 +948,16 @@ export class Overmind<ThisConfig extends IConfiguration>
945948
return this.proxyStateTree.onFlush(cb)
946949
}
947950
reconfigure(configuration: IConfiguration) {
948-
this.proxyStateTree.reset(configuration.state || {})
949-
this.state = this.proxyStateTree.state as any
951+
const changeMutations = getChangeMutations(this.originalConfiguration.state, configuration.state || {})
950952
this.actions = this.getActions(configuration.actions)
951953
this.effects = configuration.effects || {}
952954

953-
// We do one at a time as they might error due to changed state structure
955+
// We change the state to match the new structure
956+
rehydrate(this.state as any, changeMutations)
957+
958+
// We run any mutations ran during the session, it might fail though
959+
// as the state structure might have changed, but no worries we just
960+
// ignore that
954961
this.reydrateMutationsForHotReloading.forEach((mutation) => {
955962
try {
956963
rehydrate(this.state as any, [mutation])

packages/node_modules/overmind/src/utils.test.ts

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { deepCopy } from './utils'
1+
import { deepCopy, getChangeMutations } from './utils'
22

33
describe('deepCopy', () => {
44
test('should be able to preserve getters', () => {
@@ -11,4 +11,58 @@ describe('deepCopy', () => {
1111
copy.value = 15
1212
expect(copy.valuePlusTwo).toBe(17)
1313
})
14+
})
15+
16+
describe('getChangeMutations', () => {
17+
test('should be able to create a set mutation when value has changed', () => {
18+
const stateA = {
19+
foo: 'bar'
20+
}
21+
const stateB = {
22+
foo: 'bar2',
23+
}
24+
const mutations = getChangeMutations(stateA, stateB)
25+
expect(mutations[0].path).toBe('foo')
26+
expect(mutations[0].args[0]).toBe('bar2')
27+
})
28+
test('should be able to create a set mutation when nested value has changed', () => {
29+
const stateA = {
30+
foo: {
31+
bar: {
32+
baz: 'mip'
33+
}
34+
}
35+
}
36+
const stateB = {
37+
foo: {
38+
bar: {
39+
baz: 'mip2'
40+
}
41+
}
42+
}
43+
const mutations = getChangeMutations(stateA, stateB)
44+
expect(mutations.length).toBe(1)
45+
expect(mutations[0].path).toBe('foo.bar.baz')
46+
expect(mutations[0].args[0]).toBe('mip2')
47+
})
48+
test('should be able to create an unset mutation when key is not there anymore', () => {
49+
const stateA = {
50+
foo: {
51+
bar: {
52+
baz: 'mip'
53+
}
54+
}
55+
}
56+
const stateB = {
57+
foo: {
58+
bar: {
59+
60+
}
61+
}
62+
}
63+
const mutations = getChangeMutations(stateA, stateB)
64+
expect(mutations.length).toBe(1)
65+
expect(mutations[0].path).toBe('foo.bar.baz')
66+
expect(mutations[0].method).toBe('unset')
67+
})
1468
})

packages/node_modules/overmind/src/utils.ts

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
import isPlainObject from 'is-plain-obj'
22
import { IMutation, IS_PROXY, VALUE } from 'proxy-state-tree'
33

4-
import { Derived } from './derived'
5-
import { IState } from './types'
6-
74
export const IS_TEST = process.env.NODE_ENV === 'test'
85
export const IS_OPERATOR = Symbol('operator')
96
export const ORIGINAL_ACTIONS = Symbol('origina_actions')
@@ -90,6 +87,42 @@ export function deepCopy(obj) {
9087
return obj
9188
}
9289

90+
const getChangeMutationsDelimiter = '.'
91+
const getChangeMutationsRevert = () => {}
92+
export function getChangeMutations(stateA: object, stateB: object, path: string[] = [], mutations: IMutation[] = []): IMutation[] {
93+
const stateAKeys = Object.keys(stateA)
94+
const stateBKeys = Object.keys(stateB)
95+
96+
stateAKeys.forEach((key) => {
97+
if (!stateBKeys.includes(key)) {
98+
mutations.push({
99+
delimiter: getChangeMutationsDelimiter,
100+
args: [],
101+
path: path.concat(key).join('.'),
102+
hasChangedValue: false,
103+
method: 'unset',
104+
revert: getChangeMutationsRevert
105+
})
106+
}
107+
})
108+
109+
stateBKeys.forEach((key) => {
110+
if (isPlainObject(stateA[key]) && isPlainObject(stateB[key])) {
111+
getChangeMutations(stateA[key], stateB[key], path.concat(key), mutations)
112+
} else if (stateA[key] !== stateB[key]) {
113+
mutations.push({
114+
delimiter: getChangeMutationsDelimiter,
115+
args: [stateB[key]],
116+
path: path.concat(key).join('.'),
117+
hasChangedValue: false,
118+
method: 'set',
119+
revert: getChangeMutationsRevert
120+
})
121+
}
122+
})
123+
124+
return mutations
125+
}
93126

94127

95128
export function getActionPaths(actions = {}, currentPath: string[] = []) {

packages/node_modules/proxy-state-tree/src/MutationTree.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import {
99

1010
export class MutationTree<T extends object> implements IMutationTree<T> {
1111
private mutationCallbacks: IMutationCallback[] = []
12-
private disposeOnReset: Function
1312
master: IProxyStateTree<T>
1413
state: T
1514
proxifier: IProxifier<T>
@@ -23,9 +22,6 @@ export class MutationTree<T extends object> implements IMutationTree<T> {
2322
this.master = master
2423
this.proxifier = proxifier || new Proxifier(this)
2524
this.state = this.proxifier.proxify(master.sourceState, '')
26-
this.disposeOnReset = master.onReset(() => {
27-
this.state = this.proxifier.proxify(master.sourceState, '')
28-
})
2925
}
3026
trackPaths() {
3127
const paths = new Set<string>()
@@ -105,7 +101,6 @@ export class MutationTree<T extends object> implements IMutationTree<T> {
105101
this.isBlocking = false
106102
}
107103
dispose() {
108-
this.disposeOnReset()
109104
this.isTracking = false
110105
this.mutationCallbacks.length = 0
111106
this.proxifier = this.master.proxifier

packages/node_modules/proxy-state-tree/src/TrackStateTree.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,6 @@ export class TrackStateTree<T extends object> implements ITrackStateTree<T> {
1919
this.master = master
2020
this.proxifier = master.proxifier
2121
this.state = master.state
22-
this.disposeOnReset = this.master.onReset(() => {
23-
this.state = master.state
24-
})
2522
}
2623
trackPaths() {
2724
const paths = new Set<string>()
@@ -97,7 +94,6 @@ export class TrackStateTree<T extends object> implements ITrackStateTree<T> {
9794
return result
9895
}
9996
dispose() {
100-
this.disposeOnReset()
10197
if (!this.callback) {
10298
this.pathDependencies.clear()
10399

packages/node_modules/proxy-state-tree/src/index.ts

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ export class ProxyStateTree<T extends object> implements IProxyStateTree<T> {
3636
mutationTree: [] as IMutationTree<T>[],
3737
trackStateTree: [] as ITrackStateTree<T>[],
3838
}
39-
private onResetCallbacks: Function[] = []
4039
flushCallbacks: IFlushCallback[] = []
4140
mutationCallbacks: IMutationCallback[] = []
4241
currentFlushId: number = 0
@@ -86,13 +85,6 @@ export class ProxyStateTree<T extends object> implements IProxyStateTree<T> {
8685
''
8786
)
8887
}
89-
onReset(cb: Function) {
90-
this.onResetCallbacks.push(cb)
91-
92-
return () => {
93-
this.onResetCallbacks.splice(this.onResetCallbacks.indexOf(cb), 1)
94-
}
95-
}
9688
getMutationTree(): IMutationTree<T> {
9789
if (!this.options.devmode) {
9890
return (this.mutationTree =
@@ -249,11 +241,6 @@ export class ProxyStateTree<T extends object> implements IProxyStateTree<T> {
249241
delete this.pathDependencies[path]
250242
}
251243
}
252-
reset(state: T) {
253-
this.sourceState = state
254-
this.createTrackStateProxifier()
255-
this.onResetCallbacks.forEach((cb) => cb())
256-
}
257244
toJSON() {
258245
return this.sourceState
259246
}

packages/node_modules/proxy-state-tree/src/types.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,6 @@ export interface IRemoveProxyCallback {
9494
}
9595

9696
export interface IProxyStateTree<T extends object> {
97-
onReset(cb: Function): () => void
9897
addPathDependency(path: string, callback: ITrackCallback): void
9998
removePathDependency(path: string, callback: ITrackCallback): void
10099
getTrackStateTree(): ITrackStateTree<T>

0 commit comments

Comments
 (0)