UNPKG

4.9 kBJavaScriptView Raw
1import { apiRunner, apiRunnerAsync } from "./api-runner-browser"
2import React from "react"
3import ReactDOM from "react-dom"
4import { Router, navigate, Location, BaseContext } from "@reach/router"
5import { ScrollContext } from "gatsby-react-router-scroll"
6import domReady from "@mikaelkristiansson/domready"
7import {
8 shouldUpdateScroll,
9 init as navigationInit,
10 RouteUpdates,
11} from "./navigation"
12import emitter from "./emitter"
13import PageRenderer from "./page-renderer"
14import asyncRequires from "./async-requires"
15import { setLoader, ProdLoader, publicLoader } from "./loader"
16import EnsureResources from "./ensure-resources"
17import stripPrefix from "./strip-prefix"
18
19// Generated during bootstrap
20import matchPaths from "./match-paths.json"
21
22const loader = new ProdLoader(asyncRequires, matchPaths)
23setLoader(loader)
24loader.setApiRunner(apiRunner)
25
26window.asyncRequires = asyncRequires
27window.___emitter = emitter
28window.___loader = publicLoader
29
30navigationInit()
31
32apiRunnerAsync(`onClientEntry`).then(() => {
33 // Let plugins register a service worker. The plugin just needs
34 // to return true.
35 if (apiRunner(`registerServiceWorker`).length > 0) {
36 require(`./register-service-worker`)
37 }
38
39 // In gatsby v2 if Router is used in page using matchPaths
40 // paths need to contain full path.
41 // For example:
42 // - page have `/app/*` matchPath
43 // - inside template user needs to use `/app/xyz` as path
44 // Resetting `basepath`/`baseuri` keeps current behaviour
45 // to not introduce breaking change.
46 // Remove this in v3
47 const RouteHandler = props => (
48 <BaseContext.Provider
49 value={{
50 baseuri: `/`,
51 basepath: `/`,
52 }}
53 >
54 <PageRenderer {...props} />
55 </BaseContext.Provider>
56 )
57
58 class LocationHandler extends React.Component {
59 render() {
60 const { location } = this.props
61 return (
62 <EnsureResources location={location}>
63 {({ pageResources, location }) => (
64 <RouteUpdates location={location}>
65 <ScrollContext
66 location={location}
67 shouldUpdateScroll={shouldUpdateScroll}
68 >
69 <Router
70 basepath={__BASE_PATH__}
71 location={location}
72 id="gatsby-focus-wrapper"
73 >
74 <RouteHandler
75 path={
76 pageResources.page.path === `/404.html`
77 ? stripPrefix(location.pathname, __BASE_PATH__)
78 : encodeURI(
79 pageResources.page.matchPath ||
80 pageResources.page.path
81 )
82 }
83 {...this.props}
84 location={location}
85 pageResources={pageResources}
86 {...pageResources.json}
87 />
88 </Router>
89 </ScrollContext>
90 </RouteUpdates>
91 )}
92 </EnsureResources>
93 )
94 }
95 }
96
97 const { pagePath, location: browserLoc } = window
98
99 // Explicitly call navigate if the canonical path (window.pagePath)
100 // is different to the browser path (window.location.pathname). But
101 // only if NONE of the following conditions hold:
102 //
103 // - The url matches a client side route (page.matchPath)
104 // - it's a 404 page
105 // - it's the offline plugin shell (/offline-plugin-app-shell-fallback/)
106 if (
107 pagePath &&
108 __BASE_PATH__ + pagePath !== browserLoc.pathname &&
109 !(
110 loader.findMatchPath(stripPrefix(browserLoc.pathname, __BASE_PATH__)) ||
111 pagePath === `/404.html` ||
112 pagePath.match(/^\/404\/?$/) ||
113 pagePath.match(/^\/offline-plugin-app-shell-fallback\/?$/)
114 )
115 ) {
116 navigate(__BASE_PATH__ + pagePath + browserLoc.search + browserLoc.hash, {
117 replace: true,
118 })
119 }
120
121 publicLoader.loadPage(browserLoc.pathname).then(page => {
122 if (!page || page.status === `error`) {
123 throw new Error(
124 `page resources for ${browserLoc.pathname} not found. Not rendering React`
125 )
126 }
127
128 window.___webpackCompilationHash = page.page.webpackCompilationHash
129
130 const Root = () => (
131 <Location>
132 {locationContext => <LocationHandler {...locationContext} />}
133 </Location>
134 )
135
136 const WrappedRoot = apiRunner(
137 `wrapRootElement`,
138 { element: <Root /> },
139 <Root />,
140 ({ result }) => {
141 return { element: result }
142 }
143 ).pop()
144
145 const NewRoot = () => WrappedRoot
146
147 const renderer = apiRunner(
148 `replaceHydrateFunction`,
149 undefined,
150 ReactDOM.hydrate
151 )[0]
152
153 domReady(() => {
154 renderer(
155 <NewRoot />,
156 typeof window !== `undefined`
157 ? document.getElementById(`___gatsby`)
158 : void 0,
159 () => {
160 apiRunner(`onInitialClientRender`)
161 }
162 )
163 })
164 })
165})
166
\No newline at end of file