Skip to content

Commit 17a67a5

Browse files
stefanprobstpieh
authored andcommitted
feat(gatsby): allow awaiting API run triggered by createNode action (#12748)
1 parent 1fe6f9d commit 17a67a5

File tree

8 files changed

+86
-62
lines changed

8 files changed

+86
-62
lines changed

packages/gatsby-source-filesystem/src/create-remote-file-node.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ async function processRemoteNode({
242242
// be the owner of File nodes or there'll be conflicts if any other
243243
// File nodes are created through normal usages of
244244
// gatsby-source-filesystem.
245-
createNode(fileNode, { name: `gatsby-source-filesystem` })
245+
await createNode(fileNode, { name: `gatsby-source-filesystem` })
246246

247247
return fileNode
248248
}

packages/gatsby/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@
109109
"react-error-overlay": "^3.0.0",
110110
"react-hot-loader": "^4.6.2",
111111
"redux": "^4.0.0",
112+
"redux-thunk": "^2.3.0",
112113
"semver": "^5.6.0",
113114
"shallow-compare": "^1.2.2",
114115
"sift": "^5.1.0",

packages/gatsby/src/redux/__tests__/nodes.js

+28-23
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,19 @@
1-
const Redux = require(`redux`)
21
const { actions } = require(`../actions`)
32
const nodeReducer = require(`../reducers/nodes`)
43
const nodeTouchedReducer = require(`../reducers/nodes-touched`)
54

65
jest.mock(`../../db/nodes`)
76
jest.mock(`../nodes`)
87

9-
const store = Redux.createStore(
10-
Redux.combineReducers({ nodeReducer, nodeTouchedReducer }),
11-
{}
12-
)
8+
const dispatch = jest.fn()
9+
1310
describe(`Create and update nodes`, () => {
1411
beforeEach(() => {
15-
store.dispatch({
16-
type: `DELETE_CACHE`,
17-
})
12+
dispatch.mockClear()
1813
})
1914

2015
it(`allows creating nodes`, () => {
21-
const action = actions.createNode(
16+
actions.createNode(
2217
{
2318
id: `hi`,
2419
children: [],
@@ -32,13 +27,14 @@ describe(`Create and update nodes`, () => {
3227
{
3328
name: `tests`,
3429
}
35-
)
30+
)(dispatch)
31+
const action = dispatch.mock.calls[0][0]
3632
expect(action).toMatchSnapshot()
3733
expect(nodeReducer(undefined, action)).toMatchSnapshot()
3834
})
3935

4036
it(`allows updating nodes`, () => {
41-
const action = actions.createNode(
37+
actions.createNode(
4238
{
4339
id: `hi`,
4440
children: [],
@@ -61,8 +57,10 @@ describe(`Create and update nodes`, () => {
6157
{
6258
name: `tests`,
6359
}
64-
)
65-
const updateAction = actions.createNode(
60+
)(dispatch)
61+
const action = dispatch.mock.calls[0][0]
62+
63+
actions.createNode(
6664
{
6765
id: `hi`,
6866
children: [],
@@ -82,7 +80,9 @@ describe(`Create and update nodes`, () => {
8280
{
8381
name: `tests`,
8482
}
85-
)
83+
)(dispatch)
84+
const updateAction = dispatch.mock.calls[1][0]
85+
8686
let state = nodeReducer(undefined, action)
8787
state = nodeReducer(state, updateAction)
8888
expect(state.get(`hi`).pickle).toEqual(false)
@@ -91,7 +91,7 @@ describe(`Create and update nodes`, () => {
9191
})
9292

9393
it(`nodes that are added are also "touched"`, () => {
94-
const action = actions.createNode(
94+
actions.createNode(
9595
{
9696
id: `hi`,
9797
children: [],
@@ -105,13 +105,15 @@ describe(`Create and update nodes`, () => {
105105
{
106106
name: `tests`,
107107
}
108-
)
108+
)(dispatch)
109+
const action = dispatch.mock.calls[0][0]
110+
109111
let state = nodeTouchedReducer(undefined, action)
110112
expect(state[`hi`]).toBe(true)
111113
})
112114

113115
it(`allows adding fields to nodes`, () => {
114-
const action = actions.createNode(
116+
actions.createNode(
115117
{
116118
id: `hi`,
117119
children: [],
@@ -125,7 +127,8 @@ describe(`Create and update nodes`, () => {
125127
{
126128
name: `tests`,
127129
}
128-
)
130+
)(dispatch)
131+
const action = dispatch.mock.calls[0][0]
129132
let state = nodeReducer(undefined, action)
130133

131134
const addFieldAction = actions.createNodeField(
@@ -138,12 +141,13 @@ describe(`Create and update nodes`, () => {
138141
name: `test`,
139142
}
140143
)
144+
141145
state = nodeReducer(state, addFieldAction)
142146
expect(state).toMatchSnapshot()
143147
})
144148

145149
it(`throws error if a field is updated by a plugin not its owner`, () => {
146-
const action = actions.createNode(
150+
actions.createNode(
147151
{
148152
id: `hi`,
149153
children: [],
@@ -157,7 +161,8 @@ describe(`Create and update nodes`, () => {
157161
{
158162
name: `tests`,
159163
}
160-
)
164+
)(dispatch)
165+
const action = dispatch.mock.calls[0][0]
161166
let state = nodeReducer(undefined, action)
162167

163168
const addFieldAction = actions.createNodeField(
@@ -202,7 +207,7 @@ describe(`Create and update nodes`, () => {
202207
{
203208
name: `pluginA`,
204209
}
205-
)
210+
)(dispatch)
206211

207212
function callActionCreator() {
208213
actions.createNode(
@@ -219,7 +224,7 @@ describe(`Create and update nodes`, () => {
219224
{
220225
name: `pluginB`,
221226
}
222-
)
227+
)(dispatch)
223228
}
224229

225230
expect(callActionCreator).toThrowErrorMatchingSnapshot()
@@ -244,7 +249,7 @@ describe(`Create and update nodes`, () => {
244249
{
245250
name: `pluginA`,
246251
}
247-
)
252+
)(dispatch)
248253
}
249254

250255
expect(callActionCreator).toThrowErrorMatchingSnapshot()

packages/gatsby/src/redux/actions.js

+24-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const { store } = require(`./index`)
1717
const fileExistsSync = require(`fs-exists-cached`).sync
1818
const joiSchemas = require(`../joi-schemas/joi`)
1919
const { generateComponentChunkName } = require(`../utils/js-chunk-names`)
20+
const apiRunnerNode = require(`../utils/api-runner-node`)
2021

2122
const actions = {}
2223

@@ -527,6 +528,8 @@ const typeOwners = {}
527528
* readable description of what this node represent / its source. It will
528529
* be displayed when type conflicts are found, making it easier to find
529530
* and correct type conflicts.
531+
* @returns {Promise} The returned Promise resolves when all cascading
532+
* `onCreateNode` API calls triggered by `createNode` have finished.
530533
* @example
531534
* createNode({
532535
* // Data for the node.
@@ -551,7 +554,7 @@ const typeOwners = {}
551554
* }
552555
* })
553556
*/
554-
actions.createNode = (
557+
const createNode = (
555558
node: any,
556559
plugin?: Plugin,
557560
actionOptions?: ActionOptions = {}
@@ -716,6 +719,26 @@ actions.createNode = (
716719
}
717720
}
718721

722+
actions.createNode = (...args) => dispatch => {
723+
const actions = createNode(...args)
724+
dispatch(actions)
725+
const createNodeAction = (Array.isArray(actions) ? actions : [actions]).find(
726+
action => action.type === `CREATE_NODE`
727+
)
728+
729+
if (!createNodeAction) {
730+
return undefined
731+
}
732+
733+
const { payload: node, traceId, parentSpan } = createNodeAction
734+
return apiRunnerNode(`onCreateNode`, {
735+
node,
736+
traceId,
737+
parentSpan,
738+
traceTags: { nodeId: node.id, nodeType: node.internal.type },
739+
})
740+
}
741+
719742
/**
720743
* "Touch" a node. Tells Gatsby a node still exists and shouldn't
721744
* be garbage collected. Primarily useful for source plugins fetching

packages/gatsby/src/redux/index.js

+24-23
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,13 @@ const Redux = require(`redux`)
22
const _ = require(`lodash`)
33

44
const mitt = require(`mitt`)
5+
const thunk = require(`redux-thunk`).default
6+
const reducers = require(`./reducers`)
7+
const { writeToCache, readFromCache } = require(`./persist`)
58

69
// Create event emitter for actions
710
const emitter = mitt()
811

9-
// Reducers
10-
const reducers = require(`./reducers`)
11-
const { writeToCache, readFromCache } = require(`./persist`)
12-
1312
// Read old node data from cache.
1413
const readState = () => {
1514
try {
@@ -32,21 +31,23 @@ const readState = () => {
3231
return {}
3332
}
3433

35-
exports.readState = readState
34+
/**
35+
* Redux middleware handling array of actions
36+
*/
37+
const multi = ({ dispatch }) => next => action =>
38+
Array.isArray(action) ? action.filter(Boolean).map(dispatch) : next(action)
3639

37-
const store = Redux.createStore(
38-
Redux.combineReducers({ ...reducers }),
39-
readState(),
40-
Redux.applyMiddleware(function multi({ dispatch }) {
41-
return next => action =>
42-
Array.isArray(action)
43-
? action.filter(Boolean).map(dispatch)
44-
: next(action)
45-
})
46-
)
40+
const configureStore = initialState =>
41+
Redux.createStore(
42+
Redux.combineReducers({ ...reducers }),
43+
initialState,
44+
Redux.applyMiddleware(thunk, multi)
45+
)
46+
47+
const store = configureStore(readState())
4748

4849
// Persist state.
49-
function saveState() {
50+
const saveState = () => {
5051
if (process.env.DANGEROUSLY_DISABLE_OOM) {
5152
return Promise.resolve()
5253
}
@@ -64,15 +65,15 @@ function saveState() {
6465
return writeToCache(pickedState)
6566
}
6667

67-
exports.saveState = saveState
68-
6968
store.subscribe(() => {
7069
const lastAction = store.getState().lastAction
7170
emitter.emit(lastAction.type, lastAction)
7271
})
7372

74-
/** Event emitter */
75-
exports.emitter = emitter
76-
77-
/** Redux store */
78-
exports.store = store
73+
module.exports = {
74+
emitter,
75+
store,
76+
configureStore,
77+
readState,
78+
saveState,
79+
}

packages/gatsby/src/redux/plugin-runner.js

-12
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,8 @@
11
// Invoke plugins for certain actions.
22

33
const { emitter } = require(`./index`)
4-
const { getNode } = require(`../db/nodes`)
54
const apiRunnerNode = require(`../utils/api-runner-node`)
65

7-
emitter.on(`CREATE_NODE`, action => {
8-
const node = getNode(action.payload.id)
9-
const traceTags = { nodeId: node.id, nodeType: node.internal.type }
10-
apiRunnerNode(`onCreateNode`, {
11-
node,
12-
traceId: action.traceId,
13-
parentSpan: action.parentSpan,
14-
traceTags,
15-
})
16-
})
17-
186
emitter.on(`CREATE_PAGE`, action => {
197
const page = action.payload
208
apiRunnerNode(

packages/gatsby/src/utils/api-runner-node.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,11 @@ const doubleBind = (boundActionCreators, api, plugin, actionOptions) => {
3737
// Let action callers override who the plugin is. Shouldn't be
3838
// used that often.
3939
if (args.length === 1) {
40-
boundActionCreator(args[0], plugin, actionOptions)
40+
return boundActionCreator(args[0], plugin, actionOptions)
4141
} else if (args.length === 2) {
42-
boundActionCreator(args[0], args[1], actionOptions)
42+
return boundActionCreator(args[0], args[1], actionOptions)
4343
}
44+
return undefined
4445
}
4546
}
4647
}

yarn.lock

+5
Original file line numberDiff line numberDiff line change
@@ -17742,6 +17742,11 @@ reduce@^1.0.1:
1774217742
dependencies:
1774317743
object-keys "~1.0.0"
1774417744

17745+
redux-thunk@^2.3.0:
17746+
version "2.3.0"
17747+
resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.3.0.tgz#51c2c19a185ed5187aaa9a2d08b666d0d6467622"
17748+
integrity sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw==
17749+
1774517750
redux@^4.0.0:
1774617751
version "4.0.1"
1774717752
resolved "https://registry.yarnpkg.com/redux/-/redux-4.0.1.tgz#436cae6cc40fbe4727689d7c8fae44808f1bfef5"

0 commit comments

Comments
 (0)