mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-08-19 21:11:45 +10:00
perf(web): remove homepage video from the LCP path
This commit is contained in:
+2
-2
@@ -16,7 +16,7 @@
|
||||
<link rel="apple-touch-icon" href="/apple-touch-icon-180x180.png" type="image/png" sizes="180x180 any" />
|
||||
<link rel="manifest" href="/manifest.webmanifest" crossorigin="use-credentials" />
|
||||
|
||||
<title>Reactive Resume</title>
|
||||
<title>Reactive Resume — A free and open-source resume builder</title>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Keep #app empty: main.tsx only mounts React when rootElement has no children. -->
|
||||
@@ -56,6 +56,6 @@
|
||||
clip: rect(0 0 0 0);
|
||||
}
|
||||
</style>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
<script type="module" data-cfasync="false" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 66 KiB |
@@ -0,0 +1,48 @@
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import type { PropsWithChildren } from "react";
|
||||
import { render } from "@testing-library/react";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { i18n } from "@lingui/core";
|
||||
import { I18nProvider } from "@lingui/react";
|
||||
|
||||
type LinkProps = PropsWithChildren<{
|
||||
to: string;
|
||||
}>;
|
||||
|
||||
vi.mock("@tanstack/react-router", () => ({
|
||||
Link: ({ children, to, ...rest }: LinkProps) => (
|
||||
<a href={to} {...rest}>
|
||||
{children}
|
||||
</a>
|
||||
),
|
||||
}));
|
||||
|
||||
vi.mock("@/components/animation/comet-card", () => ({
|
||||
CometCard: ({ children }: PropsWithChildren) => <div>{children}</div>,
|
||||
}));
|
||||
|
||||
vi.mock("@/components/animation/spotlight", () => ({
|
||||
Spotlight: () => <div data-testid="spotlight" />,
|
||||
}));
|
||||
|
||||
i18n.loadAndActivate({ locale: "en", messages: {} });
|
||||
|
||||
const { Hero } = await import("./hero");
|
||||
|
||||
describe("Hero", () => {
|
||||
it("shows a poster and waits for user interaction before loading the video", () => {
|
||||
const { container } = render(
|
||||
<I18nProvider i18n={i18n}>
|
||||
<Hero />
|
||||
</I18nProvider>,
|
||||
);
|
||||
const video = container.querySelector("video");
|
||||
|
||||
expect(video).toHaveAttribute("poster", "/videos/timelapse-v1.webp");
|
||||
expect(video).toHaveAttribute("preload", "none");
|
||||
expect(video).toHaveAttribute("src", "/videos/timelapse-v1.mp4");
|
||||
expect(video).toHaveAttribute("controls");
|
||||
expect(video).not.toHaveAttribute("autoplay");
|
||||
});
|
||||
});
|
||||
@@ -29,15 +29,15 @@ export function Hero() {
|
||||
<video
|
||||
loop
|
||||
muted
|
||||
autoPlay
|
||||
controls
|
||||
playsInline
|
||||
preload="none"
|
||||
width={1146}
|
||||
height={720}
|
||||
src="/videos/timelapse.mp4"
|
||||
poster="/videos/timelapse-v1.webp"
|
||||
src="/videos/timelapse-v1.mp4"
|
||||
aria-label={t`Timelapse demonstration of building a resume with Reactive Resume`}
|
||||
// Reserve the intrinsic aspect ratio so the box height is known before the video
|
||||
// metadata loads — otherwise it reflows the centered hero column and causes CLS (~0.10).
|
||||
className="pointer-events-none aspect-[1146/720] w-full rounded-md border object-cover"
|
||||
className="aspect-[1146/720] w-full rounded-md border object-cover"
|
||||
/>
|
||||
|
||||
<div
|
||||
|
||||
@@ -18,7 +18,10 @@ export const Route = createFileRoute("/_home/")({
|
||||
const canonicalUrl = getCanonicalRootUrl(appUrl);
|
||||
|
||||
return {
|
||||
links: [{ rel: "canonical", href: canonicalUrl }],
|
||||
links: [
|
||||
{ rel: "canonical", href: canonicalUrl },
|
||||
{ rel: "preload", href: "/videos/timelapse-v1.webp", as: "image", fetchPriority: "high" },
|
||||
],
|
||||
scripts: [createRootStructuredDataScript(canonicalUrl)],
|
||||
};
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user