Asset Pipeline
The asset pipeline bundles your JavaScript and CSS with Bun, fingerprints the output files for cache busting, and generates a manifest so your templates can reference the correct URLs. A companion middleware serves the fingerprinted files and resolves asset paths at runtime.
Quick setup
Section titled “Quick setup”-
Generate the starter files
Terminal window pidgn assets setupThis creates an
assets/directory with starterapp.jsandapp.cssfiles, apackage.json, and abunfig.toml. -
Install JavaScript dependencies
Terminal window bun install -
Build the assets
Terminal window pidgn assets buildBun minifies your source files, writes them to
public/assets/, and generates fingerprinted copies alongside anassets-manifest.json.
How it works
Section titled “How it works”When you run pidgn assets build:
- Bun bundles
assets/app.jsintopublic/assets/app.js(minified). assets/app.cssis copied topublic/assets/app.css.- Each output file is hashed with FNV-1a and a fingerprinted copy is created (e.g.
app-2b3e914a.js). - An
assets-manifest.jsonis written mapping original names to fingerprinted names.
The manifest format:
{ "app.js": "app-2b3e914a.js", "app.css": "app-7f1dc3e8.css"}Configuration
Section titled “Configuration”Add the assets middleware to your pipeline to load the manifest and serve fingerprinted files:
const App = pidgn.Router.define(.{ .middleware = &.{ pidgn.errorHandler(.{}), pidgn.logger, pidgn.gzipCompress(.{}), pidgn.assets(.{ .manifest_path = "public/assets/assets-manifest.json", .prefix = "/static/assets", }), pidgn.staticFiles(.{ .dir = "public", .prefix = "/static" }), }, .routes = &.{ ... },});AssetConfig
Section titled “AssetConfig”| Option | Type | Default | Description |
|---|---|---|---|
manifest_path | []const u8 | "public/assets/assets-manifest.json" | Path to the manifest JSON file generated by pidgn assets build. |
prefix | []const u8 | "/static/assets" | URL prefix prepended to resolved asset paths. |
The middleware lazily loads the manifest on the first request. Once loaded, it is cached globally for the lifetime of the process.
Using asset paths in templates
Section titled “Using asset paths in templates”Use the assetPath function to resolve an asset name to its fingerprinted URL:
const asset_url = pidgn.assetPath("app.js");// Returns "/static/assets/app-2b3e914a.js"In a pidgn template:
<script src="{{ assetPath "app.js" }}"></script><link rel="stylesheet" href="{{ assetPath "app.css" }}">If the manifest has not been loaded or the asset name is not found, assetPath returns the name unchanged.
Development vs production
Section titled “Development vs production”For development, use watch mode to rebuild on every change:
pidgn assets watchThis starts Bun in watch mode and regenerates the manifest whenever a source file changes.
For production, run a single build:
pidgn assets buildThe fingerprinted filenames ensure browsers fetch new versions after a deploy, while unchanged files remain cached.
Project structure
Section titled “Project structure”After running pidgn assets setup and pidgn assets build, your project looks like this:
my_app/ assets/ app.js # Source JavaScript app.css # Source CSS public/ assets/ app.js # Bundled output app.css # Copied output app-2b3e914a.js # Fingerprinted JS app-7f1dc3e8.css # Fingerprinted CSS assets-manifest.json package.json bunfig.toml src/ main.zigNext steps
Section titled “Next steps”- Assets CLI — full command reference for
setup,build, andwatch - Live Reload — automatic browser refresh during development
- Server-Side Rendering — render React components on the server
- Static Files — serve non-bundled assets from a directory
- Middleware — understand the middleware pipeline