DEV Community

Tan Phan
Tan Phan

Posted on

How I Found and Fixed 5 Critical Lighthouse Issues in a WebGL 3D Landing Page (With a Python CLI)

A few months ago, I was building a B2B landing page that embedded a 3D industrial model using . The page looked great visually. Then I ran Lighthouse.

Score: 42/100.

Here are the 5 issues I found -- and what made each one non-obvious:

1. Too Many Font Weights (8 requests instead of 3)

Google Fonts was loading wght@300;400;500;600;700;800 -- 6 weights for Inter plus 2 for JetBrains Mono = 8 separate HTTP requests just for fonts.

Each one is render-blocking. The fix: reduce to wght@400;600;700. Saved ~400ms.

2. Script in (Render-Blocking)

The WebGL script was 300KB. Sitting in

. Blocking everything.

Fix: Move it to the end of

. Use type="module" so it defers automatically.
<!-- Before (in <head>) -->
<script src="model-viewer.min.js" type="module"></script>

<!-- After (end of <body>) -->
<script type="module" src="model-viewer.min.js"></script>
Enter fullscreen mode Exit fullscreen mode

3. Missing preconnect and dns-prefetch

The page used Google Fonts, a QR code API, and the model-viewer CDN -- but had zero preconnect tags. Each domain needed a full DNS lookup + TLS handshake before any resource could load.

Fix: Add preconnect for all external domains in

.

4. Hero Image Set to loading="lazy"

Someone (me) had applied loading="lazy" to ALL images including the hero image at the top of the page. The browser would defer loading the most important image -- the one that determines LCP.

Fix: Hero image gets loading="eager" and fetchpriority="high". Everything below the fold stays lazy.

5. The Silent SEO Killer: JavaScript Injected Into JSON-LD

This one is the nastiest bug.

A Particle.js animation was running on the page. Due to a timing issue, it appended animation callback code into a block. The page looked perfect in the browser. No console errors.</p> <p>But the JSON-LD was now invalid. Google Search Console quietly stopped indexing the Product rich snippet. I only found out 3 months later when I ran a structured data audit.</p> <hr> <h2> <a name="the-fix-webperformancesurgeon" href="#the-fix-webperformancesurgeon" class="anchor"> </a> The Fix: web-performance-surgeon </h2> <p>I got tired of hunting these issues manually, so I built a Python CLI that scans and auto-fixes all of them:<br> </p> <div class="highlight"><pre class="highlight shell"><code><span class="c"># Audit only -- shows all issues</span> python web_performance_surgeon.py index.html <span class="c"># Audit + auto-fix everything</span> python web_performance_surgeon.py index.html <span class="nt">--fix</span> </code></pre></div> <p></p> <p>Final score after fixes: <strong>98/100 Lighthouse</strong>.</p> <p>I also built companion tools for the other issues:</p> <ul> <li><strong>json-ld-schema-guardian</strong> -- specifically scans for JS injection into JSON-LD blocks</li> <li><strong>static-dom-surgeon</strong> -- surgically patches HTML elements at scale (used BeautifulSoup to patch 21 product cards without touching surrounding code)</li> <li><strong>b2b-landing-page-checklist</strong> -- 50-point pre-launch checklist with all the lessons from this project</li> </ul> <p>All free and open source: <a href="https://github.com/tanphan1105">github.com/tanphan1105</a></p> <hr> <p><em>Have you run into the JSON-LD injection bug before? Curious if this is more common than I think.</em></p>

Top comments (0)