Faster Templates, Smarter Hydration: Performance Optimizations in djust 0.1.6
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 Type | Speedup |
|---|---|
| Text-heavy templates | 10-15% |
| Mixed content | 5-10% |
| Logic-heavy templates | 2-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-djust-lazy attribute to any LiveView element:
<!-- Hydrate when scrolled into viewport (default) -->
<div data-djust-view="comments" data-djust-lazy>
<div class="skeleton">Loading comments...</div>
</div>
<!-- Hydrate on first click -->
<div data-djust-view="editor" data-djust-lazy="click">
<button>Click to edit</button>
</div>
<!-- Hydrate on hover -->
<div data-djust-view="preview" data-djust-lazy="hover">
<span>Hover for details</span>
</div>
<!-- Hydrate during browser idle time -->
<div data-djust-view="analytics" data-djust-lazy="idle">
Loading analytics...
</div>
Each mode serves a different use case:
| Mode | Best For |
|---|---|
viewport (default) | Below-fold content, long pages, infinite scroll |
click | Expandable sections, modals, tabbed content |
hover | Tooltips, preview cards, hover menus |
idle | Low-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.
Related Posts
58 Ways to Break a VDOM (and Why Ours Didn't)
We wrote 58 torture tests targeting every weak spot in djust's virtual DOM diff engine: 50-level deep trees, 500-sibling lists, keyed shuffles, duplicate keys, and rapid-fire state updates. Everything passed. Here's what we tested, what we found, and why it matters.
Deep Dive: How djust's ORM JIT Pipeline Serializes Django Models at Rust Speed
djust's JIT serialization pipeline analyzes your templates at render time, generates optimized serializer code, eliminates N+1 queries, and falls back gracefully when Rust can't reach @property attributes. Here's exactly how it works, and what we did to make it fast.
How djust's Rust VDOM Achieves 10-100x Faster Rendering
A deep dive into djust's hybrid Python/Rust architecture and how the Rust-powered virtual DOM engine delivers exceptional performance.