March Docs

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

typeStaticConfigStaticConfig = StaticConfig(String, String)#

Functions

fnconfigconfig(root : String) : StaticConfig#

Create a StaticConfig that serves files from root with no URL prefix.

fnconfig_with_prefixconfig_with_prefix(root : String, prefix : String) : StaticConfig#

Create a StaticConfig that serves files from root, stripping the given URL prefix.

fncss_tagcss_tag(filename : String) : String#

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\" />"
fnjs_tagjs_tag(filename : String) : String#

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>"
fnlooks_fingerprintedlooks_fingerprinted(filename : String) : Bool#

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")     -- true
fnmime_typemime_type(path : String) : String#

Return 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"
fnpathpath(filename : String) : String#

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)
fnserveserve(root : String) : Conn -> Conn#

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"))
fnserve_with_configserve_with_config(cfg : StaticConfig) : Conn -> Conn#

Return a plug that serves static files using the given StaticConfig.

fnserve_with_prefixserve_with_prefix(root : String, prefix : String) : Conn -> Conn#

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