<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Christopher Bailey</title>
    <description>The latest articles on DEV Community by Christopher Bailey (@oceanwaveweb).</description>
    <link>https://dev.to/oceanwaveweb</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4008520%2F94e7302b-ad3f-4cc1-a4e0-030312441739.jpeg</url>
      <title>DEV Community: Christopher Bailey</title>
      <link>https://dev.to/oceanwaveweb</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/oceanwaveweb"/>
    <language>en</language>
    <item>
      <title>How to Hit a 100 PageSpeed Score on a Real Client Website (Not Just a Demo)</title>
      <dc:creator>Christopher Bailey</dc:creator>
      <pubDate>Mon, 29 Jun 2026 17:02:39 +0000</pubDate>
      <link>https://dev.to/oceanwaveweb/how-to-hit-a-100-pagespeed-score-on-a-real-client-website-not-just-a-demo-4pf1</link>
      <guid>https://dev.to/oceanwaveweb/how-to-hit-a-100-pagespeed-score-on-a-real-client-website-not-just-a-demo-4pf1</guid>
      <description>&lt;p&gt;Anyone can score 100 on a blank HTML page. But what about a real business site — with images, custom fonts, animations, third-party scripts, and a client who wants a hero video? That's where most agencies tap out.&lt;/p&gt;

&lt;p&gt;At OceanWave Web, we build hand-coded Next.js websites for small businesses, and a perfect (or near-perfect) PageSpeed score isn't a bonus — it's the baseline. Here's exactly how we do it, with the real techniques we use on every project.&lt;/p&gt;

&lt;p&gt;Why PageSpeed Actually Matters (Beyond the Bragging Rights)&lt;/p&gt;

&lt;p&gt;Before the how, let's quickly address the why:&lt;/p&gt;

&lt;p&gt;SEO: Google uses Core Web Vitals as a ranking signal. A slow site is a penalized site.&lt;br&gt;
Conversions: A 1-second delay in load time can reduce conversions by up to 7%.&lt;br&gt;
User trust: A fast site feels professional. A slow one, even a beautiful one, feels broken.&lt;/p&gt;

&lt;p&gt;For small businesses competing against big brands, performance is a real differentiator.&lt;/p&gt;

&lt;p&gt;The Stack We Use&lt;/p&gt;

&lt;p&gt;We build on Next.js (App Router), deployed on Vercel, with hand-written CSS or Tailwind. No page builders, no WordPress, no theme bloat. This matters because half the battle is starting with clean code.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Images: The Biggest Win&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Images are almost always the #1 culprit behind slow scores. Here's the full playbook:&lt;/p&gt;

&lt;p&gt;Use next/image for Everything&lt;/p&gt;

&lt;p&gt;Next.js's &lt;a href="" class="article-body-image-wrapper"&gt;&lt;img&gt;&lt;/a&gt; component handles lazy loading, responsive sizing, and WebP/AVIF conversion automatically.&lt;/p&gt;

&lt;p&gt;jsximport Image from 'next/image'&lt;/p&gt;

&lt;p&gt;
  src="/hero.jpg"&lt;br&gt;
  alt="Hero image"&lt;br&gt;
  width={1200}&lt;br&gt;
  height={630}&lt;br&gt;
  priority // Only for above-the-fold images&lt;br&gt;
  sizes="(max-width: 768px) 100vw, 1200px"&lt;br&gt;
/&amp;gt;&lt;/p&gt;

&lt;p&gt;Use priority only on your LCP (Largest Contentful Paint) image — typically the hero. Adding it everywhere defeats the purpose.&lt;/p&gt;

&lt;p&gt;Compress Before You Even Upload&lt;/p&gt;

&lt;p&gt;Even WebP has limits. We run all client assets through Squoosh or sharp before they ever hit the repo. Target:&lt;/p&gt;

&lt;p&gt;Hero images: under 200KB&lt;br&gt;
Card/thumbnail images: under 80KB&lt;br&gt;
Icons: use SVG, not PNG&lt;/p&gt;

&lt;p&gt;Avoid Layout Shift with Explicit Dimensions&lt;/p&gt;

&lt;p&gt;Always set width and height on every image. This lets the browser reserve space before the image loads, avoiding Cumulative Layout Shift (CLS).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fonts: The Silent Killer&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Google Fonts are convenient but expensive. Here's how we handle typography without paying the performance tax:&lt;/p&gt;

