Static
Bastion.Static — static file serving middleware and asset tag helpers.
Serves files from a directory on disk. Designed to be inserted into a Bastion pipeline before the router so that asset requests are handled without hitting application code.
Cache behaviour:
- Files with an 8-character content-hash suffix (e.g. app-a1b2c3d4.css)
are served with "public, max-age=31536000, immutable".
- All other files get "public, max-age=3600".
- ETag headers are computed from mtime + size (via File.stat).
- Conditional GET (If-None-Match) is honoured; 304 is returned when
the client's ETag matches.Asset manifest: Forge writes priv/static/manifest.json mapping logical asset names to their fingerprinted URLs. Static.path/1, Static.css_tag/1, and Static.js_tag/1 consult this manifest to produce correct URLs.
Usage:
HttpServer.new(4000)
|> HttpServer.plug(Static.serve("priv/static"))
|> HttpServer.plug(Router.to_plug(router))
|> HttpServer.listen()Types
Functions
Create a StaticConfig that serves files from root with no URL prefix.
Create a StaticConfig that serves files from root, stripping the given URL prefix.
Return an HTML <link rel="stylesheet"> tag pointing at the fingerprinted URL for the given CSS asset.
Example:
Static.css_tag("css/app.css")
-- "<link rel=\"stylesheet\" href=\"/static/css/app-a1b2c3d4.css\" />"Return an HTML <script src="..."> tag pointing at the fingerprinted URL for the given JS asset.
Example:
Static.js_tag("bastion.js")
-- "<script src=\"/static/bastion.js\"></script>"Return true if filename appears to carry a Forge content-hash suffix.
A fingerprinted filename ends with "-XXXXXXXX.ext" where XXXXXXXX is
exactly 8 characters (the first 8 hex digits of the content hash).
Example:
Static.looks_fingerprinted("app-a1b2c3d4.css") -- true
Static.looks_fingerprinted("app.css") -- false
Static.looks_fingerprinted("march-islands.js") -- false (7-char stem "islands")
Static.looks_fingerprinted("c-12345678.wasm") -- trueReturn the MIME type for a file path based on its extension.
Example:
Static.mime_type("priv/static/app.css") -- "text/css"
Static.mime_type("priv/static/logo.png") -- "image/png"
Static.mime_type("counter.wasm") -- "application/wasm"
Static.mime_type("data.bin") -- "application/octet-stream"Return the URL for a static asset, looking up the fingerprinted path from the asset manifest at priv/static/manifest.json. Falls back to /static/{filename} when the manifest is absent or the key is not found.
Manifest format (written by Forge at build time):
{
"css/app.css": "/static/css/app-a1b2c3d4.css",
"bastion.js": "/static/bastion-e5f6g7h8.js"
}
Example:
Static.path("css/app.css") -- "/static/css/app-a1b2c3d4.css" (manifest hit)
Static.path("favicon.ico") -- "/static/favicon.ico" (fallback)Return a plug that serves static files from the given directory.
Requests that resolve to a readable file are served and the conn is halted.
Unmatched requests (file not found) are passed through unchanged so the
router can handle them.
Example:
HttpServer.plug(server, Static.serve("priv/static"))Return a plug that serves static files using the given StaticConfig.
Return a plug that serves static files from root, stripping prefix from the URL.
Example:
Static.serve_with_prefix("priv/static", "/static")
-- A request for /static/app.css serves priv/static/app.css