Skip to main content
All Docs
FeaturesBlockManOSUpdated March 26, 2026

Performance: Managing Third-Party Script Loading (PERF-24)

Performance: Managing Third-Party Script Loading (PERF-24)

Release: v1.0.70
Control: PERF-24
Category: Performance / Resource Loading

Overview

This audit finding (PERF-24) identifies a risk introduced by a large browser script asset (public/tailwindcss-browser.js, 271KB) whose loading strategy is uncontrolled. Without an explicit loading strategy, this script may load synchronously and block the browser's rendering pipeline, degrading Time to Interactive (TTI) and Largest Contentful Paint (LCP) scores.

No usage of Next.js's built-in next/script component was found in the codebase, indicating that script loading optimisation has not yet been applied to any third-party or large asset script.


The Problem: Render-Blocking Scripts

When a browser encounters a <script> tag in the document without async or defer attributes, it:

  1. Pauses HTML parsing at that point.
  2. Downloads the script (network latency applies).
  3. Executes the script before continuing to parse the rest of the document.

For a 271KB file like tailwindcss-browser.js, this can add hundreds of milliseconds of delay on average connections — directly penalising Core Web Vitals scores and user-perceived load time.


Affected Asset

public/tailwindcss-browser.js

  • Size: ~271KB
  • Location: public/ directory (served as a static asset)
  • Suspected use: Dynamic HTML rendering inside the MarketingIframe component
  • Risk: If loaded via a synchronous <script> tag on any page, it is render-blocking

Recommended Fixes

Option 1: Use next/script with lazyOnload

If the script is genuinely needed on a page (e.g. for MarketingIframe rendering), replace any bare <script> tag with Next.js's Script component using the lazyOnload strategy. This defers loading until after the page is fully interactive.

import Script from 'next/script';

// Inside your component or page:
<Script
  src="/tailwindcss-browser.js"
  strategy="lazyOnload"
/>

When to use: The script is needed on the main page but is not critical for initial render.


Option 2: Inject Only into the Iframe Document

If tailwindcss-browser.js is only needed for rendering HTML inside the MarketingIframe, inject it into the iframe's own document rather than the parent page. This confines any performance cost entirely to the iframe context.

// Inside marketing-iframe.tsx — build an srcdoc string
const iframeContent = `
  <!DOCTYPE html>
  <html>
    <head>
      <script src="/tailwindcss-browser.js"></script>
    </head>
    <body>
      ${dynamicHtmlContent}
    </body>
  </html>
`;

<iframe srcDoc={iframeContent} />

When to use: The script is only needed to style or render content inside the iframe, never on the main page.


Option 3: Remove the Asset

If tailwindcss-browser.js is not actively referenced anywhere in the application, remove it from public/ entirely.

rm public/tailwindcss-browser.js

Verify no references exist before removing:

grep -r "tailwindcss-browser" ./

When to use: The file is dead code / an unused legacy asset.


Auditing marketing-iframe.tsx

Regardless of which option is chosen for the asset itself, the marketing-iframe.tsx component should be audited to ensure it does not perform any synchronous script injection. Patterns to check for and avoid:

PatternRisk
document.write('<script ...')Render-blocking, deprecated
Setting innerHTML with a <script> tagScripts injected via innerHTML may not execute consistently
Constructing a <script> element and appending to document.head without async/deferSynchronous execution risk
Bare <script src="..."> in a JSX return outside of next/scriptBypasses Next.js loading optimisation

Next.js Script Loading Strategies — Quick Reference

StrategyWhen it loadsUse case
beforeInteractiveBefore page hydrationCritical scripts only (e.g. consent management)
afterInteractiveAfter page hydrationAnalytics, tag managers
lazyOnloadDuring browser idle timeLow-priority scripts, marketing tools
worker (experimental)In a Web WorkerOffload heavy scripts from main thread

For most non-critical third-party scripts, lazyOnload or afterInteractive are the appropriate choices.


Related