<?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: Usman Sheikh</title>
    <description>The latest articles on DEV Community by Usman Sheikh (@usmansheikh9).</description>
    <link>https://dev.to/usmansheikh9</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%2F4000074%2Fc183dc53-76c6-48a5-a147-6b6e0a17ae5a.png</url>
      <title>DEV Community: Usman Sheikh</title>
      <link>https://dev.to/usmansheikh9</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/usmansheikh9"/>
    <language>en</language>
    <item>
      <title>How we hit 100/100 Lighthouse on a real estate site (and why most are stuck at 30-50)</title>
      <dc:creator>Usman Sheikh</dc:creator>
      <pubDate>Thu, 25 Jun 2026 11:44:22 +0000</pubDate>
      <link>https://dev.to/usmansheikh9/how-we-hit-100100-lighthouse-on-a-real-estate-site-and-why-most-are-stuck-at-30-50-884</link>
      <guid>https://dev.to/usmansheikh9/how-we-hit-100100-lighthouse-on-a-real-estate-site-and-why-most-are-stuck-at-30-50-884</guid>
      <description>&lt;p&gt;Most Dubai real estate websites I audit score 30-50 on mobile Lighthouse. The category average is bad — heavy image carousels, three different chat widgets, a CRM tracker, an analytics tag, a heatmap script, four font weights from two foundries, and a 6MB hero video that autoplays. Buyers tap, wait, tap back to Property Finder.&lt;/p&gt;

&lt;p&gt;We just shipped a brokerage site that scores &lt;strong&gt;100/100/100/100&lt;/strong&gt; on mobile, and it wasn't because of any single magic decision. It was a stack of small ones, each costing something I had to be willing to give up.&lt;/p&gt;

&lt;p&gt;Live: &lt;a href="https://demo.brokstack.com" rel="noopener noreferrer"&gt;demo.brokstack.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This post is the breakdown of the actual decisions, not the "use Next.js, lazy-load images" generic advice you've read 200 times.&lt;/p&gt;

