-
Notifications
You must be signed in to change notification settings - Fork 10.3k
/
index.js
120 lines (107 loc) · 2.95 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
const Redux = require(`redux`)
const _ = require(`lodash`)
const fs = require(`fs`)
const mitt = require(`mitt`)
const stringify = require(`json-stringify-safe`)
// Create event emitter for actions
const emitter = mitt()
// Reducers
const reducers = require(`./reducers`)
const objectToMap = obj => {
let map = new Map()
Object.keys(obj).forEach(key => {
map.set(key, obj[key])
})
return map
}
const mapToObject = map => {
const obj = {}
for (let [key, value] of map) {
obj[key] = value
}
return obj
}
// Read from cache the old node data.
let initialState = {}
try {
const file = fs.readFileSync(`${process.cwd()}/.cache/redux-state.json`)
// Apparently the file mocking in node-tracking-test.js
// can override the file reading replacing the mocked string with
// an already parsed object.
if (Buffer.isBuffer(file) || typeof file === `string`) {
initialState = JSON.parse(file)
}
if (initialState.staticQueryComponents) {
initialState.staticQueryComponents = objectToMap(
initialState.staticQueryComponents
)
}
if (initialState.components) {
initialState.components = objectToMap(initialState.components)
}
if (initialState.nodes) {
initialState.nodes = objectToMap(initialState.nodes)
}
} catch (e) {
// ignore errors.
}
const store = Redux.createStore(
Redux.combineReducers({ ...reducers }),
initialState,
Redux.applyMiddleware(function multi({ dispatch }) {
return next => action =>
Array.isArray(action)
? action.filter(Boolean).map(dispatch)
: next(action)
})
)
// Persist state.
const saveState = state => {
const pickedState = _.pick(state, [
`nodes`,
`status`,
`componentDataDependencies`,
`jsonDataPaths`,
`components`,
`staticQueryComponents`,
])
pickedState.staticQueryComponents = mapToObject(
pickedState.staticQueryComponents
)
pickedState.components = mapToObject(pickedState.components)
pickedState.nodes = mapToObject(pickedState.nodes)
const stringified = stringify(pickedState, null, 2)
fs.writeFile(
`${process.cwd()}/.cache/redux-state.json`,
stringified,
() => {}
)
}
const saveStateDebounced = _.debounce(saveState, 1000)
store.subscribe(() => {
const lastAction = store.getState().lastAction
emitter.emit(lastAction.type, lastAction)
})
// During development, once bootstrap is finished, persist state on changes.
let bootstrapFinished = false
if (process.env.gatsby_executing_command === `develop`) {
emitter.on(`BOOTSTRAP_FINISHED`, () => {
bootstrapFinished = true
saveState(store.getState())
})
emitter.on(`*`, () => {
if (bootstrapFinished) {
saveStateDebounced(store.getState())
}
})
}
// During builds, persist state once bootstrap has finished.
if (process.env.gatsby_executing_command === `build`) {
emitter.on(`BOOTSTRAP_FINISHED`, () => {
saveState(store.getState())
})
}
/** Event emitter */
exports.emitter = emitter
/** Redux store */
exports.store = store