6.4 KiB
CLIP Template System Refactoring
- Overview
- What Changed
- New Template Utilities
- Template Changes
- Route Handler Changes
- Benefits
- JavaScript Updates
- Testing Checklist
- Future Enhancements
- Related TODO Items
- References
Overview
This document describes the refactoring of Asteroid Radio's template system to use proper CLIP machinery with centralized template management, caching, and consistent rendering patterns.
What Changed
Before: Inconsistent Implementation
- Manual template loading with
plump:parseandalexandria:read-file-into-stringin every route - Keyword arguments passed directly to
clip:process-to-string - No template caching - files read on every request
- Duplicate template loading code across routes
- Custom
data-textattribute processor defined in main file
After: Proper CLIP System
- Centralized template utilities in
template-utils.lisp - Template caching for better performance (templates loaded once)
- Consistent
render-template-with-plistfunction across all routes - Custom
data-textattribute processor properly organized - CLIP's standard keyword argument approach
New Template Utilities
File: template-utils.lisp
Template Caching
*template-cache*- Hash table for parsed template DOMsget-template- Load and cache templates by nameclear-template-cache- Clear cache during development
Rendering Functions
-
render-template-with-plist- Main rendering function using plist-style keyword arguments- Accepts template name and keyword arguments
- Passes arguments directly to CLIP's
process-to-string - CLIP makes values available via
(clip:clipboard key-name)
CLIP Attribute Processor
-
data-text- Custom attribute processor for text replacement- Usage:
<span data-text="key-name">Default Text</span> - Replaces element text content with clipboard value
- This is CLIP's standard approach for custom processors
- Usage:
Template Changes
Templates Remain Unchanged
Templates continue to use data-text attributes (CLIP's standard for custom processors):
template/admin.chtmltemplate/front-page.chtmltemplate/player.chtmltemplate/login.chtml
Template Attribute Usage
<!-- Templates use data-text for dynamic content -->
<title data-text="title">🎵 ASTEROID RADIO 🎵</title>
<h1 data-text="station-name">🎵 ASTEROID RADIO 🎵</h1>
<p class="status" data-text="server-status">🟢 Running</p>
<span data-text="track-count">0</span>
Note: The data-text attributes remain in the rendered HTML output. This is normal CLIP behavior - the attribute is processed and content is replaced, but the attribute itself is not removed.
Route Handler Changes
Updated Files
asteroid.lisp- Front page, admin, player routesauth-routes.lisp- Login route
Example Change
;; Before - Manual template loading in every route
(define-page front-page #@"/" ()
(let ((template-path (merge-pathnames "template/front-page.chtml"
(asdf:system-source-directory :asteroid))))
(clip:process-to-string
(plump:parse (alexandria:read-file-into-string template-path))
:title "🎵 ASTEROID RADIO 🎵"
:station-name "🎵 ASTEROID RADIO 🎵")))
;; After - Centralized template rendering with caching
(define-page front-page #@"/" ()
(render-template-with-plist "front-page"
:title "🎵 ASTEROID RADIO 🎵"
:station-name "🎵 ASTEROID RADIO 🎵"))
How It Works
render-template-with-plistcallsget-templateto load/cache the template- Template is loaded once and cached in
*template-cache* - Keyword arguments are passed directly to
clip:process-to-string - CLIP's
data-textprocessor replaces content using(clip:clipboard key-name)
Benefits
- Performance - Template caching reduces file I/O
- Consistency - All routes use the same rendering approach
- Maintainability - Centralized template logic
- Standards Compliance - Uses CLIP's intended design patterns
- Extensibility - Easy to add new attribute processors
- Debugging - Clear separation between template loading and rendering
JavaScript Updates
JavaScript selectors remain unchanged - they continue to use data-text attributes:
// JavaScript uses data-text attributes to find and update elements
document.querySelector('[data-text="now-playing-artist"]').textContent = artist;
document.querySelector('[data-text="now-playing-track"]').textContent = track;
document.querySelector('[data-text="listeners"]').textContent = listeners;
Testing Checklist
To verify the refactoring works correctly:
- Build executable with
make - Restart Asteroid server
- Visit front page (/) - verify content displays correctly
- Verify template caching is working (templates loaded once)
- Visit admin page (/admin) - verify status indicators work
- Visit player page (/player) - verify player loads
- Test login (/login) - verify error messages display
- Check browser console for JavaScript errors
- Verify "Now Playing" updates work
- Test track scanning and playback
Test Results
- ✅ Templates render correctly with
data-textattributes - ✅ Content is properly replaced via CLIP's clipboard system
- ✅ Template caching reduces file I/O operations
- ✅ All routes use consistent
render-template-with-plistfunction
Future Enhancements
Potential improvements to the template system:
- Template Composition - Add support for including partial templates
- Template Inheritance - Implement layout/block system for shared structure
- Hot Reloading - Auto-reload templates in development mode when files change
-
Additional Processors - Create more custom attribute processors as needed:
data-iffor conditional renderingdata-loopfor iterating over collectionsdata-attrfor dynamic attribute values
- Template Validation - Add linting/validation tools to catch errors early
Related TODO Items
This refactoring completes the following TODO.org item:
- Templates: move our template hydration into the Clip machinery
What Was Accomplished
- ✅ Centralized template processing utilities
- ✅ Implemented template caching for performance
- ✅ Standardized rendering approach across all routes
- ✅ Properly organized CLIP attribute processors
- ✅ Maintained CLIP's standard patterns and conventions
References
- CLIP Documentation: https://shinmera.github.io/clip/
- Plump Documentation: https://shinmera.github.io/plump/
- Radiance Framework: https://shirakumo.github.io/radiance/