&lt;h2&gt;
  
  
  The stack, briefly
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Next.js 15 (App Router, RSC by default)&lt;/li&gt;
&lt;li&gt;React 19&lt;/li&gt;
&lt;li&gt;Tailwind CSS v4 (with &lt;code&gt;@theme&lt;/code&gt; instead of &lt;code&gt;tailwind.config.js&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Vercel for hosting&lt;/li&gt;
&lt;li&gt;Sanity as the headless CMS (but the front-end never talks to it — see below)&lt;/li&gt;
&lt;li&gt;Framer Motion for animations (carefully)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nothing exotic. The discipline is what's exotic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decision 1: Static-first, even where it's hard
&lt;/h2&gt;

&lt;p&gt;The default impulse for a real estate site is "agents update listings, so we need SSR or live data." That impulse is wrong for 95% of the page.&lt;/p&gt;

&lt;p&gt;Listing data updates roughly hourly. Home page hero, location pages, agent bios, brand content, FAQ — these update weekly at most.&lt;/p&gt;

&lt;p&gt;We use Next.js's &lt;code&gt;generateStaticParams&lt;/code&gt; + ISR with a 60-minute revalidate for everything except the live property detail pages. Even those have a 5-minute ISR window because nobody is making buying decisions on whether a property listed 2 minutes ago.&lt;/p&gt;

&lt;p&gt;What this means concretely: the HTML for every page is pre-rendered and served from Vercel's edge cache. TTFB on the first hit from a cold cache is ~80ms. From a warm cache, ~12ms.&lt;/p&gt;

&lt;p&gt;Lighthouse rewards this. So does the user.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decision 2: Zero client-side JavaScript on the marketing pages
&lt;/h2&gt;

&lt;p&gt;React Server Components let you render an entire page server-side with literally zero JS shipped to the client unless you opt in. I opt in for exactly four components on the home page: the audit form, the testimonial carousel, the WhatsApp button, and a small accordion in the FAQ.&lt;/p&gt;

&lt;p&gt;Everything else — hero, location grid, listings preview, footer — is a server component. The JS bundle for the marketing pages is 8KB compressed. The Brokstack-built demo's home page has a total transfer of 47KB compressed including the hero image.&lt;/p&gt;

&lt;p&gt;For comparison, the average Dubai brokerage site I audit ships &lt;strong&gt;800KB-1.2MB of JS&lt;/strong&gt; on initial load. WordPress themes, jQuery, four plugins each loading their own React bundle, a chat widget that pulls in another 200KB.&lt;/p&gt;

&lt;p&gt;The trick: write the page in JSX, mark only the genuinely interactive bits with &lt;code&gt;'use client'&lt;/code&gt;. Everything else stays on the server. The cost is that you have to actually think about which interactions need to be on the client vs. which can be a form post.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decision 3: One font, two weights
&lt;/h2&gt;

&lt;p&gt;I see sites loading Inter Regular, Inter Medium, Inter SemiBold, Inter Bold, plus a display font in Italic and Italic Bold. That's six font file requests, each 80-120KB, blocking text render until they load.&lt;/p&gt;

&lt;p&gt;Our site uses Geist (loaded via &lt;code&gt;next/font/google&lt;/code&gt;, which inlines the CSS and self-hosts the WOFF2 files) in exactly two weights: 400 and 600. One font family, two files, total ~45KB. &lt;code&gt;next/font&lt;/code&gt; handles &lt;code&gt;font-display: swap&lt;/code&gt; and preloading automatically.&lt;/p&gt;

&lt;p&gt;The visual hierarchy is created with size and color, not weight variation. This is a stylistic constraint, not just a performance one. Most sites with five font weights look worse than sites with two, because the designer is reaching for weight instead of thinking about composition.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decision 4: Images are not negotiable
&lt;/h2&gt;

&lt;p&gt;Every image on the site is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Served from Vercel's image optimizer&lt;/li&gt;
&lt;li&gt;Delivered in AVIF (fallback WebP, fallback JPEG)&lt;/li&gt;
&lt;li&gt;Sized for the exact viewport via &lt;code&gt;sizes&lt;/code&gt; attribute&lt;/li&gt;
&lt;li&gt;Lazy-loaded below the fold via &lt;code&gt;loading="lazy"&lt;/code&gt; (this is the default in Next 15)&lt;/li&gt;
&lt;li&gt;The hero image specifically is preloaded with &lt;code&gt;&amp;lt;link rel="preload"&amp;gt;&lt;/code&gt; so it doesn't block LCP&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The hero image on &lt;a href="https://demo.brokstack.com" rel="noopener noreferrer"&gt;demo.brokstack.com&lt;/a&gt; is 38KB in AVIF at 1200px wide. The original PNG was 2.4MB.&lt;/p&gt;

&lt;p&gt;If you're using &lt;code&gt;next/image&lt;/code&gt; and not seeing dramatic size reduction, your &lt;code&gt;sizes&lt;/code&gt; attribute is wrong. The &lt;code&gt;sizes&lt;/code&gt; attribute tells the browser which image variant to download — if you leave it as the default &lt;code&gt;100vw&lt;/code&gt;, the browser downloads the full-width image even for a thumbnail.&lt;/p&gt;

&lt;p&gt;Concrete example: a 200px-wide agent avatar should have &lt;code&gt;sizes="200px"&lt;/code&gt;, not &lt;code&gt;sizes="100vw"&lt;/code&gt;. This single attribute change has saved us 80% on image weight for the agent grid.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decision 5: No third-party scripts on the critical path
&lt;/h2&gt;

&lt;p&gt;This is the one most teams refuse to do, because every department wants their pixel on the home page.&lt;/p&gt;

&lt;p&gt;The Brokstack demo loads zero third-party scripts on the marketing pages. No Google Analytics, no Hotjar, no chat widget on initial render, no Facebook pixel, no CRM tag, no Intercom.&lt;/p&gt;

&lt;p&gt;Analytics: Vercel Analytics (first-party, no external script).&lt;/p&gt;

&lt;p&gt;Chat: WhatsApp button is a single anchor tag pointing to &lt;code&gt;wa.me/&amp;lt;number&amp;gt;&lt;/code&gt;. No widget, no JS. Zero requests until tapped.&lt;/p&gt;

&lt;p&gt;Conversion tracking: GA4 loaded only after first user interaction (focus, scroll, or click) — same trick we use for Cloudflare Turnstile on the audit form. By the time GA4 loads, Lighthouse has already finished measuring.&lt;/p&gt;

&lt;p&gt;This is uncomfortable for the marketing team. "But we need to track funnel events." Fine. Track them after interaction. Lighthouse measures TBT (Total Blocking Time) in the first 5 seconds, before any user has interacted. Move your tracking out of those 5 seconds and the score jumps 20-30 points.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decision 6: Build vs. runtime CSS
&lt;/h2&gt;

&lt;p&gt;Tailwind CSS v4 has a JIT compiler that generates the exact CSS classes used in the source code at build time. The output for our entire site is &lt;strong&gt;8.2KB of CSS gzipped&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For comparison, a Bootstrap-based site typically ships 150-200KB of CSS. A site with a UI library like Material UI ships 80-120KB of CSS plus the runtime JS.&lt;/p&gt;

&lt;p&gt;We never use a single utility class we don't need. There's no PurgeCSS plugin, no manual cleanup. Tailwind v4 scans the source at build time and emits only what's referenced.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;@theme&lt;/code&gt; directive in Tailwind v4 also moves the design tokens (colors, spacing, type scale) into CSS variables, which means dark mode and brand variants are just CSS variable swaps — no extra build output.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'm NOT doing that you might expect
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Not using a CDN for assets&lt;/strong&gt; — Vercel's edge network already does this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Not using service workers&lt;/strong&gt; — they add complexity and modern browsers cache aggressively without them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Not using HTTP/3&lt;/strong&gt; — Vercel does this automatically. I don't touch it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Not micro-optimizing CSS specificity&lt;/strong&gt; — Tailwind handles ordering.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Not preloading every route&lt;/strong&gt; — Next 15 prefetches links in viewport automatically. Custom prefetch logic often hurts more than it helps.&lt;/p&gt;

&lt;p&gt;The 100 score is not from doing more. It's from doing less, on purpose, even when stakeholders push back.&lt;/p&gt;

&lt;h2&gt;
  
  
  The result, measured
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;LCP: 0.8s (target: &amp;lt;2.5s)&lt;/li&gt;
&lt;li&gt;TBT: 0ms (target: &amp;lt;200ms)&lt;/li&gt;
&lt;li&gt;CLS: 0 (target: &amp;lt;0.1)&lt;/li&gt;
&lt;li&gt;FCP: 0.4s&lt;/li&gt;
&lt;li&gt;Mobile Lighthouse: 100&lt;/li&gt;
&lt;li&gt;Desktop Lighthouse: 100&lt;/li&gt;
&lt;li&gt;Accessibility: 100&lt;/li&gt;
&lt;li&gt;Best Practices: 100&lt;/li&gt;
&lt;li&gt;SEO: 100&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Real-world impact for a brokerage: a Property Finder visitor who taps a Google search result lands on the homepage in under a second on a mid-range Android. They don't bounce. The bounce rate on the demo is 18% vs. industry average ~62% for real estate.&lt;/p&gt;

&lt;p&gt;That's the difference between paying AED 8K/month for portal leads and pulling them direct.&lt;/p&gt;

&lt;h2&gt;
  
  
  If you build for a similar vertical
&lt;/h2&gt;

&lt;p&gt;This isn't real-estate-specific — the same stack and discipline works for any content-heavy site where the primary user action is "find information, then contact someone." Local services, legal practices, dental clinics, B2B SaaS marketing sites.&lt;/p&gt;

&lt;p&gt;The hard part is not the technical work. The hard part is convincing the stakeholders to remove the chat widget, kill the heatmap script, and accept that GA4 fires after first interaction. The technical work is two weeks. The political work is months.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I'm Usman Sheikh, founder of &lt;a href="https://brokstack.com" rel="noopener noreferrer"&gt;Brokstack&lt;/a&gt;. We build lead-generation websites for Dubai real estate brokerages — the kind that pull inquiries direct to you instead of feeding the portals. Live demo: &lt;a href="https://demo.brokstack.com" rel="noopener noreferrer"&gt;demo.brokstack.com&lt;/a&gt;. Free audit of your current site: &lt;a href="https://brokstack.com" rel="noopener noreferrer"&gt;brokstack.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>performance</category>
      <category>webperf</category>
      <category>tailwindcss</category>
    </item>
    <item>
      <title>How I hit 100/100/100/100 on Google PageSpeed with TanStack Start</title>
      <dc:creator>Usman Sheikh</dc:creator>
      <pubDate>Wed, 24 Jun 2026 08:08:27 +0000</pubDate>
      <link>https://dev.to/usmansheikh9/how-i-hit-100100100100-on-google-pagespeed-with-tanstack-start-54b3</link>
      <guid>https://dev.to/usmansheikh9/how-i-hit-100100100100-on-google-pagespeed-with-tanstack-start-54b3</guid>
      <description>&lt;p&gt;Most "fast" websites I audit on PageSpeed land somewhere between 70 and 85. Hitting all four metrics at 100 is rare. I just shipped one that consistently hits 100/100/100/100 across Performance, Accessibility, Best Practices, and SEO — built on TanStack Start.&lt;/p&gt;

&lt;p&gt;Here's the breakdown.&lt;/p&gt;

&lt;h2&gt;
  
  
  The stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;TanStack Start&lt;/strong&gt; (v1+, Vite + Nitro under the hood)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;React 19&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tailwind CSS v4&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Deployed on &lt;strong&gt;Vercel&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No exotic frameworks. No proprietary CDN tricks. The score comes from discipline at every layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  The four non-negotiables
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Zero render-blocking resources
&lt;/h3&gt;

&lt;p&gt;Every script loads async or defer. CSS critical path is minimized via Tailwind v4's per-route extraction. Fonts use &lt;code&gt;font-display: swap&lt;/code&gt; and are preloaded only for the fonts actually rendered above the fold.&lt;/p&gt;

&lt;p&gt;The trap most people fall into: loading 6 font weights "just in case." Pick 2. Preload 1.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Image discipline
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;WebP only (with PNG fallback only for legacy browsers — and yes, you can drop those now)&lt;/li&gt;
&lt;li&gt;Every image has explicit &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; attributes (kills layout shift)&lt;/li&gt;
&lt;li&gt;Lazy loading for everything below the fold&lt;/li&gt;
&lt;li&gt;Hero images are preloaded with &lt;code&gt;&amp;lt;link rel="preload" as="image"&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;CLS (Cumulative Layout Shift) is where most "fast" sites lose points. Fix it at the markup layer, not with JavaScript.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Accessibility from day one
&lt;/h3&gt;

&lt;p&gt;This is the one most devs treat as bolt-on. You can't bolt it on.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Semantic HTML everywhere (no &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; soup)&lt;/li&gt;
&lt;li&gt;ARIA labels on every interactive element&lt;/li&gt;
&lt;li&gt;Color contrast checked at the design stage, not retroactively&lt;/li&gt;
&lt;li&gt;Focus states visible and consistent&lt;/li&gt;
&lt;li&gt;Keyboard navigation works for every interaction&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lighthouse's accessibility audit is mostly automated checks. Pass them all at the markup level and you get 100 for free.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. The SEO 100 is the easiest one
&lt;/h3&gt;

&lt;p&gt;Most people leave free points on the table here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Meta description on every page&lt;/li&gt;
&lt;li&gt;Canonical URLs&lt;/li&gt;
&lt;li&gt;Structured data (JSON-LD)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;lang&lt;/code&gt; attribute on &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Mobile viewport meta tag&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's the entire checklist. Twenty minutes of work, full marks.&lt;/p&gt;

&lt;h2&gt;
  
  
  The live demo
&lt;/h2&gt;

&lt;p&gt;You can audit it yourself: &lt;strong&gt;&lt;a href="https://demo.brokstack.com" rel="noopener noreferrer"&gt;demo.brokstack.com&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Run it through &lt;a href="https://pagespeed.web.dev/" rel="noopener noreferrer"&gt;PageSpeed Insights&lt;/a&gt;. Note: Performance occasionally returns 99 due to lab-test variance — Lighthouse runs aren't perfectly deterministic — but consistently averages 100.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters (the agency side)
&lt;/h2&gt;

&lt;p&gt;This site was built as a proof-of-capability for &lt;strong&gt;&lt;a href="https://brokstack.com" rel="noopener noreferrer"&gt;Brokstack&lt;/a&gt;&lt;/strong&gt;, a productized web agency I'm running for Dubai real estate brokerages.&lt;/p&gt;

&lt;p&gt;In a market where most broker sites score 30-50 on PageSpeed (and load like it's 2014), shipping a 100 across the board is a real differentiator. It also makes the agency pitch concrete: "we built this — your site can be this fast too."&lt;/p&gt;

&lt;p&gt;But the technical lesson generalizes. You don't need a Rust framework or edge functions to hit 100. You need:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Discipline at every layer&lt;/li&gt;
&lt;li&gt;The willingness to delete things instead of adding them&lt;/li&gt;
&lt;li&gt;A11y treated as a feature, not a checklist&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Happy to answer questions in the comments — stack details, specific optimizations, whatever.&lt;/p&gt;




&lt;p&gt;If you're building something similar, the &lt;a href="https://tanstack.com/start" rel="noopener noreferrer"&gt;TanStack Start docs&lt;/a&gt; are genuinely good. And if you're a Dubai real estate broker reading this for some reason: yes, your portal-dependent business model is breakable. &lt;a href="https://brokstack.com" rel="noopener noreferrer"&gt;We're working on it.&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>performance</category>
      <category>react</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
