Spaces:
Running
Running
Commit ·
ba02f4d
1
Parent(s): 31167c5
Fix OOM build: load Plotly from CDN instead of npm bundle
Browse filesThe plotly.js-basic-dist npm package (~1.4MB gzipped) caused the
Docker build to OOM on the HF Space cpu-basic tier. Replace it with
a lightweight CDN loader that fetches plotly-basic at runtime. This
removes the heavy webpack processing entirely and drops the JS bundle
from 1.7MB to 250KB.
frontend/package.json
CHANGED
|
@@ -20,10 +20,8 @@
|
|
| 20 |
"cors": "^2.8.5",
|
| 21 |
"express": "^4.18.2",
|
| 22 |
"http-proxy-middleware": "^2.0.6",
|
| 23 |
-
"plotly.js-basic-dist": "^3.4.0",
|
| 24 |
"react": "^18.3.1",
|
| 25 |
"react-dom": "^18.3.1",
|
| 26 |
-
"react-plotly.js": "^2.6.0",
|
| 27 |
"react-router-dom": "^6.28.0",
|
| 28 |
"react-scripts": "5.0.1",
|
| 29 |
"serve-static": "^1.15.0",
|
|
|
|
| 20 |
"cors": "^2.8.5",
|
| 21 |
"express": "^4.18.2",
|
| 22 |
"http-proxy-middleware": "^2.0.6",
|
|
|
|
| 23 |
"react": "^18.3.1",
|
| 24 |
"react-dom": "^18.3.1",
|
|
|
|
| 25 |
"react-router-dom": "^6.28.0",
|
| 26 |
"react-scripts": "5.0.1",
|
| 27 |
"serve-static": "^1.15.0",
|
frontend/src/pages/LeaderboardPage/components/Leaderboard/components/Chart/Chart.js
CHANGED
|
@@ -1,12 +1,80 @@
|
|
| 1 |
-
import React, { useState,
|
| 2 |
import { Box, Typography, Chip, CircularProgress } from "@mui/material";
|
| 3 |
import { useTheme } from "@mui/material/styles";
|
| 4 |
import useChartData from "./useChartData";
|
| 5 |
import { DATASET_OPTIONS, REFERENCE_LINE_COLOR } from "../../constants/chartDefaults";
|
| 6 |
|
| 7 |
-
const
|
| 8 |
-
|
| 9 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
|
| 11 |
const Chart = ({ filteredData, scoreDisplay }) => {
|
| 12 |
const theme = useTheme();
|
|
@@ -124,32 +192,16 @@ const Chart = ({ filteredData, scoreDisplay }) => {
|
|
| 124 |
</Box>
|
| 125 |
|
| 126 |
{/* Plot */}
|
| 127 |
-
<
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
<CircularProgress size={28} />
|
| 138 |
-
</Box>
|
| 139 |
-
}
|
| 140 |
-
>
|
| 141 |
-
<Plot
|
| 142 |
-
data={traces}
|
| 143 |
-
layout={themedLayout}
|
| 144 |
-
config={{
|
| 145 |
-
responsive: true,
|
| 146 |
-
displayModeBar: false,
|
| 147 |
-
staticPlot: false,
|
| 148 |
-
}}
|
| 149 |
-
style={{ width: "100%" }}
|
| 150 |
-
useResizeHandler
|
| 151 |
-
/>
|
| 152 |
-
</Suspense>
|
| 153 |
|
| 154 |
{/* Reference line legend */}
|
| 155 |
<Box
|
|
|
|
| 1 |
+
import React, { useState, useEffect, useRef, useCallback } from "react";
|
| 2 |
import { Box, Typography, Chip, CircularProgress } from "@mui/material";
|
| 3 |
import { useTheme } from "@mui/material/styles";
|
| 4 |
import useChartData from "./useChartData";
|
| 5 |
import { DATASET_OPTIONS, REFERENCE_LINE_COLOR } from "../../constants/chartDefaults";
|
| 6 |
|
| 7 |
+
const PLOTLY_CDN = "https://cdn.plot.ly/plotly-basic-2.35.2.min.js";
|
| 8 |
+
|
| 9 |
+
// Load Plotly from CDN once, return a promise
|
| 10 |
+
let plotlyPromise = null;
|
| 11 |
+
const loadPlotly = () => {
|
| 12 |
+
if (window.Plotly) return Promise.resolve(window.Plotly);
|
| 13 |
+
if (plotlyPromise) return plotlyPromise;
|
| 14 |
+
plotlyPromise = new Promise((resolve, reject) => {
|
| 15 |
+
const script = document.createElement("script");
|
| 16 |
+
script.src = PLOTLY_CDN;
|
| 17 |
+
script.async = true;
|
| 18 |
+
script.onload = () => resolve(window.Plotly);
|
| 19 |
+
script.onerror = () => reject(new Error("Failed to load Plotly"));
|
| 20 |
+
document.head.appendChild(script);
|
| 21 |
+
});
|
| 22 |
+
return plotlyPromise;
|
| 23 |
+
};
|
| 24 |
+
|
| 25 |
+
const PlotlyChart = ({ data, layout, config, style }) => {
|
| 26 |
+
const containerRef = useRef(null);
|
| 27 |
+
const [Plotly, setPlotly] = useState(window.Plotly || null);
|
| 28 |
+
const [loading, setLoading] = useState(!window.Plotly);
|
| 29 |
+
|
| 30 |
+
useEffect(() => {
|
| 31 |
+
if (!Plotly) {
|
| 32 |
+
loadPlotly()
|
| 33 |
+
.then((P) => {
|
| 34 |
+
setPlotly(P);
|
| 35 |
+
setLoading(false);
|
| 36 |
+
})
|
| 37 |
+
.catch(() => setLoading(false));
|
| 38 |
+
}
|
| 39 |
+
}, [Plotly]);
|
| 40 |
+
|
| 41 |
+
const draw = useCallback(() => {
|
| 42 |
+
if (Plotly && containerRef.current && data?.length) {
|
| 43 |
+
Plotly.react(containerRef.current, data, layout, config);
|
| 44 |
+
}
|
| 45 |
+
}, [Plotly, data, layout, config]);
|
| 46 |
+
|
| 47 |
+
useEffect(() => {
|
| 48 |
+
draw();
|
| 49 |
+
}, [draw]);
|
| 50 |
+
|
| 51 |
+
// Resize handler
|
| 52 |
+
useEffect(() => {
|
| 53 |
+
if (!Plotly || !containerRef.current) return;
|
| 54 |
+
const ro = new ResizeObserver(() => {
|
| 55 |
+
if (containerRef.current) Plotly.Plots.resize(containerRef.current);
|
| 56 |
+
});
|
| 57 |
+
ro.observe(containerRef.current);
|
| 58 |
+
return () => ro.disconnect();
|
| 59 |
+
}, [Plotly]);
|
| 60 |
+
|
| 61 |
+
if (loading) {
|
| 62 |
+
return (
|
| 63 |
+
<Box
|
| 64 |
+
sx={{
|
| 65 |
+
display: "flex",
|
| 66 |
+
justifyContent: "center",
|
| 67 |
+
alignItems: "center",
|
| 68 |
+
minHeight: 400,
|
| 69 |
+
}}
|
| 70 |
+
>
|
| 71 |
+
<CircularProgress size={28} />
|
| 72 |
+
</Box>
|
| 73 |
+
);
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
return <div ref={containerRef} style={style} />;
|
| 77 |
+
};
|
| 78 |
|
| 79 |
const Chart = ({ filteredData, scoreDisplay }) => {
|
| 80 |
const theme = useTheme();
|
|
|
|
| 192 |
</Box>
|
| 193 |
|
| 194 |
{/* Plot */}
|
| 195 |
+
<PlotlyChart
|
| 196 |
+
data={traces}
|
| 197 |
+
layout={themedLayout}
|
| 198 |
+
config={{
|
| 199 |
+
responsive: true,
|
| 200 |
+
displayModeBar: false,
|
| 201 |
+
staticPlot: false,
|
| 202 |
+
}}
|
| 203 |
+
style={{ width: "100%" }}
|
| 204 |
+
/>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 205 |
|
| 206 |
{/* Reference line legend */}
|
| 207 |
<Box
|