Performance Optimization

Optimize your ABC showcase for blazing-fast load times and smooth interactions.

Build Performance

Jekyll Build Optimization

Exclude unnecessary files:

# _config.yml
exclude:
  - node_modules/
  - src/
  - vendor/
  - .git/
  - .github/
  - README.md
  - Gemfile
  - Gemfile.lock
  - package.json
  - package-lock.json

Use incremental builds:

bundle exec jekyll build --incremental

Profile build time:

bundle exec jekyll build --profile

Optimize Data Files

Reduce _data/mods.json size:

{
  "modpacks": [
    {
      "slug": "abc",
      "name": "ABC Pack",
      "desc": "Brief description",
      "icon": "/path/to/icon.png",
      "dl": 50000,
      "cat": ["tech"]
    }
  ]
}

Use abbreviated keys and remove unnecessary fields.

Compress JSON:

# Install jq
brew install jq

# Minify JSON
jq -c . _data/mods.json > _data/mods.min.json

Asset Optimization

Images

Use WebP format:

<picture>
  <source srcset="image.webp" type="image/webp" />
  <img src="image.png" alt="Description" />
</picture>

Convert images:

# Install ImageMagick
brew install imagemagick

# Convert to WebP
magick convert input.png -quality 80 output.webp

Optimize existing images:

# PNG optimization
pngquant --quality 65-80 image.png

# JPG optimization
jpegoptim --max=85 image.jpg

Lazy loading:

<img src="image.jpg" loading="lazy" alt="Description" />

CSS Optimization

Minify CSS:

# _config.yml
sass:
  style: compressed

Critical CSS:

Extract above-the-fold styles:

<head>
  <style>
    /* Critical CSS inline */
    body {
      margin: 0;
      font-family: sans-serif;
    }
    .hero {
      min-height: 100vh;
    }
  </style>

  <!-- Defer non-critical CSS -->
  <link
    rel="preload"
    href="/assets/css/main.css"
    as="style"
    onload="this.onload=null;this.rel='stylesheet'"
  />
  <noscript><link rel="stylesheet" href="/assets/css/main.css" /></noscript>
</head>

Remove unused CSS:

npm install -g purgecss

purgecss --css assets/css/*.css \
         --content _site/**/*.html \
         --output assets/css/

JavaScript Optimization

Defer non-critical scripts:

<script src="/assets/js/main.js" defer></script>

Async for independent scripts:

<script src="/assets/js/analytics.js" async></script>

Minify JavaScript:

npm install -g terser

terser input.js -o output.min.js -c -m

Code splitting:

<!-- Load only what's needed -->

<script src="/assets/js/docs.js" defer></script>

Caching Strategies

HTTP Caching

Add cache headers:

<!-- Netlify: _headers file -->
/assets/* Cache-Control: public, max-age=31536000, immutable /css/*
Cache-Control: public, max-age=31536000, immutable /js/* Cache-Control: public,
max-age=31536000, immutable /*.html Cache-Control: public, max-age=0,
must-revalidate

Versioning assets:

<link rel="stylesheet" href="/assets/css/main.css?v=1765935080">

Service Worker

Basic service worker:

// sw.js
const CACHE_NAME = "abc-site-v1";
const urlsToCache = [
  "/",
  "/assets/css/main.css",
  "/assets/js/main.js",
  "/assets/images/logo.svg",
];

self.addEventListener("install", (event) => {
  event.waitUntil(
    caches.open(CACHE_NAME).then((cache) => cache.addAll(urlsToCache))
  );
});

self.addEventListener("fetch", (event) => {
  event.respondWith(
    caches
      .match(event.request)
      .then((response) => response || fetch(event.request))
  );
});

Register service worker:

<script>
  if ("serviceWorker" in navigator) {
    navigator.serviceWorker.register("/sw.js");
  }
</script>

Loading Optimization

Resource Hints

Preconnect to external domains:

<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://cdn.modrinth.com" />

Prefetch next page:

<link rel="prefetch" href="" />

Preload critical resources:

<link
  rel="preload"
  href="/assets/fonts/main.woff2"
  as="font"
  type="font/woff2"
  crossorigin
/>
<link rel="preload" href="/assets/images/hero.webp" as="image" />

Font Optimization

Use system fonts:

body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen,
    Ubuntu, Cantarell, sans-serif;
}

Or optimize web fonts:

/* Only load needed weights and styles */
@font-face {
  font-family: "CustomFont";
  src: url("/fonts/custom-regular.woff2") format("woff2");
  font-weight: 400;
  font-display: swap;
}

