-
Notifications
You must be signed in to change notification settings - Fork 1
Assets
Compile-time static-asset bundling. Anything you drop under
<app>/assets/ is baked into the binary at tep build time and
served straight from memory — no separate static-file server, no
disk reads at runtime, no path-traversal class of bug.
my-app/
├── app.rb
└── assets/
├── styles.css
├── logo.svg
├── htmx.min.js
└── img/
└── header.png
Build:
tep build app.rbAt build, bin/tep walks <app>/assets/**/*, computes each path
relative to the assets root, and emits a Tep::Assets._add(path, body, mime) call per file. The resulting binary contains the asset
bytes in its read-only data segment.
The framework's request dispatcher checks Tep::Assets.serve(path, response) before route table lookup. Hits short-circuit:
GET /styles.css → asset → 200 with bytes from memory
GET /img/header.png → asset → 200 with bytes from memory
GET /users/42 → not an asset → falls through to your routes
You don't write any handler code. The path-to-asset mapping is
<request.path> matched against /<filename> (the leading /
matters).
Inferred from the extension at build time:
| Extension | Content-Type |
|---|---|
.html .htm
|
text/html |
.css |
text/css |
.js |
application/javascript |
.json |
application/json |
.svg |
image/svg+xml |
.png |
image/png |
.jpg .jpeg
|
image/jpeg |
.gif |
image/gif |
.txt |
text/plain |
.ico |
image/x-icon |
.woff / .woff2
|
font/woff / font/woff2
|
| anything else | application/octet-stream |
Override per-file at the source level by editing the assets table post-build is not supported — if the default's wrong, post-process the file to a known extension, or wrap the asset in a real route.
Rare but possible — e.g. inlining an SVG into an HTML template:
get '/' do
if Tep::Assets.has?("/logo.svg")
logo = Tep::APP.asset_bodies["/logo.svg"]
"<div>" + logo + "</div>"
else
"logo missing"
end
endTep::Assets.has?(path) returns whether the asset was bundled;
the byte content lives in Tep::APP.asset_bodies[path] (and the
mime in Tep::APP.asset_mimes[path]).
my-app/
├── app.rb
└── assets/
├── index.html
├── bundle.js
└── styles.css
require 'sinatra'
get '/' do
redirect '/index.html'
end
# Everything else is served straight from the asset bundle.The framework sets Cache-Control: public, max-age=3600 on
assets by default (1 hour). Re-deploying the binary produces a new
asset table; bump the URL or override the header if you want a
longer lifetime. If you want a different policy, write your own
route that overrides:
get '/styles.css' do
response.headers["Cache-Control"] = "no-cache"
Tep::APP.asset_bodies["/styles.css"]
end(Caveat: a hand-written route shadows the asset table for that path.)
- Binary size grows linearly with asset bytes. A 5 MB image bundled in produces a 5 MB+ binary. For large static content, bundle a manifest and pull at runtime from object storage instead.
-
No build-time minification. If you want minified CSS / JS,
run the minifier as a pre-step (e.g.
npm run buildwrites intoassets/). -
Paths are case-sensitive everywhere. Linux is case-sensitive
by default; URLs match exactly. Don't ship
/Logo.pngand reference/logo.pngfrom your HTML. -
No directory listing. Requesting
/img/404s. There's no index.html magic; if you want one, route it explicitly.