Load terminal chart canvas eagerly

This commit is contained in:
2569718930@qq.com
2026-06-01 07:05:08 +08:00
parent 6e00160897
commit d1633331bc
4 changed files with 14 additions and 68 deletions
@@ -1,13 +1,12 @@
"use client"; "use client";
import clsx from "clsx"; import clsx from "clsx";
import dynamic from "next/dynamic";
import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import type { ScanOpportunityRow } from "@/lib/dashboard-types"; import type { ScanOpportunityRow } from "@/lib/dashboard-types";
import { useLatestPatch, useSseResyncVersion } from "@/hooks/use-sse-patches"; import { useLatestPatch, useSseResyncVersion } from "@/hooks/use-sse-patches";
import { Panel } from "@/components/dashboard/scan-terminal/Panel"; import { Panel } from "@/components/dashboard/scan-terminal/Panel";
import { ModelCurvesSummary } from "@/components/dashboard/scan-terminal/ModelCurvesSummary"; import { ModelCurvesSummary } from "@/components/dashboard/scan-terminal/ModelCurvesSummary";
import { TemperatureChartCanvasFallback } from "@/components/dashboard/scan-terminal/TemperatureChartCanvasFallback"; import { TemperatureChartCanvas } from "@/components/dashboard/scan-terminal/TemperatureChartCanvas";
import { TemperatureRunwayDetails } from "@/components/dashboard/scan-terminal/TemperatureRunwayDetails"; import { TemperatureRunwayDetails } from "@/components/dashboard/scan-terminal/TemperatureRunwayDetails";
import { TemperatureStatsBars } from "@/components/dashboard/scan-terminal/TemperatureStatsBars"; import { TemperatureStatsBars } from "@/components/dashboard/scan-terminal/TemperatureStatsBars";
import { rowName } from "@/components/dashboard/scan-terminal/utils"; import { rowName } from "@/components/dashboard/scan-terminal/utils";
@@ -63,32 +62,10 @@ const DEFERRED_DETAIL_LOAD_DELAY_MS = 1_200;
const DEFERRED_DETAIL_LOAD_GROUP_SIZE = 3; const DEFERRED_DETAIL_LOAD_GROUP_SIZE = 3;
const DEFERRED_DETAIL_LOAD_WAVE_STEP_MS = 900; const DEFERRED_DETAIL_LOAD_WAVE_STEP_MS = 900;
let temperatureChartCanvasModulePromise: Promise<
typeof import("@/components/dashboard/scan-terminal/TemperatureChartCanvas")
> | null = null;
function loadTemperatureChartCanvasModule() {
temperatureChartCanvasModulePromise ??= import(
"@/components/dashboard/scan-terminal/TemperatureChartCanvas"
);
return temperatureChartCanvasModulePromise;
}
export function preloadTemperatureChartCanvas() { export function preloadTemperatureChartCanvas() {
return loadTemperatureChartCanvasModule().then(() => undefined, () => undefined); return Promise.resolve();
} }
const TemperatureChartCanvas = dynamic(
() =>
loadTemperatureChartCanvasModule().then(
(mod) => mod.TemperatureChartCanvas,
),
{
ssr: false,
loading: () => <TemperatureChartCanvasFallback />,
},
);
function peakGlowLabel(state: keyof typeof PEAK_GLOW_PANEL_CLASS, isEn: boolean) { function peakGlowLabel(state: keyof typeof PEAK_GLOW_PANEL_CLASS, isEn: boolean) {
if (state === "watch") return isEn ? "Watch" : "关注"; if (state === "watch") return isEn ? "Watch" : "关注";
if (state === "near_peak") return isEn ? "Near peak" : "接近峰值"; if (state === "near_peak") return isEn ? "Near peak" : "接近峰值";
@@ -1,35 +0,0 @@
export function TemperatureChartCanvasFallback({ compact }: { compact?: boolean }) {
const horizontalLines = compact ? 5 : 7;
const verticalLines = compact ? 5 : 8;
const minChartHeight = compact === false ? 220 : 120;
return (
<div
className="relative flex-1 overflow-hidden rounded-sm border border-slate-100 bg-white"
style={{ minHeight: minChartHeight }}
>
<div className="absolute inset-x-3 bottom-7 top-4 rounded-sm border border-slate-100">
{Array.from({ length: horizontalLines }).map((_, index) => (
<span
key={`h-${index}`}
className="absolute left-0 right-0 border-t border-dashed border-sky-100"
style={{ top: `${(index / Math.max(1, horizontalLines - 1)) * 100}%` }}
/>
))}
{Array.from({ length: verticalLines }).map((_, index) => (
<span
key={`v-${index}`}
className="absolute bottom-0 top-0 border-l border-dashed border-sky-100"
style={{ left: `${(index / Math.max(1, verticalLines - 1)) * 100}%` }}
/>
))}
</div>
<div className="absolute inset-0 grid place-items-center">
<div className="flex items-center gap-2 rounded border border-slate-200 bg-white px-3 py-2 text-xs font-semibold text-slate-500 shadow-sm">
<span className="h-3 w-3 animate-spin rounded-full border-2 border-blue-200 border-t-blue-500" />
</div>
</div>
</div>
);
}
@@ -73,9 +73,14 @@ export async function runTests() {
"selected city chart should consume SSE patches and use a 2-minute no-patch fallback", "selected city chart should consume SSE patches and use a 2-minute no-patch fallback",
); );
assert( assert(
chartSource.includes("loadTemperatureChartCanvasModule") && chartSource.includes("preloadTemperatureChartCanvas"),
chartSource.includes("preloadTemperatureChartCanvas"), "terminal chart canvas should expose a preload hook for first-paint optimization",
"terminal chart canvas should expose a preload hook for the dynamic chart chunk", );
assert(
chartSource.includes('from "@/components/dashboard/scan-terminal/TemperatureChartCanvas"') &&
!chartSource.includes("next/dynamic") &&
!chartSource.includes("TemperatureChartCanvasFallback"),
"terminal chart canvas should be loaded with the terminal route instead of showing a second-stage dynamic chunk fallback",
); );
assert( assert(
dashboardSource.includes("preloadTemperatureChartCanvas") && dashboardSource.includes("preloadTemperatureChartCanvas") &&
@@ -97,11 +97,10 @@ export function runTests() {
"terminal dashboard must lazy-load the training analytics tab so Recharts stays out of the default terminal path", "terminal dashboard must lazy-load the training analytics tab so Recharts stays out of the default terminal path",
); );
assert( assert(
chartSource.includes('from "next/dynamic"') && chartSource.includes('import { TemperatureChartCanvas } from "@/components/dashboard/scan-terminal/TemperatureChartCanvas";') &&
chartSource.includes("TemperatureChartCanvasFallback") && !chartSource.includes("TemperatureChartCanvasFallback") &&
chartSource.includes("import(\"@/components/dashboard/scan-terminal/TemperatureChartCanvas\")") && !chartSource.includes("import(\"@/components/dashboard/scan-terminal/TemperatureChartCanvas\")"),
!chartSource.includes('import { TemperatureChartCanvas } from "@/components/dashboard/scan-terminal/TemperatureChartCanvas";'), "terminal temperature charts must load the Recharts canvas with the terminal route so visible cards do not sit behind a second-stage fallback",
"terminal temperature charts must lazy-load the Recharts canvas behind a lightweight fallback",
); );
assert( assert(
chartSource.includes("setLiveTemp(null);") && chartSource.includes("setLiveTemp(null);") &&