&lt;p&gt;Self-Host Your Fonts&lt;/p&gt;

&lt;p&gt;js// app/layout.js&lt;br&gt;
import localFont from 'next/font/local'&lt;/p&gt;

&lt;p&gt;const myFont = localFont({&lt;br&gt;
  src: './fonts/MyFont.woff2',&lt;br&gt;
  display: 'swap',&lt;br&gt;
  variable: '--font-my-font',&lt;br&gt;
})&lt;/p&gt;

&lt;p&gt;With next/font, fonts are:&lt;/p&gt;

&lt;p&gt;Self-hosted at build time (no external request)&lt;br&gt;
Preloaded automatically&lt;br&gt;
Injected with font-display: swap to prevent invisible text&lt;/p&gt;

&lt;p&gt;Limit Font Weights&lt;/p&gt;

&lt;p&gt;Every font weight is an extra file. If you only need 400 and 700, don't load 300, 500, and 900 too. Audit your design and cut ruthlessly.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;JavaScript: Ship Less, Load Smarter&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Code-Split with Dynamic Imports&lt;/p&gt;

&lt;p&gt;Don't load components the user hasn't seen yet.&lt;/p&gt;

&lt;p&gt;jsximport dynamic from 'next/dynamic'&lt;/p&gt;

&lt;p&gt;const HeavyModal = dynamic(() =&amp;gt; import('@/components/HeavyModal'), {&lt;br&gt;
  loading: () =&amp;gt; &lt;/p&gt;
&lt;p&gt;Loading...&lt;/p&gt;,&lt;br&gt;
})

&lt;p&gt;This is especially useful for modals, chat widgets, map embeds, and anything "below the fold."&lt;/p&gt;

&lt;p&gt;Audit Your Bundle&lt;/p&gt;

&lt;p&gt;Run next build and check the output. Better yet, use bundlephobia.com before installing any npm package. A single unoptimized dependency can blow up your score.&lt;/p&gt;

&lt;p&gt;Defer Third-Party Scripts&lt;/p&gt;

&lt;p&gt;Analytics, chat widgets, and marketing tools are notorious score-killers. Use Next.js's  component with the right strategy:&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;jsximport Script from &amp;amp;#39;next/script&amp;amp;#39;&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;// Load after page is interactive&amp;lt;br&amp;gt;
&amp;lt;Script src="https://analytics.example.com/script.js" strategy="afterInteractive" /&amp;gt;&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;// Load after browser is idle&amp;lt;br&amp;gt;
&amp;lt;Script src="https://widget.example.com/widget.js" strategy="lazyOnload" /&amp;gt;&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Never use strategy=&amp;amp;quot;beforeInteractive&amp;amp;quot; unless the script is 100% critical (it almost never is).&amp;lt;/p&amp;gt;

&amp;lt;ol&amp;gt;
&amp;lt;li&amp;gt;CSS: Keep It Lean&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;

&amp;lt;p&amp;gt;Avoid Render-Blocking CSS&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;All your CSS should either be:&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Inlined (handled automatically by Next.js for critical styles)&amp;lt;br&amp;gt;
Loaded asynchronously for non-critical styles&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Purge Unused Styles&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;If you&amp;amp;#39;re using Tailwind, enable the content purge config properly:&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;js// tailwind.config.js&amp;lt;br&amp;gt;
module.exports = {&amp;lt;br&amp;gt;
  content: [&amp;lt;br&amp;gt;
    &amp;amp;#39;./app/&amp;lt;strong&amp;gt;/*.{js,ts,jsx,tsx}&amp;amp;#39;,&amp;lt;br&amp;gt;
    &amp;amp;#39;./components/&amp;lt;/strong&amp;gt;/*.{js,ts,jsx,tsx}&amp;amp;#39;,&amp;lt;br&amp;gt;
  ],&amp;lt;br&amp;gt;
}&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;This removes unused utility classes from your production build. A typical Tailwind purge goes from 3.5MB to under 15KB.&amp;lt;/p&amp;gt;

&amp;lt;ol&amp;gt;
&amp;lt;li&amp;gt;Core Web Vitals: The Actual Metrics&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;

