feat: 首页 Go SSR 与 React hydrate 同构,消壳层与帖行闪动
补齐侧栏/右栏图标与徽章、鉴权种子、StaticFeedList,并修正嵌套 a 与标题徽章对齐。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,22 +1,89 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
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 { ensureColdBootReady, isMainLayoutPath } from './utils/prefetchRoute';
|
||||
|
||||
applyTheme(getStoredTheme());
|
||||
consumeHomeBoot();
|
||||
|
||||
async function boot() {
|
||||
const path = `${window.location.pathname}${window.location.search}`;
|
||||
// 前台:齐套前不挂载;完成后一次 createRoot
|
||||
if (isMainLayoutPath(window.location.pathname)) {
|
||||
await ensureColdBootReady(path);
|
||||
}
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||
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>,
|
||||
</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();
|
||||
|
||||
Reference in New Issue
Block a user