Date: 2026-04-08
Branch: master (production)
Goal: Improve Lighthouse performance scores (mobile 51 -> ~70-75, desktop 78 -> ~85-90) through template and asset fixes with no pipeline changes.
| Metric | Mobile | Desktop |
|---|---|---|
| Performance | 51 | 78 |
| Accessibility | 87 | 84 |
| Best Practices | 69 | 73 |
| SEO | 92 | 92 |
Why: jQuery (91KB) loads synchronously from Google CDN, blocking rendering on every page. This is the single largest render-blocking resource.
How defer works: Deferred scripts execute in source order after HTML parsing completes, but before the DOMContentLoaded event fires. Inline <script> blocks cannot be deferred — they execute immediately when the parser encounters them. This means any inline script that references $ or jQuery will throw ReferenceError if jQuery is deferred.
Changes required:
defer to jQuery_layouts/base.html.haml line 224 — add :defer => "true"_layouts/home.html.haml line 61 — add :defer => "true"defer to functions.min.js in base layout_layouts/base.html.haml line 229 — add :defer => "true"functions.js is entirely wrapped in $(document).ready() and depends on jQuery existing at parse time. It currently loads synchronously after jQuery (also synchronous), which works. With jQuery deferred, functions.min.js must also be deferred to maintain execution order. (home.html.haml already has defer on this script.)DOMContentLoadedSince deferred scripts execute before DOMContentLoaded, wrapping inline scripts in document.addEventListener('DOMContentLoaded', function() { ... }) guarantees jQuery is available when the callback runs.
Affected inline scripts:
home.html.haml:78-82 — matchHeight call:
javascript
// Before:
$(function() { $('.equal-testimonials').matchHeight(); });
// After:
document.addEventListener('DOMContentLoaded', function() {
$('.equal-testimonials').matchHeight();
});
base.html.haml:234-235 — #{page.javascript} dynamic block. Used by:
_layouts/event.html.haml — blank (no issue)_layouts/event-dual.html.haml — blank (no issue)_layouts/landing-event.html.haml — contains $(document).ready(function(){...})Fix: wrap the template output in DOMContentLoaded:
haml
-if page.javascript
:javascript
document.addEventListener('DOMContentLoaded', function() { #{page.javascript} });
The $(document).ready() inside DOMContentLoaded is redundant but harmless — jQuery executes the callback immediately since DOM is already ready.
base.html.haml:255-265 — customers page mixItUp initialization using $(function(){...}):
javascript
// Wrap in DOMContentLoaded instead of $(function(){})
document.addEventListener('DOMContentLoaded', function() {
// ... existing mixItUp code using jQuery
});
Why: css/maps/styles.css.map (401KB) and css/maps/mmenu.css.map (56KB) are committed to git and deployed to S3. Browsers download them when DevTools are open, but they waste bandwidth and expose source structure.
Approach: Add css/maps/ to .gitignore and remove tracked maps from git. The Gulpfile will continue generating them locally for development. They just won't be committed or deployed.
Files:
- .gitignore — add css/maps/
- Run git rm -r --cached css/maps/ to untrack existing files
Why: Currently loading wght@0,300..800;1,300..800 — every weight 300-800 in both regular and italic. The SCSS only uses weights 400, 500, 600, 700, 800 with no italic. This over-fetches font data on every page load.
New URL: https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;500;600;700;800&display=swap
Files:
- _layouts/base.html.haml lines 11-14 — update all four Google Fonts references
- _layouts/home.html.haml lines 15-18 — update all four Google Fonts references
loading="lazy" to below-fold imagesWhy: Below-fold images without lazy loading compete with critical resources during initial page load, delaying LCP and increasing total blocking time.
Files and images:
- _partials/front_page/outcomes.html.haml — 3 customer logo SVGs (tunedglobal.svg, logo-boddle.svg, parakeet-logo-pms-aero.svg)
- _partials/front_page/scroller_compliance.html.haml — 2 logos (ISO-27001-certified_col.svg, jasanz.svg)
- _partials/footer-home.html.haml — base2_white.svg, jasanz.svg
Not touched: Header logo (base2.svg) stays eager — it's above fold. Hero image already has fetchpriority="high" and loading="eager".
After changes, rebuild locally and run Lighthouse on the local _site output:
1. gulp sassTask (recompile CSS if SCSS changed, though no SCSS changes in this spec)
2. Build with Awestruct via Podman
3. Serve _site/ and run Lighthouse in Chrome DevTools
4. Compare mobile and desktop performance scores to baseline