Subset fonts:

# Install glyphhanger
npm install -g glyphhanger

# Generate subset
glyphhanger --subset=font.ttf \
            --formats=woff2 \
            --whitelist="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"

Runtime Performance

Efficient JavaScript

Debounce expensive operations:

function debounce(func, wait) {
  let timeout;
  return function (...args) {
    clearTimeout(timeout);
    timeout = setTimeout(() => func.apply(this, args), wait);
  };
}

// Usage
const search = debounce((query) => {
  // Expensive search operation
}, 300);

input.addEventListener("input", (e) => search(e.target.value));

Use requestAnimationFrame:

function updateAnimation() {
  // Animation logic
  requestAnimationFrame(updateAnimation);
}

requestAnimationFrame(updateAnimation);

Lazy load images:

const observer = new IntersectionObserver((entries) => {
  entries.forEach((entry) => {
    if (entry.isIntersecting) {
      const img = entry.target;
      img.src = img.dataset.src;
      observer.unobserve(img);
    }
  });
});

document.querySelectorAll("img[data-src]").forEach((img) => {
  observer.observe(img);
});

CSS Performance

Avoid expensive selectors:

/* Slow */
div > div > div > p {
}

/* Fast */
.paragraph {
}

Use transforms over position:

/* Slow */
.element {
  left: 100px;
  top: 100px;
}

/* Fast */
.element {
  transform: translate(100px, 100px);
}

Enable GPU acceleration:

.animated {
  transform: translateZ(0);
  will-change: transform;
}

Monitoring

Lighthouse

npm install -g lighthouse

lighthouse https://yoursite.com \
  --output html \
  --output-path ./report.html

Web Vitals

Measure Core Web Vitals:

<script type="module">
  import {
    getCLS,
    getFID,
    getFCP,
    getLCP,
    getTTFB,
  } from "https://unpkg.com/web-vitals@3/dist/web-vitals.js";

  function sendToAnalytics(metric) {
    console.log(metric);
    // Send to analytics service
  }

  getCLS(sendToAnalytics);
  getFID(sendToAnalytics);
  getFCP(sendToAnalytics);
  getLCP(sendToAnalytics);
  getTTFB(sendToAnalytics);
</script>

Performance API

// Measure page load time
window.addEventListener("load", () => {
  const perfData = performance.getEntriesByType("navigation")[0];
  console.log("Page load time:", perfData.loadEventEnd - perfData.fetchStart);
});

// Custom timing
performance.mark("search-start");
// ... search operation
performance.mark("search-end");
performance.measure("search", "search-start", "search-end");

Checklist

  • Enable SASS compression
  • Exclude unnecessary files from build
  • Optimize and compress images
  • Minify CSS and JavaScript
  • Add lazy loading for images
  • Implement resource hints (preconnect, prefetch)
  • Configure HTTP caching headers
  • Use system fonts or subset web fonts
  • Defer non-critical JavaScript
  • Enable gzip/brotli compression
  • Remove unused CSS
  • Optimize data file sizes
  • Test with Lighthouse
  • Monitor Core Web Vitals
  • Set up service worker for offline support

Benchmarking

Before Optimization

Lighthouse Score: 65
First Contentful Paint: 2.5s
Largest Contentful Paint: 4.2s
Total Bundle Size: 850KB

After Optimization

Lighthouse Score: 95
First Contentful Paint: 0.8s
Largest Contentful Paint: 1.2s
Total Bundle Size: 220KB

Next Steps