Remove Unused JavaScript
Eliminate JavaScript that no page executes to cut parse, compile, and main-thread time.
Metrics
This technique can move up to 33% of LCP's share of the Lighthouse score.
This technique can move up to 100% of TBT's share of the Lighthouse score.
This technique does not move CLS.
This technique can move up to 67% of FCP's share of the Lighthouse score.
This technique can move up to 67% of SI's share of the Lighthouse score.
This technique does not move TTFB.
Overview
JavaScript is the most expensive resource per byte on the web. Every kilobyte of JS must be transferred, parsed by the V8 engine, compiled to bytecode, and then executed — all on the main thread. A 300 KB JavaScript bundle that is 50% unused still costs the full parse and compile time for all 300 KB. Removing code that never runs is among the highest-leverage optimisations for TBT and INP on JavaScript-heavy pages.
Impact grade, A+ to D: how much of the Lighthouse score this technique can move. Unaffected: CLS, TTFB.
The Problem
WordPress sites accumulate JavaScript from themes, plugins, and page builders — much of it shipped as monolithic bundles that include code for features not present on the current page. A contact form plugin may load its full validation library on every page even when no form exists. Lighthouse’s Coverage audit commonly finds 60–90% of JS on a page is unused on first load.
Performance Impact
LCP
less script to parse and execute frees the main thread sooner to handle layout and paint of the LCP element
TBT
200–1000ms
less JavaScript compiled and executed on the main thread
FCP
100–400ms
fewer parser-blocking or render-competing scripts
SI
100–300ms
main thread freed sooner for painting
Risk: Medium
requires coverage testing — removing active code breaks features
How it works
01
Audit coverage in Chrome DevTools
Open DevTools → More tools → Coverage. Load the page, then check each JavaScript file. Red bars show unexecuted byte ranges. Focus first on large files with > 60% unused coverage.
02
Conditionally dequeue plugin scripts
In WordPress, many plugin scripts load globally but are only needed on specific pages. Use
wp_dequeue_script()conditionally — remove contact form scripts from pages without a form, slider scripts from pages without a slider.03
Tree-shake with a bundler
Webpack, Rollup, and Vite use static analysis to detect and remove exported functions that are never imported. Enable tree-shaking by using ES module syntax (
import/export) rather than CommonJS (require).04
Code-split with dynamic imports
Split large bundles into chunks loaded only when needed. Replace
import Dialog from './dialog'withconst { Dialog } = await import('./dialog')inside the click handler — the dialog code loads only when the user opens it.
Limitations
- Tree-shaking requires ES module syntax throughout the dependency graph — CommonJS modules cannot be statically analysed for dead code.
- Dynamic imports add a network round trip when the feature is first used — pre-warm the import on hover or Intersection Observer to hide the latency.
- Conditional dequeuing in WordPress requires testing every page type to ensure scripts are present where genuinely needed.
Common Mistakes
Deferring large unused scripts instead of removing them
defer moves execution after parsing but still parses and compiles the entire file. A 200 KB unused script still costs its full parse+compile time even with defer. Only code that runs should be loaded at all.
Removing a script without checking if another plugin depends on it
WordPress scripts declare dependencies via the $deps parameter of wp_enqueue_script(). Dequeuing a dependency can silently break other plugins. Check the dependency chain before dequeuing.
Need help applying this to your site?
Targeted fixes, not guesswork. We identify which techniques move the needle for your specific WordPress stack.
Start an Engagement