Home Features Docs Blog Security Examples Quick Start

Faster Templates, Smarter Hydration: Performance Optimizations in djust 0.1.6

djust Team | | 4 min read
Visualization of template optimization with branching nodes converging into optimized paths

Why Performance Matters for Server-Side Rendering

In a world where users expect instant interactions, every millisecond counts. Traditional server-side rendering can feel sluggish compared to client-side frameworks, but it doesn't have to be that way. With djust 0.1.6, we've pushed the boundaries of what's possible with server-rendered reactive applications.

This release introduces four significant performance improvements that work together to make your djust applications faster and more memory-efficient. Let's dive into each one.

AST Optimization: 5-15% Faster Template Rendering

Every time djust renders a template, it first parses it into an Abstract Syntax Tree (AST). In previous versions, the parser would create separate nodes for each piece of static text, even when they appeared consecutively.

Consider this template fragment:

<div class="card">
    <!-- User profile card -->
    <span class="name">{{ user.name }}</span>
</div>

Previously, this would create multiple Text nodes and a Comment node that produce no output. Now, the new optimize_ast() function automatically:

  • Merges adjacent Text nodes into a single node, reducing allocations
  • Removes Comment nodes during optimization (since they produce no output)
  • Recursively optimizes children in If, For, Block, and With nodes

The result? Fewer memory allocations during rendering and a 5-15% improvement in render time, with text-heavy templates seeing the biggest gains.

Template TypeSpeedup
Text-heavy templates10-15%
Mixed content5-10%
Logic-heavy templates2-5%

Lazy Hydration: 20-40% Memory Reduction

Not every LiveView element needs to be interactive immediately. A dashboard might have charts below the fold that the user may never scroll to. A product page might have expandable sections that most users never open.

Lazy hydration allows you to defer WebSocket connections until they're actually needed. Instead of establishing connections for all LiveView elements on page load, you can specify when each element should "wake up."

Add the data-live-lazy attribute to any LiveView element:

<!-- Hydrate when scrolled into viewport (default) -->
<div data-live-view="comments" data-live-lazy>
    <div class="skeleton">Loading comments...</div>
</div>

<!-- Hydrate on first click -->
<div data-live-view="editor" data-live-lazy="click">
    <button>Click to edit</button>
</div>

<!-- Hydrate on hover -->
<div data-live-view="preview" data-live-lazy="hover">
    <span>Hover for details</span>
</div>

<!-- Hydrate during browser idle time -->
<div data-live-view="analytics" data-live-lazy="idle">
    Loading analytics...
</div>

Each mode serves a different use case:

ModeBest For
viewport (default)Below-fold content, long pages, infinite scroll
clickExpandable sections, modals, tabbed content
hoverTooltips, preview cards, hover menus
idleLow-priority content, preloading

For programmatic control, use the JavaScript API:

// Force hydration of a specific element
window.djust.lazyHydration.hydrateNow(element);

// Check if element is pending hydration
const isPending = window.djust.lazyHydration.isPending(element);

// Hydrate all pending elements at once
window.djust.lazyHydration.hydrateAll();

TurboNav Integration: Seamless Navigation

Single-page application navigation (like Turbo Drive or Hotwire) provides a smooth browsing experience, but it can conflict with frameworks that expect full page loads. djust 0.1.6 introduces full TurboNav compatibility.

When navigating between pages:

  • Existing WebSocket connections are properly disconnected
  • LiveView state is cleaned up to prevent memory leaks
  • New connections are established for the incoming page's LiveView elements
  • Lazy hydration state is reset for the new page

To enable TurboNav support, include the djust client script in your base template so it's available on all pages:

<!-- base.html -->
<script src="{% static 'djust/client.js' %}"></script>

A double-load guard prevents issues if the script is included multiple times, and the turbo:load event handler automatically reinitializes djust after each navigation.

Whitespace Preservation: Proper Code Formatting

When rendering code snippets or preformatted text, whitespace matters. Previous versions could inadvertently collapse or modify whitespace during VDOM patching.

djust 0.1.6 now properly preserves all whitespace inside:

  • <pre> elements (preformatted text)
  • <code> elements (inline and block code)
  • <textarea> elements (form inputs)
  • <script> elements (inline JavaScript)
  • <style> elements (inline CSS)

This ensures that code examples, poetry, ASCII art, and any other whitespace-sensitive content renders exactly as intended.

Bonus: Form Validation Fix

We also fixed a subtle bug where dynamically inserted elements (like form validation error messages) could cause ID collisions. The new parse_html_continue() function maintains ID counter continuity across parsing operations, ensuring that every element gets a unique identifier.

Upgrading to 0.1.6

Upgrading is simple:

pip install --upgrade djust

All optimizations are applied automatically. No code changes required. Your existing templates will render faster, and you can opt into lazy hydration for additional memory savings.

What's Next

We're continuing to push the performance envelope. Upcoming releases will include component-level template caching, parallel batch rendering for Rust components, and automatic query optimization based on template analysis.

Have feedback or questions? Join us on GitHub or check out our documentation for more details on these optimizations.

Share this post

Related Posts