Repository navigation
Expand file tree
/
Copy pathmain.tsx
More file actions
91 lines (84 loc) · 3.8 KB
/
Copy pathmain.tsx
File metadata and controls
91 lines (84 loc) · 3.8 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
import { createRoot } from "react-dom/client";
import { flushSync } from "react-dom";
import App from "./App.tsx";
import { WebTelemetry } from "./components/WebTelemetry";
import { appLanguageReady } from "./i18n";
import "@fontsource-variable/nunito";
import "@fontsource-variable/fredoka";
import "@fontsource-variable/jetbrains-mono";
import "./index.css";
import { registerServiceWorker } from "./register-service-worker";
import { installStaleChunkReload } from "./lib/reload-stale-chunk";
import { initializeObservability } from "./lib/observability";
import { preloadStartupRoute } from "./lib/route-modules";
import { legacyCallbackPath } from "./lib/auth-callback";
import { choosePathLanguage, chooseUrlLanguage, searchWithoutLanguage } from "./lib/url-language";
const initializeTelemetry = (): void => {
const run = (): void => { void initializeObservability(); };
if (typeof window.requestIdleCallback === "function") {
window.requestIdleCallback(run);
} else {
window.setTimeout(run, 0);
}
};
const LANGUAGE_WAIT_MS = 3_000;
/** The route whose HTML the build prerendered into #root, when it is the page being opened. */
function prerenderedRoute(container: HTMLElement): string | undefined {
const route = container.dataset.prerendered;
return route === "*" || route === window.location.pathname ? route : undefined;
}
installStaleChunkReload();
export function mountApp(): void {
// Sign-in links already in inboxes return to / or /app. Move them onto the
// callback route before the first render, so the prerendered landing page
// is replaced and AuthProvider exchanges the code there.
const callbackPath = legacyCallbackPath(window.location);
if (callbackPath) window.history.replaceState(window.history.state, "", callbackPath);
// A ?lang= link picks the language before the first render waits for it, and
// leaves the address so a later switcher choice survives a reload.
const { pathname, search, hash } = window.location;
if (chooseUrlLanguage(search)) {
window.history.replaceState(window.history.state, "", `${pathname}${searchWithoutLanguage(search)}${hash}`);
}
// /hu and /es pages were prerendered in their language; the first render matches it.
choosePathLanguage(pathname);
const container = document.getElementById("root")!;
const root = createRoot(container);
const app = (
<>
<App />
<WebTelemetry />
</>
);
const prerendered = prerenderedRoute(container);
const page = preloadStartupRoute(prerendered === "*" ? "*" : window.location.pathname);
// The first render waits for the chosen language's strings, so a Spanish or
// Hungarian visitor never sees the English text first. A stalled request
// must not hold the startup screen: after a few seconds English renders and
// the language switches when its strings arrive.
const languageReady = Promise.race([
appLanguageReady(),
new Promise<void>((resolve) => { window.setTimeout(resolve, LANGUAGE_WAIT_MS); }),
]);
if (prerendered) {
// The prerendered page stays on screen until its module is loaded, then one
// synchronous render replaces it with the same page. A failed load renders
// anyway and the route's own lazy load reports the error.
const render = (): void => {
flushSync(() => root.render(app));
delete container.dataset.prerendered;
};
void Promise.all([page, languageReady]).then(render, render);
} else {
// HTML prerendered for another route (an offline copy, say) is replaced like the startup shell.
delete container.dataset.prerendered;
const render = (): void => root.render(app);
void languageReady.then(render, render);
}
registerServiceWorker();
if (document.readyState === "complete") {
initializeTelemetry();
} else {
window.addEventListener("load", initializeTelemetry, { once: true });
}
}