&amp;lt;p&amp;gt;PageSpeed is built on three Core Web Vitals. You need all three to be green:&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;MetricWhat It MeasuresGood ThresholdLCP (Largest Contentful Paint)Load time of main content&amp;amp;lt; 2.5sINP (Interaction to Next Paint)Response time to user input&amp;amp;lt; 200msCLS (Cumulative Layout Shift)Visual stability&amp;amp;lt; 0.1&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Fix LCP&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Use priority on your hero image&amp;lt;br&amp;gt;
Preconnect to critical origins: &amp;lt;link rel="preconnect" href="https://fonts.gstatic.com" /&amp;gt;&amp;lt;br&amp;gt;
Make your server respond fast (Vercel edge network helps here)&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Fix INP (replaced FID in 2024)&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Minimize long JavaScript tasks&amp;lt;br&amp;gt;
Break up heavy computations with setTimeout or Web Workers&amp;lt;br&amp;gt;
Use React&amp;amp;#39;s useTransition for non-urgent state updates&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;jsxconst [isPending, startTransition] = useTransition()&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;startTransition(() =&amp;amp;gt; {&amp;lt;br&amp;gt;
  setFilteredResults(heavyFilter(data))&amp;lt;br&amp;gt;
})&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Fix CLS&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Always set image dimensions&amp;lt;br&amp;gt;
Reserve space for ads/embeds with explicit height containers&amp;lt;br&amp;gt;
Avoid injecting content above existing content dynamically&amp;lt;/p&amp;gt;

&amp;lt;ol&amp;gt;
&amp;lt;li&amp;gt;Server-Side Rendering + Caching&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;

&amp;lt;p&amp;gt;Next.js App Router gives you powerful caching primitives out of the box.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;js// Cache a data fetch for 1 hour&amp;lt;br&amp;gt;
const data = await fetch(&amp;amp;#39;&amp;lt;a href="https://api.example.com/data"&amp;gt;https://api.example.com/data&amp;lt;/a&amp;gt;&amp;amp;#39;, {&amp;lt;br&amp;gt;
  next: { revalidate: 3600 }&amp;lt;br&amp;gt;
})&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;For truly static content (like a small business homepage), use export const dynamic = &amp;amp;#39;force-static&amp;amp;#39; to pre-render at build time. Zero server compute, near-instant response.&amp;lt;/p&amp;gt;

&amp;lt;ol&amp;gt;
&amp;lt;li&amp;gt;The Audit Workflow We Use on Every Project&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;

&amp;lt;p&amp;gt;Before launch, we run through this checklist:&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;PageSpeed Insights — pagespeed.web.dev on mobile first (it&amp;amp;#39;s the harder test)&amp;lt;br&amp;gt;
WebPageTest — for waterfall analysis and finding hidden render-blocking resources&amp;lt;br&amp;gt;
Lighthouse in Chrome DevTools — for local iteration before deploying&amp;lt;br&amp;gt;
GTmetrix — cross-check and historical tracking&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;We run audits on both mobile and desktop. Mobile is the stricter standard, and it&amp;amp;#39;s where most real users are.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Real Results&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;On a recent project for a local service business, we took their site from a 34 (mobile) on PageSpeed to a 98 mobile / 100 desktop after migration from a WordPress theme to hand-coded Next.js. Load time dropped from 6.8s to under 1.2s.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;The impact wasn&amp;amp;#39;t just the score — organic traffic increased 40% over the next three months as the improved Core Web Vitals fed into Google&amp;amp;#39;s ranking algorithm.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;TL;DR Checklist&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Use next/image with explicit dimensions and priority on LCP only&amp;lt;br&amp;gt;
 Self-host fonts with next/font&amp;lt;br&amp;gt;
 Dynamic import heavy components&amp;lt;br&amp;gt;
 Defer all third-party scripts with strategy=&amp;amp;quot;afterInteractive&amp;amp;quot; or &amp;amp;quot;lazyOnload&amp;amp;quot;&amp;lt;br&amp;gt;
 Purge unused CSS&amp;lt;br&amp;gt;
 Preconnect to critical third-party origins&amp;lt;br&amp;gt;
 Use SSG or ISR for static/semi-static pages&amp;lt;br&amp;gt;
 Audit on mobile, not just desktop&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Performance isn&amp;amp;#39;t magic — it&amp;amp;#39;s a series of deliberate choices made at every step of the build. If you&amp;amp;#39;re building sites on Next.js and want to go deeper on any of these techniques, drop a comment below or reach out at oceanwaveweb.com.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Built by OceanWave Web — hand-coded Next.js websites for small businesses, starting at $0 down.&amp;lt;/p&amp;gt;
&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>performance</category>
      <category>seo</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
