Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions packages/gatsby-link/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,13 +103,15 @@ class GatsbyLink extends React.Component {
activeStyle: $activeStyle,
ref: $ref,
innerRef: $innerRef,
state,
/* eslint-enable no-unused-vars */
...rest
} = this.props

return (
<Link
to={to}
state={state}
getProps={getProps}
innerRef={this.handleRef}
onMouseEnter={e => {
Expand Down
2 changes: 1 addition & 1 deletion packages/gatsby/cache-dir/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ apiRunnerAsync(`onClientEntry`).then(() => {
loader.addPagesArray(pages)
loader.addDevRequires(syncRequires)

loader.getResourcesForPathname(window.location.pathname, () => {
loader.getResourcesForPathname(window.location.pathname).then(() => {
let Root = hot(module)(preferDefault(require(`./root`)))
domReady(() => {
renderer(<Root />, rootElement, () => {
Expand Down
168 changes: 88 additions & 80 deletions packages/gatsby/cache-dir/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -274,18 +274,18 @@ const queue = {

getPage: pathname => findPage(pathname),

getResourcesForPathname: (path, cb = () => {}) => {
// If we're loading from a service worker (it's already activated on
// this initial render) and we can't find a page, there's a good chance
// we're on a new page that this (now old) service worker doesn't know
// about so we'll unregister it and reload.
checkIfDoingInitialRenderForSW: path => {
if (
inInitialRender &&
navigator &&
navigator.serviceWorker &&
navigator.serviceWorker.controller &&
navigator.serviceWorker.controller.state === `activated`
) {
// If we're loading from a service worker (it's already activated on
// this initial render) and we can't find a page, there's a good chance
// we're on a new page that this (now old) service worker doesn't know
// about so we'll unregister it and reload.
if (!findPage(path)) {
navigator.serviceWorker
.getRegistrations()
Expand All @@ -303,97 +303,104 @@ const queue = {
})
}
}
const doingInitialRender = inInitialRender
inInitialRender = false
// In development we know the code is loaded already
// so we just return with it immediately.
if (process.env.NODE_ENV !== `production`) {
const page = findPage(path)
if (!page) {
cb()
return null
}
const pageResources = {
component: syncRequires.components[page.componentChunkName],
page,
}
},

const onDataCallback = () => {
cb(pageResources)
}
getResourcesForPathnameSync: path => pathScriptsCache[path],

getResourcesForPathname: path => {
queue.checkIfDoingInitialRenderForSW(path)

if (devGetPageData(page.path, onDataCallback)) {
return pageResources
return new Promise((resolve, reject) => {
const doingInitialRender = inInitialRender
inInitialRender = false

// Production code path
if (failedPaths[path]) {
handleResourceLoadError(
path,
`Previously detected load failure for "${path}"`
)
return reject()
}
return null
}
// Production code path
if (failedPaths[path]) {
handleResourceLoadError(
path,
`Previously detected load failure for "${path}"`
)
cb()
return null
}
const page = findPage(path)
const page = findPage(path)

if (!page && !fetchedPageResourceMap) {
// If page wasn't found check and we didn't fetch resources map for
// all pages, wait for fetch to complete and try to get resources again
fetchPageResourceMap().then(() => {
queue.getResourcesForPathname(path, cb)
})
return null
}
if (!page && !fetchedPageResourceMap) {
// If page wasn't found check and we didn't fetch resources map for
// all pages, wait for fetch to complete and try to get resources again
fetchPageResourceMap().then(() =>
resolve(queue.getResourcesForPathname(path))
)
}

if (!page) {
console.log(`A page wasn't found for "${path}"`)
cb()
return null
}
if (!page) {
console.log(`A page wasn't found for "${path}"`)
return reject()
}

// Use the path from the page so the pathScriptsCache uses
// the normalized path.
path = page.path
// Use the path from the page so the pathScriptsCache uses
// the normalized path.
path = page.path

// Check if it's in the cache already.
if (pathScriptsCache[path]) {
Promise.resolve().then(() => {
cb(pathScriptsCache[path])
// Check if it's in the cache already.
if (pathScriptsCache[path]) {
emitter.emit(`onPostLoadPageResources`, {
page,
pageResources: pathScriptsCache[path],
})
})
return pathScriptsCache[path]
}
return resolve(pathScriptsCache[path])
}

emitter.emit(`onPreLoadPageResources`, { path })
// Nope, we need to load resource(s)

Promise.all([
getResourceModule(page.componentChunkName),
getResourceModule(page.jsonName),
]).then(([component, json]) => {
const pageResources = { component, json, page }
pageResources.page.jsonURL = createJsonURL(jsonDataPaths[page.jsonName])
pathScriptsCache[path] = pageResources
cb(pageResources)

emitter.emit(`onPostLoadPageResources`, {
page,
pageResources,
// Nope, we need to load resource(s)
emitter.emit(`onPreLoadPageResources`, {
path,
})

if (doingInitialRender) {
// We got all resourecs needed for first mount,
// we can fetch resoures for all pages.
fetchPageResourceMap()
// In development we know the code is loaded already
// so we just return with it immediately.
if (process.env.NODE_ENV !== `production`) {
const page = findPage(path)
const pageResources = {
component: syncRequires.components[page.componentChunkName],
page,
}
// Add to the cache.
pathScriptsCache[path] = pageResources
devGetPageData(page.path).then(pageData => {
emitter.emit(`onPostLoadPageResources`, {
page,
pageResources,
})
resolve(pageResources)
})
} else {
Promise.all([
getResourceModule(page.componentChunkName),
getResourceModule(page.jsonName),
]).then(([component, json]) => {
const pageResources = {
component,
json,
page,
}
pageResources.page.jsonURL = createJsonURL(
jsonDataPaths[page.jsonName]
)
pathScriptsCache[path] = pageResources
resolve(pageResources)

emitter.emit(`onPostLoadPageResources`, {
page,
pageResources,
})

if (doingInitialRender) {
// We got all resources needed for first mount,
// we can fetch resoures for all pages.
fetchPageResourceMap()
}
})
}
})

return null
},

// for testing
Expand All @@ -407,6 +414,7 @@ export const setApiRunnerForLoader = runner => {

export const publicLoader = {
getResourcesForPathname: queue.getResourcesForPathname,
getResourcesForPathnameSync: queue.getResourcesForPathnameSync,
}

export default queue
22 changes: 8 additions & 14 deletions packages/gatsby/cache-dir/navigation.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ function maybeRedirect(pathname) {

if (redirect != null) {
if (process.env.NODE_ENV !== `production`) {
const pageResources = loader.getResourcesForPathname(pathname)
const pageResources = loader.getResourcesForPathnameSync(pathname)

if (pageResources != null) {
console.error(
Expand Down Expand Up @@ -58,6 +58,7 @@ const navigate = (to, replace) => {
// If we had a service worker update, no matter the path, reload window
if (window.GATSBY_SW_UPDATED) {
window.location = pathname
return
}

// Start a timer to wait for a second before transitioning and showing a
Expand All @@ -69,24 +70,17 @@ const navigate = (to, replace) => {
})
}, 1000)

const loaderCallback = pageResources => {
if (!pageResources) {
// We fetch resources for 404 page in page-renderer.js. Calling it
// here is to ensure that we have needed resouces to render page
// before navigating to it
if (process.env.NODE_ENV === `production`) {
loader.getResourcesForPathname(`/404.html`, loaderCallback)
} else {
loader.getResourcesForPathname(pathname).then(pageResources => {
if (!pageResources && process.env.NODE_ENV === `production`) {
loader.getResourcesForPathname(`/404.html`).then(() => {
clearTimeout(timeoutId)
reachNavigate(to, { replace })
}
})
} else {
clearTimeout(timeoutId)
reachNavigate(to, { replace })
clearTimeout(timeoutId)
}
}

loader.getResourcesForPathname(pathname, loaderCallback)
})
}

function shouldUpdateScroll(prevRouterProps, { location: { pathname } }) {
Expand Down
30 changes: 10 additions & 20 deletions packages/gatsby/cache-dir/page-renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,10 @@ class PageRenderer extends React.Component {

// Set the pathname for 404 pages.
const pathname = this.getPathName(location)
this.onPostLoadPageResources = this.onPostLoadPageResources.bind(this)

this.state = {
lastPathname: location.pathname,
pageResources: loader.getResourcesForPathname(pathname),
pageResources: loader.getResourcesForPathnameSync(pathname),
}
}

Expand All @@ -35,7 +34,9 @@ class PageRenderer extends React.Component {
}

if (prevState.lastPathname !== location.pathname) {
const pageResources = loader.getResourcesForPathname(location.pathname)
const pageResources = loader.getResourcesForPathnameSync(
location.pathname
)

if (pageResources) {
nextState.pageResources = pageResources
Expand All @@ -49,24 +50,13 @@ class PageRenderer extends React.Component {
// Listen to events so when our page gets updated, we can transition.
// This is only useful on delayed transitions as the page will get rendered
// without the necessary page resources and then re-render once those come in.
emitter.on(`onPostLoadPageResources`, this.onPostLoadPageResources)
}

onPostLoadPageResources(e) {
const page = loader.getPage(this.props.location.pathname)
emitter.on(`onPostLoadPageResources`, e => {
const page = loader.getPage(this.props.location.pathname)

if (page && e.page.path === page.path) {
// only update state if it changed, otherwise we get into
// weird loop - TODO: find root cause of it instead of this
// workaround.
if (this.state.pageResources !== e.pageResources) {
if (page && e.page.path === page.path) {
this.setState({ pageResources: e.pageResources })
}
}
}

componentWillUnmount() {
emitter.off(`onPostLoadPageResources`, this.onPostLoadPageResources)
})
}

componentDidUpdate(prevProps) {
Expand All @@ -75,11 +65,11 @@ class PageRenderer extends React.Component {
const { location } = this.props
const pathName = this.getPathName(location)

if (!loader.getResourcesForPathname(pathName))
if (!loader.getResourcesForPathnameSync(pathName))
// Page resources won't be set in cases where the browser back button
// or forward button is pushed as we can't wait as normal for resources
// to load before changing the page.
loader.getResourcesForPathname(pathName, pageResources => {
loader.getResourcesForPathnameSync(pathName, pageResources => {
// The page may have changed since we started this, in which case doesn't update
if (this.props.location.pathname !== location.pathname) {
return
Expand Down
2 changes: 1 addition & 1 deletion packages/gatsby/cache-dir/production-app.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ apiRunnerAsync(`onClientEntry`).then(() => {
}
}

loader.getResourcesForPathname(window.location.pathname, () => {
loader.getResourcesForPathname(window.location.pathname).then(() => {
const Root = () =>
createElement(
Router,
Expand Down
2 changes: 1 addition & 1 deletion packages/gatsby/cache-dir/root.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class RouteHandler extends React.Component {
render() {
const { location } = this.props
const { pathname } = location
const pageResources = loader.getResourcesForPathname(pathname)
const pageResources = loader.getResourcesForPathnameSync(pathname)
const isPage = !!(pageResources && pageResources.component)
let child
if (isPage) {
Expand Down
Loading