This repository was archived by the owner on May 13, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 923
Expand file tree
/
Copy pathindex.js
More file actions
164 lines (147 loc) · 5.74 KB
/
index.js
File metadata and controls
164 lines (147 loc) · 5.74 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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
/**
* This is the main entrypoint file for the application.
*
* When loaded in the client side, the application is rendered in the
* #root element.
*
* When the bundle created from this file is imported in the server
* side, the exported `renderApp` function can be used for server side
* rendering.
*
* Note that this file is required for the build process.
*/
// React 16 depends on the collection types Map and Set, as well as requestAnimationFrame.
// https://reactjs.org/docs/javascript-environment-requirements.html
import 'core-js/features/map';
import 'core-js/features/set';
import 'raf/polyfill';
import React from 'react';
import ReactDOM from 'react-dom';
import { loadableReady } from '@loadable/component';
import { createInstance, types as sdkTypes } from './util/sdkLoader';
import { ClientApp, renderApp } from './app';
import configureStore from './store';
import { matchPathname } from './util/routes';
import * as sample from './util/sample';
import * as apiUtils from './util/api';
import config from './config';
import { authInfo } from './ducks/Auth.duck';
import { fetchAppAssets } from './ducks/hostedAssets.duck';
import { fetchCurrentUser } from './ducks/user.duck';
import routeConfiguration from './routeConfiguration';
import * as log from './util/log';
import { LoggingAnalyticsHandler, GoogleAnalyticsHandler } from './analytics/handlers';
import './styles/marketplaceDefaults.css';
const render = (store, shouldHydrate) => {
// If the server already loaded the auth information, render the app
// immediately. Otherwise wait for the flag to be loaded and render
// when auth information is present.
const state = store.getState();
const cdnAssetsVersion = state.hostedAssets.version;
const authInfoLoaded = state.Auth.authInfoLoaded;
const info = authInfoLoaded ? Promise.resolve({}) : store.dispatch(authInfo());
info
.then(() => {
store.dispatch(fetchCurrentUser());
// Ensure that Loadable Components is ready
// and fetch hosted assets in parallel before initializing the ClientApp
return Promise.all([
loadableReady(),
store.dispatch(fetchAppAssets(config.appCdnAssets, cdnAssetsVersion)),
]);
})
.then(([_, fetchedAssets]) => {
const translations = fetchedAssets?.translations?.data || {};
if (shouldHydrate) {
ReactDOM.hydrate(
<ClientApp store={store} hostedTranslations={translations} />,
document.getElementById('root')
);
} else {
ReactDOM.render(
<ClientApp store={store} hostedTranslations={translations} />,
document.getElementById('root')
);
}
})
.catch(e => {
log.error(e, 'browser-side-render-failed');
});
};
const setupAnalyticsHandlers = () => {
let handlers = [];
// Log analytics page views and events in dev mode
if (config.dev) {
handlers.push(new LoggingAnalyticsHandler());
}
// Add Google Analytics 4 (GA4) handler if tracker ID is found
if (process.env.REACT_APP_GOOGLE_ANALYTICS_ID) {
if (window?.gtag) {
handlers.push(new GoogleAnalyticsHandler(window.gtag));
} else {
// Some adblockers (e.g. Ghostery) might block the Google Analytics integration.
console.warn(
'Google Analytics (window.gtag) is not available. It might be that your adblocker is blocking it.'
);
}
if (process.env.REACT_APP_GOOGLE_ANALYTICS_ID.indexOf('G-') !== 0) {
console.warn(
'Google Analytics 4 (GA4) should have measurement id that starts with "G-" prefix'
);
}
}
return handlers;
};
// If we're in a browser already, render the client application.
if (typeof window !== 'undefined') {
// set up logger with Sentry DSN client key and environment
log.setup();
const baseUrl = config.sdk.baseUrl ? { baseUrl: config.sdk.baseUrl } : {};
const assetCdnBaseUrl = config.sdk.assetCdnBaseUrl
? { assetCdnBaseUrl: config.sdk.assetCdnBaseUrl }
: {};
// eslint-disable-next-line no-underscore-dangle
const preloadedState = window.__PRELOADED_STATE__ || '{}';
const initialState = JSON.parse(preloadedState, sdkTypes.reviver);
const sdk = createInstance({
transitVerbose: config.sdk.transitVerbose,
clientId: config.sdk.clientId,
secure: config.usingSSL,
typeHandlers: apiUtils.typeHandlers,
...baseUrl,
...assetCdnBaseUrl,
});
const analyticsHandlers = setupAnalyticsHandlers();
const store = configureStore(initialState, sdk, analyticsHandlers);
require('./util/polyfills');
render(store, !!window.__PRELOADED_STATE__);
if (config.dev) {
// Expose stuff for the browser REPL
window.app = {
config,
sdk,
sdkTypes,
store,
sample,
routeConfiguration: routeConfiguration(),
};
}
}
// Show warning if CSP is not enabled
const CSP = process.env.REACT_APP_CSP;
const cspEnabled = CSP === 'block' || CSP === 'report';
if (CSP === 'report' && process.env.REACT_APP_ENV === 'production') {
console.warn(
'Your production environment should use CSP with "block" mode. Read more from: https://www.sharetribe.com/docs/ftw-security/how-to-set-up-csp-for-ftw/'
);
} else if (!cspEnabled) {
console.warn(
"CSP is currently not enabled! You should add an environment variable REACT_APP_CSP with the value 'report' or 'block'. Read more from: https://www.sharetribe.com/docs/ftw-security/how-to-set-up-csp-for-ftw/"
);
}
// Export the function for server side rendering.
export default renderApp;
// exporting matchPathname and configureStore for server side rendering.
// matchPathname helps to figure out which route is called and if it has preloading needs
// configureStore is used for creating initial store state for Redux after preloading
export { matchPathname, configureStore, routeConfiguration, config, fetchAppAssets };