UNPKG

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