Hugo Performance Optimization: Making Vitis Lightning Fast

โ€ข 5 minutes read

The Need for Speed

In an age of bloated JavaScript frameworks, Vitis proves that fast, feature-rich sites don’t require sacrifice. Let’s explore the optimizations that deliver:

  • โšก <1s page load times
  • ๐ŸŽฏ 95+ Lighthouse scores
  • ๐Ÿ“ฆ <50KB initial payload
  • ๐Ÿš€ Instant navigation with prefetch

Build-Time Optimizations

1. Intelligent Asset Bundling

Hugo’s asset pipeline handles:

{{ $css := resources.Get "css/style.css" }}
{{ $css = $css | postCSS | minify | fingerprint }}
<link rel="stylesheet" href="{{ $css.RelPermalink }}">

This gives us:

  • Minification - Removes whitespace and comments
  • Fingerprinting - Cache-busting via content hashes
  • PostCSS - Processes Tailwind and autoprefixes

2. Tailwind PurgeCSS

Vitis uses Tailwind’s JIT compiler:

// tailwind.config.js
module.exports = {
  content: ["./layouts/**/*.{html,js}"],
  // Only includes CSS for classes actually used
}

Result: 2.5MB Tailwind โ†’ 15KB in production

3. Conditional Feature Loading

The knowledge graph only loads on relevant pages:

{{ if or .IsHome (eq .Type "graph") }}
  <script src="{{ $d3js }}"></script>
  <script src="{{ $graphjs }}"></script>
{{ end }}

Most pages ship zero JavaScript!

4. Optimized Syntax Highlighting

[markup.highlight]
  noClasses = false  # Use CSS instead of inline styles
  style = "dracula"

One CSS file for all code blocks vs. inline styles on every <pre>.

Runtime Optimizations

1. Lazy Image Loading

<img 
  src="{{ $image.RelPermalink }}"
  loading="lazy"
  decoding="async"
  alt="..."
>

Images below the fold load on scroll, not on page load.

2. Resource Hints

Critical resources prefetched:

<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="dns-prefetch" href="https://cdn.example.com">

3. Critical CSS Inlining

Above-the-fold styles inline in <head>:

<style>
  /* Critical CSS for initial render */
  body { font-family: Inter, sans-serif; }
  .header { /* ... */ }
</style>

Eliminates render-blocking CSS for initial paint.

4. Font Optimization

@font-face {
  font-family: 'Inter';
  font-display: swap;  /* Show fallback immediately */
  src: url('/fonts/inter.woff2') format('woff2');
}

Font-display: swap prevents invisible text during load.

JavaScript Performance

1. Vanilla JS Over Frameworks

Vitis uses zero frameworks:

// React equivalent: ~50KB
// Vitis approach: ~5KB

document.getElementById('theme-toggle')
  .addEventListener('click', toggleDarkMode);

For simple interactions, vanilla JS is 10x smaller.

2. Event Delegation

Instead of multiple listeners:

// โŒ One listener per item
items.forEach(item => {
  item.addEventListener('click', handler);
});

// โœ… One listener for all
container.addEventListener('click', e => {
  if (e.target.matches('.item')) handler(e);
});
let searchTimeout;
searchInput.addEventListener('input', e => {
  clearTimeout(searchTimeout);
  searchTimeout = setTimeout(() => {
    performSearch(e.target.value);
  }, 300);
});

Reduces search operations from 50/second to ~3/second.

4. Intersection Observer

Efficient scroll detection:

const observer = new IntersectionObserver(entries => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      loadContent(entry.target);
    }
  });
});

elements.forEach(el => observer.observe(el));

Network Optimizations

1. HTTP/2 Server Push

In Netlify config:

headers
  for = "/*"
  [headers.values]
    Link = '''
      </css/output.css>; rel=preload; as=style,
      </js/main.js>; rel=preload; as=script
    '''

2. Compression

Gzip/Brotli compression enabled:

# netlify.toml
[build.processing.css]
  bundle = true
  minify = true

[build.processing.js]
  bundle = true
  minify = true

Text assets compress ~70%.

3. CDN Distribution

Static assets served from edge locations:

User in Tokyo โ†’ Tokyo CDN node (15ms)
vs.
User in Tokyo โ†’ US origin server (250ms)

16x faster response times!

4. Cache Headers

Aggressive caching for static assets:

headers
  for = "/css/*"
  [headers.values]
    Cache-Control = "public, max-age=31536000, immutable"

Graph Visualization Performance

The knowledge graph visualizer handles large datasets:

1. Canvas Rendering Mode

For graphs with 500+ nodes:

if (nodeCount > 500) {
  useCanvas();  // 10x faster than SVG
} else {
  useSVG();     // Better for small graphs
}

2. Quadtree Optimization

D3’s force simulation uses spatial indexing:

simulation.force('collision', 
  d3.forceCollide()
    .radius(20)
    .iterations(2)  // Reduce for performance
);

