Skip to content

Commit 3f19b98

Browse files
authored
Fix(webapp): Dynamically load spline on 404 on page (#2834)
Remove the spline dependency and load it dynamically on the 404 page. Uses a web component with a workaround for React.
1 parent 09460ab commit 3f19b98

File tree

4 files changed

+77
-53
lines changed

4 files changed

+77
-53
lines changed

apps/webapp/app/components/ErrorDisplay.tsx

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
import { HomeIcon } from "@heroicons/react/20/solid";
22
import { isRouteErrorResponse, useRouteError } from "@remix-run/react";
3-
import { motion } from "framer-motion";
43
import { friendlyErrorDisplay } from "~/utils/httpErrors";
54
import { LinkButton } from "./primitives/Buttons";
65
import { Header1 } from "./primitives/Headers";
76
import { Paragraph } from "./primitives/Paragraph";
8-
import Spline from "@splinetool/react-spline";
7+
import { TriggerRotatingLogo } from "./TriggerRotatingLogo";
98
import { type ReactNode } from "react";
109

1110
type ErrorDisplayOptions = {
@@ -57,14 +56,7 @@ export function ErrorDisplay({ title, message, button }: DisplayOptionsProps) {
5756
{button ? button.title : "Go to homepage"}
5857
</LinkButton>
5958
</div>
60-
<motion.div
61-
className="pointer-events-none absolute inset-0 overflow-hidden"
62-
initial={{ opacity: 0 }}
63-
animate={{ opacity: 1 }}
64-
transition={{ delay: 0.5, duration: 2, ease: "easeOut" }}
65-
>
66-
<Spline scene="https://prod.spline.design/wRly8TZN-e0Twb8W/scene.splinecode" />
67-
</motion.div>
59+
<TriggerRotatingLogo />
6860
</div>
6961
);
7062
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import { motion } from "framer-motion";
2+
import { useEffect, useState } from "react";
3+
4+
declare global {
5+
namespace JSX {
6+
interface IntrinsicElements {
7+
"spline-viewer": React.DetailedHTMLProps<
8+
React.HTMLAttributes<HTMLElement> & {
9+
url?: string;
10+
"loading-anim-type"?: string;
11+
},
12+
HTMLElement
13+
>;
14+
}
15+
}
16+
17+
interface Window {
18+
__splineLoader?: Promise<void>;
19+
}
20+
}
21+
22+
export function TriggerRotatingLogo() {
23+
const [isSplineReady, setIsSplineReady] = useState(false);
24+
25+
useEffect(() => {
26+
// Already registered from a previous render
27+
if (customElements.get("spline-viewer")) {
28+
setIsSplineReady(true);
29+
return;
30+
}
31+
32+
// Another mount already started loading - share the same promise
33+
if (window.__splineLoader) {
34+
window.__splineLoader.then(() => setIsSplineReady(true)).catch(() => setIsSplineReady(false));
35+
return;
36+
}
37+
38+
// First mount: create script and shared loader promise
39+
const script = document.createElement("script");
40+
script.type = "module";
41+
// Version pinned; SRI hash omitted as unpkg doesn't guarantee hash stability across deploys
42+
script.src = "https://unpkg.com/@splinetool/[email protected]/build/spline-viewer.js";
43+
44+
window.__splineLoader = new Promise<void>((resolve, reject) => {
45+
script.onload = () => resolve();
46+
script.onerror = () => reject();
47+
});
48+
49+
window.__splineLoader.then(() => setIsSplineReady(true)).catch(() => setIsSplineReady(false));
50+
51+
document.head.appendChild(script);
52+
53+
// Intentionally no cleanup: once the custom element is registered globally,
54+
// removing the script would break re-mounts while providing no benefit
55+
}, []);
56+
57+
if (!isSplineReady) {
58+
return null;
59+
}
60+
61+
return (
62+
<motion.div
63+
className="pointer-events-none absolute inset-0 overflow-hidden"
64+
initial={{ opacity: 0 }}
65+
animate={{ opacity: 1 }}
66+
transition={{ delay: 0.5, duration: 2, ease: "easeOut" }}
67+
>
68+
<spline-viewer
69+
loading-anim-type="spinner-small-light"
70+
url="https://prod.spline.design/wRly8TZN-e0Twb8W/scene.splinecode"
71+
style={{ width: "100%", height: "100%" }}
72+
/>
73+
</motion.div>
74+
);
75+
}

apps/webapp/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,6 @@
109109
"@sentry/remix": "9.46.0",
110110
"@slack/web-api": "7.9.1",
111111
"@socket.io/redis-adapter": "^8.3.0",
112-
"@splinetool/react-spline": "^2.2.6",
113112
"@tabler/icons-react": "^2.39.0",
114113
"@tailwindcss/container-queries": "^0.1.1",
115114
"@tanstack/react-virtual": "^3.0.4",

pnpm-lock.yaml

Lines changed: 0 additions & 42 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)