Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[v2] improve how we load GraphQL query results in development/production (aka Ludicrous Mode) #4555

Merged
merged 38 commits into from
Apr 6, 2018
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
e218c1f
Create placeholder JSON store
m-allanson Mar 15, 2018
0894947
Rename
m-allanson Mar 15, 2018
4ca7dda
Websocket placeholder
m-allanson Mar 15, 2018
cf55f6b
Push query results JSON over websockets
m-allanson Mar 15, 2018
293f36a
More descriptive variable name
m-allanson Mar 16, 2018
7e852cf
Fix queries being overwritten
m-allanson Mar 16, 2018
2adaffe
Remove eslint-disable flag
m-allanson Mar 16, 2018
c03cc34
Remove junk
m-allanson Mar 16, 2018
ca50615
test require error fix for windows
pieh Mar 15, 2018
460ca7d
dont require json data in sync-require
pieh Mar 15, 2018
f4c92e5
dont add layout data to json array multiple times
pieh Mar 16, 2018
e6239ee
initial async loading
pieh Mar 16, 2018
4e064d7
revert saving json directly to public for now
pieh Mar 16, 2018
1801fa7
updated production-app to sync with prop name change in ComponentRend…
pieh Mar 16, 2018
53bc172
we load json data via json-loader component in develop and not handli…
pieh Mar 16, 2018
adc3ce1
hashes for json files
pieh Mar 17, 2018
9008479
fix preloading, use xhr instead of fetch - for some reason can't forc…
pieh Mar 20, 2018
3050620
dont use full paths in dataPath - remove static/d/ path and .json ext…
pieh Mar 21, 2018
46e5235
Merge pull request #4635 from pieh/json-loader
m-allanson Mar 21, 2018
a3b6aee
Enable cached query results to be loaded
m-allanson Mar 22, 2018
66e462c
Don't dump all query results out to the client
m-allanson Mar 26, 2018
8196649
Merge pull request #4658 from m-allanson/load-develop-query-results
m-allanson Mar 26, 2018
7602a73
Merge remote-tracking branch 'upstream/v2' into json-loader-w4
pieh Mar 26, 2018
f0b3b0c
fix preload link to json data
pieh Mar 26, 2018
c268376
Merge remote-tracking branch 'upstream/v2' into json-loader
pieh Mar 28, 2018
2d9e286
remove not used function
pieh Mar 28, 2018
95fcd4a
remove more not used code
pieh Mar 28, 2018
20252dc
Update to latest webpack/mini-css-extract-plugin
KyleAMathews Mar 29, 2018
44797c3
don't write new (a)sync-requires.js if components didn't change (#4759)
pieh Mar 29, 2018
467a792
create just one websocket client (#4763)
pieh Mar 29, 2018
dd442c7
Filter out duplicate query jobs and create secondary queue for jobs i…
KyleAMathews Mar 29, 2018
abcb58c
[json-loader] Don't emit new file node until previous is finished pro…
KyleAMathews Apr 3, 2018
e374818
[json-loader] Only log file events if we're past bootstrap (#4826)
KyleAMathews Apr 3, 2018
62754de
[json-loader] dont recompile on data change - part 2 (#4837)
pieh Apr 5, 2018
4a09f74
[json-loader] develop - reading results from file improvments (#4850)
pieh Apr 5, 2018
868ef8b
Add query prioritization based on what page(s) user(s) are on
KyleAMathews Apr 5, 2018
b4fdecb
Add initial forward slash
KyleAMathews Apr 6, 2018
1bb7cc4
Actually this is how we add back the initial forward slash
KyleAMathews Apr 6, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 34 additions & 13 deletions packages/gatsby/cache-dir/json-store.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,40 +10,61 @@ class JSONStore extends React.Component {
super(props)
this.state = {
data: {},
receivedData: false,
}
try {
this.socket = window.io()
} catch (err) {
console.error(`Could not connect to socket.io on dev server.`)
}
this.setPageData = this.setPageData.bind(this)
this.getPageData = this.getPageData.bind(this)
}

componentDidMount() {
this.socket.on(`queryResult`, data => {
this.setState({
data,
receivedData: true,
})
this.socket.on(`queryResult`, this.setPageData)
}

shouldComponentUpdate(nextProps, nextState) {
if (nextProps !== this.props) return true

// if json for nextState is not available
const nextJsonId = get(nextProps.pageResources, `page.jsonName`)
if (!nextState.data[nextJsonId]) return false

// if nextState json is the same as current state json
const sameDataPath =
get(nextState, `data[${nextJsonId}].dataPath`) ===
get(this, `state.data[${nextJsonId}].dataPath`)

if (sameDataPath) return false

return true
}

setPageData(newData) {
this.setState({
data: { [newData.path]: newData },
})
}

getPageData(path) {
const ob = this.state.data[path]
if (!ob) {
console.log(`Missing JSON: ${path}`)
return {}
}
return JSON.parse(ob)
const res = this.state.data[path]

// always check for fresh data
this.socket.emit(`getPageData`, path)

if (!res || !res.data) return false
return JSON.parse(res.data)
}

render() {
if (!this.state.receivedData) return ``
const { isPage, pages, pageResources } = this.props
const propsWithoutPages = omit(this.props, `pages`)

if (isPage) {
const jsonId = get(pageResources, `page.jsonName`)
const pageData = this.getPageData(jsonId)
if (pageData === false) return ``
return createElement(ComponentRenderer, {
key: `normal-page`,
...propsWithoutPages,
Expand Down
13 changes: 4 additions & 9 deletions packages/gatsby/src/commands/develop.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const formatWebpackMessages = require(`react-dev-utils/formatWebpackMessages`)
const chalk = require(`chalk`)
const address = require(`address`)
const sourceNodes = require(`../utils/source-nodes`)
const ws = require(`../utils/websocket`)
const websocketManager = require(`../utils/websocket-manager`)

// const isInteractive = process.stdout.isTTY

Expand Down Expand Up @@ -196,14 +196,9 @@ async function startServer(program) {
/**
* Set up the HTTP server and socket.io.
**/

const server = require(`http`).Server(app)
ws.init(server)
const io = ws.instance()
io.on(`connection`, socket => {
socket.join(`clients`)
socket.emit(`queryResult`, ws.flushResults())
})
websocketManager.init({ server, directory: program.directory })
const socket = websocketManager.getSocket()

const listener = server.listen(program.port, program.host, err => {
if (err) {
Expand All @@ -228,7 +223,7 @@ async function startServer(program) {

chokidar.watch(watchGlobs).on(`change`, async () => {
await createIndexHtml()
io.to(`clients`).emit(`reload`)
socket.to(`clients`).emit(`reload`)
})

return [compiler, listener]
Expand Down
36 changes: 13 additions & 23 deletions packages/gatsby/src/internal-plugins/query-runner/pages-writer.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const getLayoutById = layouts => id => layouts.find(l => l.id === id)
// Write out pages information.
const writePages = async () => {
bootstrapFinished = true
let { program, pages, layouts } = store.getState()
let { program, jsonDataPaths, pages, layouts } = store.getState()
// Write out pages.json
const pagesData = pages.reduce(
(mem, { path, matchPath, componentChunkName, layout, jsonName }) => {
Expand Down Expand Up @@ -40,9 +40,10 @@ const writePages = async () => {
componentChunkName: p.componentChunkName,
component: p.component,
})

if (p.layout) {
let layout = getLayoutById(layouts)(p.layout)

const layoutDataPath = jsonDataPaths[layout.jsonName]
if (!layout) {
throw new Error(
`Could not find layout '${
Expand All @@ -53,34 +54,34 @@ const writePages = async () => {

if (!_.includes(pageLayouts, layout)) {
pageLayouts.push(layout)
if (layout.dataPath) {
if (typeof layoutDataPath !== `undefined`) {
json.push({
jsonName: layout.jsonName,
dataPath: layout.dataPath,
layoutDataPath,
})
}

const wrapperComponent = `
import React from "react"
import Component from "${layout.component}"
${layout.dataPath &&
${layoutDataPath &&
`import data from "${joinPath(
program.directory,
`public`,
`static`,
`d`,
`${layout.dataPath}.json`
`${layoutDataPath}.json`
)}"`}
export default (props) => <Component {...props}${layout.dataPath &&


export default (props) => <Component {...props}${layoutDataPath &&
` {...data}`} />
`
fs.writeFileSync(layout.componentWrapperPath, wrapperComponent)
}
}
if (p.dataPath) {
json.push({ jsonName: p.jsonName, dataPath: p.dataPath })
if (p.jsonName && jsonDataPaths[p.jsonName]) {
json.push({ jsonName: p.jsonName, dataPath: jsonDataPaths[p.jsonName] })
}
})

Expand Down Expand Up @@ -124,18 +125,7 @@ const preferDefault = m => m && m.default || m
.join(`,\n`)}
}\n\n`

const staticDataPaths = JSON.stringify(
_.reduce(
json,
(acc, j) => {
acc[j.jsonName] = j.dataPath
return acc
},
{}
),
null,
2
)
const staticDataPaths = JSON.stringify(jsonDataPaths)

asyncRequires += `exports.json = ${staticDataPaths}\n\n`

Expand Down
73 changes: 29 additions & 44 deletions packages/gatsby/src/internal-plugins/query-runner/query-runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { graphql as graphqlFunction } from "graphql"
const fs = require(`fs-extra`)
const report = require(`gatsby-cli/lib/reporter`)
const md5 = require(`md5`)
const ws = require(`../../utils/websocket`)
const websocketManager = require(`../../utils/websocket-manager`)

const path = require(`path`)
const { store } = require(`../../redux`)
Expand Down Expand Up @@ -63,54 +63,39 @@ module.exports = async (pageOrLayout, component) => {

if (resultHashes[pageOrLayout.jsonName] !== resultHash) {
resultHashes[pageOrLayout.jsonName] = resultHash
const programType = program._[0]

// In production, write file to public/static/d/ folder.
if (programType === `build`) {
const dataPath = `${generatePathChunkName(
pageOrLayout.jsonName
)}-${resultHash}`

const resultPath = path.join(
program.directory,
`public`,
`static`,
`d`,
`${dataPath}.json`
)
await fs.writeFile(resultPath, resultJSON)

if (!pageOrLayout.path) {
store.dispatch({
type: `SET_LAYOUT_DATA_PATH`,
payload: {
id: pageOrLayout.id,
dataPath,
},
})
} else {
store.dispatch({
type: `SET_PAGE_DATA_PATH`,
payload: {
path: pageOrLayout.path,
dataPath,
},
})
}
// Always write file to public/static/d/ folder.
const dataPath = `${generatePathChunkName(
pageOrLayout.jsonName
)}-${resultHash}`

return
}
const programType = program._[0]

// In development queue up results until a client is available
// push subsequent results to client
if (programType === `develop`) {
const result = {}
result[pageOrLayout.jsonName] = resultJSON
ws.pushResult(result)
const sockets = ws.instance()
if (sockets) {
sockets.emit(`queryResult`, result)
const data = {
dataPath,
data: resultJSON,
path: pageOrLayout.jsonName,
}
websocketManager.emitData({ data })
}

const resultPath = path.join(
program.directory,
`public`,
`static`,
`d`,
`${dataPath}.json`
)
await fs.writeFile(resultPath, resultJSON)

store.dispatch({
type: `SET_JSON_DATA_PATH`,
payload: {
[pageOrLayout.jsonName]: dataPath,
},
})

return
}
}
1 change: 1 addition & 0 deletions packages/gatsby/src/redux/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ const saveState = _.debounce(state => {
`nodes`,
`status`,
`componentDataDependencies`,
`jsonDataPaths`,
])
fs.writeFile(
`${process.cwd()}/.cache/redux-state.json`,
Expand Down
1 change: 1 addition & 0 deletions packages/gatsby/src/redux/reducers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ module.exports = {
webpack: require(`./webpack`),
redirects: require(`./redirects`),
babelrc: require(`./babelrc`),
jsonDataPaths: require(`./json-data-paths`),
}
17 changes: 17 additions & 0 deletions packages/gatsby/src/redux/reducers/json-data-paths.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// const omit = require(`lodash/omit`)

module.exports = (state = {}, action) => {
switch (action.type) {
// case `DELETE_ALL_JSON_DATA_PATHS`:
// return {}
case `SET_JSON_DATA_PATH`:
return {
...state,
...action.payload,
}
// case `DELETE_JSON_DATA_PATH`:
// return omit(state, action.payload)
default:
return state
}
}
12 changes: 0 additions & 12 deletions packages/gatsby/src/redux/reducers/layouts.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,7 @@ module.exports = (state = [], action) => {
return [...state.concat(action.payload)]
}
}
case `SET_LAYOUT_DATA_PATH`: {
const index = _.findIndex(state, l => l.id === action.payload.id)
if (index !== -1) {
return [
...state
.slice(0, index)
.concat({ ...state[index], dataPath: action.payload.dataPath })
.concat(state.slice(index + 1)),
]
}

return state
}
case `DELETE_LAYOUT`:
return state.filter(l => l.id !== action.payload.id)
default:
Expand Down
12 changes: 0 additions & 12 deletions packages/gatsby/src/redux/reducers/pages.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,7 @@ module.exports = (state = [], action) => {
return [...state.concat(action.payload)]
}
}
case `SET_PAGE_DATA_PATH`: {
const index = _.findIndex(state, p => p.path === action.payload.path)
if (index !== -1) {
return [
...state
.slice(0, index)
.concat({ ...state[index], dataPath: action.payload.dataPath })
.concat(state.slice(index + 1)),
]
}

return state
}
case `DELETE_PAGE`:
return state.filter(p => p.path !== action.payload.path)
default:
Expand Down
Loading