-
Notifications
You must be signed in to change notification settings - Fork 212
Expand file tree
/
Copy pathmain.jsx
More file actions
138 lines (127 loc) · 5.22 KB
/
main.jsx
File metadata and controls
138 lines (127 loc) · 5.22 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/*
* Copyright (c) 2021, salesforce.com, inc.
* All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/
/* global __webpack_require__ */
import React, {useRef} from 'react'
import {hydrateRoot} from 'react-dom/client'
import {BrowserRouter as Router} from 'react-router-dom'
import {ServerContext, CorrelationIdProvider} from '../universal/contexts'
import App from '../universal/components/_app'
import {getAppConfig} from '../universal/compatibility'
import Switch from '../universal/components/switch'
import {getRoutes, routeComponent} from '../universal/components/route-component'
import {loadableReady} from '@loadable/component'
import {uuidv4} from '../../utils/uuidv4.client'
import PropTypes from 'prop-types'
import logger from '../../utils/logger-instance'
import {getRouterBasePath} from '../universal/utils'
/* istanbul ignore next */
export const registerServiceWorker = (url) => {
return Promise.resolve().then(() => {
if ('serviceWorker' in navigator) {
return Promise.resolve()
.then(() => new Promise((resolve) => window.addEventListener('load', resolve)))
.then(() => navigator.serviceWorker.register(url))
.then((registration) =>
logger.info(
`ServiceWorker registration successful with scope: ${registration.scope}`,
{namespace: 'registerServiceWorker'}
)
)
.catch((err) =>
logger.error('ServiceWorker registration failed', {
namespace: 'registerServiceWorker',
additionalProperties: {error: err}
})
)
}
})
}
export const OuterApp = ({routes, error, WrappedApp, locals, onHydrate}) => {
const AppConfig = getAppConfig()
const isInitialPageRef = useRef(true)
const routerBasename = getRouterBasePath() || undefined
return (
<ServerContext.Provider value={{}}>
<Router ref={onHydrate} basename={routerBasename}>
<CorrelationIdProvider
correlationId={() => {
// If we are hydrating an error page use the server correlation id.
if (isInitialPageRef.current && window.__ERROR__) {
isInitialPageRef.current = false
return window.__INITIAL_CORRELATION_ID__
}
return uuidv4()
}}
>
<AppConfig locals={locals}>
<Switch
error={error}
appState={window.__PRELOADED_STATE__}
routes={routes}
App={WrappedApp}
/>
</AppConfig>
</CorrelationIdProvider>
</Router>
</ServerContext.Provider>
)
}
OuterApp.propTypes = {
routes: PropTypes.array.isRequired,
error: PropTypes.object,
WrappedApp: PropTypes.func.isRequired,
locals: PropTypes.object,
onHydrate: PropTypes.func
}
/* istanbul ignore next */
export const start = () => {
const AppConfig = getAppConfig()
const rootEl = document.getElementsByClassName('react-target')[0]
const data = JSON.parse(document.getElementById('mobify-data').innerHTML)
// Set all globals sent from the server on the window object.
Object.entries(data).forEach(([key, value]) => {
window[key] = value
})
// Tell webpack how to find javascript files
Object.defineProperty(__webpack_require__, 'p', {
get: () => window.Progressive.buildOrigin
})
// On the browser we don't have request.locals, so we just provide an empty
// object that exists for the lifetime of the app. AppConfig components can use
// this to set up, eg. Redux stores.
const locals = {}
// AppConfig.restore *must* come before getRoutes()
AppConfig.restore(locals, window.__PRELOADED_STATE__.__STATE_MANAGEMENT_LIBRARY)
// We need to tell the routeComponent HOC when the app is hydrating in order to
// prevent pages from re-fetching data on the first client-side render. The
// reason we do this is that we expect a render to have taken place
// on the server already. That server-side render already called getProps()
// and froze the application state as a JSON blob on the page.
//
// This is VERY fiddly – don't go crazy with window.__HYDRATING__. You have
// been warned.
window.__HYDRATING__ = true
const props = {
error: window.__ERROR__,
locals: locals,
routes: getRoutes(locals),
WrappedApp: routeComponent(App, false, locals)
}
return Promise.resolve()
.then(() => new Promise((resolve) => loadableReady(resolve)))
.then(() => {
hydrateRoot(
rootEl,
<OuterApp
{...props}
onHydrate={() => {
window.__HYDRATING__ = false
}}
/>
)
})
}