避免 Logo/下拉刷新仍跑旧 index.js,以及站内消息预取失败弹出英文 toast。 Co-authored-by: Cursor <cursoragent@cursor.com>
97 lines
2.4 KiB
TypeScript
97 lines
2.4 KiB
TypeScript
import React from 'react';
|
||
import { hydrateRoot, createRoot } from 'react-dom/client';
|
||
import { applyTheme, getStoredTheme } from './utils/theme';
|
||
import App from './App';
|
||
import { consumeHomeBoot } from './utils/homeBoot';
|
||
import { beginHomeHydrate } from './utils/homeHydrate';
|
||
import { reloadForStaleChunk } from './utils/chunkLoad';
|
||
import { ensureColdBootReady, isMainLayoutPath } from './utils/prefetchRoute';
|
||
|
||
applyTheme(getStoredTheme());
|
||
consumeHomeBoot();
|
||
|
||
// Vite modulepreload / 动态 import 失败(发版后旧 hashed URL 404)
|
||
window.addEventListener('vite:preloadError', (event) => {
|
||
event.preventDefault();
|
||
reloadForStaleChunk();
|
||
});
|
||
|
||
function hasSSRHome(): boolean {
|
||
return !!document.querySelector('#root .ssr-home');
|
||
}
|
||
|
||
function waitForStylesheets(): Promise<void> {
|
||
const links = Array.from(document.querySelectorAll('link[rel="stylesheet"]'));
|
||
if (links.length === 0) return Promise.resolve();
|
||
return Promise.all(
|
||
links.map(
|
||
(node) =>
|
||
new Promise<void>((resolve) => {
|
||
const link = node as HTMLLinkElement;
|
||
try {
|
||
if (link.sheet) {
|
||
resolve();
|
||
return;
|
||
}
|
||
} catch {
|
||
/* cross-origin */
|
||
}
|
||
const finish = () => resolve();
|
||
link.addEventListener('load', finish, { once: true });
|
||
link.addEventListener('error', finish, { once: true });
|
||
}),
|
||
),
|
||
).then(() => undefined);
|
||
}
|
||
|
||
function renderApp() {
|
||
return (
|
||
<React.StrictMode>
|
||
<App />
|
||
</React.StrictMode>
|
||
);
|
||
}
|
||
|
||
function mountCreateRoot(el: HTMLElement) {
|
||
createRoot(el).render(renderApp());
|
||
}
|
||
|
||
/** 有 SSR 正文:hydrate 接管同一 DOM;失败则回退 createRoot */
|
||
function mountHydrateHome(el: HTMLElement) {
|
||
beginHomeHydrate();
|
||
try {
|
||
hydrateRoot(el, renderApp());
|
||
} catch (err) {
|
||
console.warn('[j13] hydrateRoot 失败,回退 createRoot', err);
|
||
el.innerHTML = '';
|
||
mountCreateRoot(el);
|
||
}
|
||
}
|
||
|
||
async function boot() {
|
||
const path = `${window.location.pathname}${window.location.search}`;
|
||
const ssr = hasSSRHome();
|
||
|
||
await waitForStylesheets();
|
||
try {
|
||
if (document.fonts?.ready) await document.fonts.ready;
|
||
} catch {
|
||
/* ignore */
|
||
}
|
||
|
||
if (isMainLayoutPath(window.location.pathname)) {
|
||
await ensureColdBootReady(path);
|
||
}
|
||
|
||
const root = document.getElementById('root');
|
||
if (!root) return;
|
||
|
||
if (ssr) {
|
||
mountHydrateHome(root);
|
||
} else {
|
||
mountCreateRoot(root);
|
||
}
|
||
}
|
||
|
||
void boot();
|