DEV Community

Cover image for Keeping a heavy, animated landing page fast in Next.js
Daniel Pertu
Daniel Pertu

Posted on

Keeping a heavy, animated landing page fast in Next.js

My marketing homepage has interactive game demos, scroll animations, and a lot of moving parts. All of that kills first load if you ship it in one bundle. Here's how I kept it fast without cutting the fun stuff.

Server-render the hero, lazy-load the rest. The only thing that needs to be fast is what's above the fold. I keep the hero server-rendered and dependency-light so the Largest Contentful Paint lands early, then defer everything below it.

next/dynamic for the expensive, client-only pieces. The interactive demos are pure client components — no reason to server-render a canvas game:

const GameDemo = dynamic(() => import("./GameDemo"), {
  ssr: false,
  loading: () => <DemoSkeleton />,
});
Enter fullscreen mode Exit fullscreen mode

Only mount a demo when it's about to be seen. Dynamic import splits the code, but I don't even want to fetch that chunk until the user scrolls near it. An Intersection Observer gates the mount:

const [show, setShow] = useState(false);
useEffect(() => {
  const io = new IntersectionObserver(([e]) => e.isIntersecting && setShow(true), {
    rootMargin: "200px", // start loading just before it enters view
  });
  ref.current && io.observe(ref.current);
  return () => io.disconnect();
}, []);
Enter fullscreen mode Exit fullscreen mode

Measure, don't guess. @next/bundle-analyzer showed me a charting lib and an animation lib were most of my initial weight — both trivially deferrable once I stopped importing them at the top level. Pair that with next/image for the demo thumbnails and next/font to kill layout-shift from web fonts, and the "everything happens at once" homepage loads like a static one.

The principle: the browser should pay for a feature only when the user is about to reach it. Split by route and by viewport.

This is the actual homepage for CogniPrep — https://cogniprep.app if you want to poke at the load behaviour.

Top comments (0)