3. Filtering Instead of Re-rendering

// โŒ Recreate graph
function filterByTag(tag) {
  destroyGraph();
  const filtered = nodes.filter(n => n.tag === tag);
  createGraph(filtered);
}

// โœ… Hide/show nodes
function filterByTag(tag) {
  nodes.forEach(n => {
    n.style.opacity = n.tag === tag ? 1 : 0.1;
  });
}

Measuring Performance

Tools Used

  1. Lighthouse - Overall scores
  2. WebPageTest - Real-world testing
  3. Chrome DevTools - Detailed profiling
  4. Bundle Analyzer - Asset size breakdown

Key Metrics

Vitis achieves:

First Contentful Paint:  0.8s
Largest Contentful Paint: 1.2s
Time to Interactive:      1.5s
Total Blocking Time:      50ms
Cumulative Layout Shift:  0.01

All in the “Good” range for Core Web Vitals!

Performance Budget

Strict limits enforced:

Asset TypeBudgetActual
HTML20KB12KB
CSS30KB15KB
JavaScript50KB8KB
Fonts100KB45KB
Images200KB120KB
Total400KB200KB

We’re using only 50% of our budget!

Performance Anti-Patterns

Avoid These Mistakes

โŒ Loading all JS on every page

<!-- Don't do this -->
<script src="/js/graph.js"></script>  
<script src="/js/search.js"></script>
<script src="/js/analytics.js"></script>

โœ… Conditional loading

{{ if .Params.hasGraph }}
  <script src="/js/graph.js"></script>
{{ end }}

โŒ Unoptimized images

![](huge-uncompressed-image.png)

โœ… Hugo image processing

{{ $img := $img.Resize "800x webp q85" }}

โŒ Blocking resources in <head>

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

โœ… Async/defer attributes

<script src="analytics.js" defer></script>

Progressive Enhancement

Vitis works without JavaScript:

  1. Core content - Fully accessible with JS disabled
  2. Basic navigation - All links work
  3. Search - Degrades to site search
  4. Graph - Shows message: “Enable JS for interactive graph”

Enhanced features load progressively:

HTML only:        โญ๏ธโญ๏ธโญ๏ธ (usable)
+ CSS:            โญ๏ธโญ๏ธโญ๏ธโญ๏ธ (beautiful)
+ JS:             โญ๏ธโญ๏ธโญ๏ธโญ๏ธโญ๏ธ (fully interactive)

Mobile Performance

Special optimizations for mobile:

1. Reduced Motion

@media (prefers-reduced-motion: reduce) {
  * {
    animation: none !important;
    transition: none !important;
  }
}

Respects user preferences and saves battery.

2. Smaller Breakpoint Images

{{ $mobile := $img.Resize "400x webp q80" }}
{{ $desktop := $img.Resize "1200x webp q85" }}

<picture>
  <source media="(max-width: 640px)" srcset="{{ $mobile }}">
  <img src="{{ $desktop }}" alt="...">
</picture>

Mobile users download 1/3 the data.

3. Touch-Optimized Interactions

.interactive-element {
  min-width: 44px;   /* WCAG touch target size */
  min-height: 44px;
  touch-action: manipulation;  /* Removes 300ms delay */
}

The Results

Comparing Vitis to popular alternatives:

ThemeLoad TimeJS SizeLighthouse
Vitis0.8s8KB98
Theme A2.3s120KB72
Theme B1.8s85KB81
Theme C3.1s200KB65

Vitis is 2-4x faster than alternatives!

Implementation Checklist

Apply these optimizations to your site:

  • Enable Hugo minification
  • Configure Tailwind purge
  • Add lazy loading to images
  • Inline critical CSS
  • Use font-display: swap
  • Implement resource hints
  • Enable Gzip/Brotli
  • Set cache headers
  • Remove unused JavaScript
  • Optimize syntax highlighting
  • Test with Lighthouse
  • Monitor Core Web Vitals

Continuous Monitoring

Performance is ongoing:

# Run before every deploy
npm run test:performance

# Checks:
# - Bundle sizes within budget
# - Lighthouse score > 95
# - No new blocking resources
# - Image optimization

Future Optimizations

Exploring:

  • ๐Ÿ”„ Service Worker - Offline support
  • ๐Ÿ”„ Partial Hydration - Interactive islands
  • ๐Ÿ”„ WebP with AVIF fallback - Next-gen formats
  • ๐Ÿ”„ HTTP/3 - QUIC protocol benefits

Conclusion

Fast sites provide:

  • โœ… Better UX - Users stay longer
  • โœ… Higher rankings - Google rewards speed
  • โœ… More conversions - Speed = revenue
  • โœ… Lower costs - Less bandwidth

Vitis proves you can have it all: rich features, beautiful design, and blazing speed.

Learn More


Speed is a feature. Make it a priority from day one.

Share Article
Link Map
Pages Tags

Related Posts