Static Resources Overview
What are Static Resources?
Spry provides a built-in system for serving static assets like CSS, JavaScript, images, and fonts. The static resource system handles content negotiation, compression, and caching automatically.
Unlike traditional web frameworks that serve static files directly from disk, Spry's static resources are pre-compressed and can be embedded directly into your binary for single-binary deployments.
Types of Static Resources
Spry provides three implementations of the
StaticResource interface:
FileStaticResource
Reads pre-compiled .ssr (Spry Static Resource) files from
disk at runtime. These files contain the resource data along with
pre-compressed versions (gzip, zstd, brotli) and metadata.
- Loaded from
.ssrfiles generated by spry-mkssr - Contains all compression variants in a single file
- Includes SHA-512 hash for ETags
MemoryStaticResource
Holds static resource data entirely in memory. Useful for dynamically generated resources or when you want to load resources from a custom source.
- All data held in RAM
- Supports all compression formats
- Created programmatically at runtime
ConstantStaticResource
Embeds static resources directly into your binary at compile time. The resource data becomes part of your executable, enabling true single-binary deployments.
- Compiled into your binary
- Generated by spry-mkssr with
--valaflag - Zero runtime file I/O
The StaticResource Interface
All static resources implement the StaticResource interface,
which defines the contract for serving static content:
public interface StaticResource : Object {
// The unique name of this resource (e.g., "docs.css")
public abstract string name { get; }
// Returns the best encoding supported by the client
public abstract string get_best_encoding(Set<string> supported);
// Returns the ETag for a specific encoding
public abstract string get_etag_for(string encoding);
// Converts the resource to an HTTP result
public abstract HttpResult to_result(string encoding,
StatusCode status = StatusCode.OK)
throws Error;
}
The StaticResourceProvider Endpoint
Spry includes a built-in endpoint for serving static resources. The
StaticResourceProvider handles all the complexity of content
negotiation and caching.
Route Pattern
Static resources are served from the route:
/_spry/res/{resource}
Where {resource} is the name of the resource (e.g.,
docs.css, htmx.js).
Content Negotiation
The provider automatically selects the best compression format based on
the client's Accept-Encoding header. Supported encodings:
- gzip - Universal browser support
- zstd - Modern, high-performance compression
- br (Brotli) - Best compression ratios for text
- identity - No compression (always available)
ETag-Based Caching
Each resource generates an ETag based on its content hash and encoding.
The provider handles If-None-Match requests, returning
304 Not Modified when the client's cached version is current.
// ETag format: "{encoding}-{hash}"
// Example: "br-a1b2c3d4e5f6..."
// The provider checks If-None-Match automatically:
if (request.headers.get_or_empty("If-None-Match").contains(etag)) {
return new HttpEmptyResult(StatusCode.NOT_MODIFIED);
}
// Fresh content is returned with the ETag header
response.set_header("ETag", etag);
Using Resources in Templates
Spry provides the spry-res attribute for easily referencing
static resources in your HTML templates. This attribute automatically
generates the correct URL for your resource.
<!-- Stylesheets -->
<link rel="stylesheet" spry-res="docs.css">
<!-- JavaScript -->
<script spry-res="htmx.js"></script>
<script spry-res="htmx-sse.js"></script>
<!-- Images -->
<img spry-res="logo.png" alt="Logo">
<!-- Results in URLs like: -->
<!-- /_spry/res/docs.css -->
<!-- /_spry/res/htmx.js -->
The spry-res attribute works with any element that has
href or src attributes:
-
for stylesheets -
for JavaScript -
for images -
for media elements
How It Works
Build Time
Use spry-mkssr to generate .ssr files or Vala source files
Registration
Register resources via dependency injection
Request
Client requests /_spry/res/resource-name
Negotiation
Server selects best encoding based on Accept-Encoding
Response
Compressed content sent with ETag for caching