Zig 0.17.0

Static files

Files in the public folder are served as they are: public/favicon.png is /favicon.png, and public/fonts/onest.woff2 is /fonts/onest.woff2. Nothing has to be registered.

They are answered before any route or middleware runs, so a static file never needs a login.

The code on this page is from Posts, the example app in examples/posts (source).

What goes there

Images, fonts, icons, and the stylesheet. In a project with pages, the build compiles src/styles.css into public/css/app.css, and the layout links to it:

html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{ title ?? "Posts" }</title>
    <link rel="icon" type="image/png" href="/favicon.png">
    <link rel="shortcut icon" href="/favicon.ico">
    <link rel="stylesheet" href="/css/app.css">
</head>
<body class="ui-page">
    <header class="ui-topbar">
        <a class="ui-brand" href="/posts">
            <svg width="14" height="32" viewBox="0 0 14 32" aria-hidden="true"><line x1="7" y1="0" x2="7" y2="22" stroke="#FF5300" stroke-width="2"/><circle cx="7" cy="25" r="6" fill="#FF5300"/></svg>
            Posts
        </a>
        <nav class="ui-topbar-links">
            if (current_user) {
            <a class="ui-btn ui-btn-ghost ui-who" href="/auth/account">{ current_user.name }</a>
            <form action="/auth/logout" method="post">
                <button class="ui-btn ui-btn-ghost" type="submit">Sign out</button>
            </form>
            } else {
            <a class="ui-btn ui-btn-ghost" href="/auth/login">Sign in</a>
            }
            if (!composing) {
            <a class="ui-btn ui-btn-primary" href="/posts/new">New post</a>
            }
        </nav>
    </header>

    { slot }

    <footer class="ui-footer">
        <span>Posts is an example app for Spider.</span>
        <a class="ui-link" href="https://github.com/llllOllOOll/spider">Built with Spider</a>
    </footer>
</body>
</html>

public/css/app.css is made by the build and is not kept in git. Files you put in public yourself are.

Caching

Every file is sent with an ETag, a fingerprint of its content, and browsers are told to check it before using their copy. When the file has not changed the answer is 304, with no body, so the file is not downloaded again.

For a file that never changes under its address, add ?v= and anything after it. The answer then tells the browser to keep the file for a year without asking. Posts does it for its fonts:

css
@import "tailwindcss";

/* The look of the app (ui-* classes): see ui.css. */
@import "./ui.css";

/* Icon sets: one @plugin per set. Manage with `spider icons add|remove <set>`. */
@plugin "../bin/icons/heroicons.mjs";

/* Fonts, served by the app itself. Licenses: public/fonts/OFL-*.txt */
@font-face {
    font-family: 'Bricolage Grotesque';
    font-style: normal;
    font-weight: 600 800;
    font-display: swap;
    src: url('/fonts/bricolage-grotesque.woff2?v=1') format('woff2');
}
@font-face {
    font-family: 'Onest';
    font-style: normal;
    font-weight: 400 600;
    font-display: swap;
    src: url('/fonts/onest.woff2?v=1') format('woff2');
}
@font-face {
    font-family: 'JetBrains Mono';
    font-style: normal;
    font-weight: 400 500;
    font-display: swap;
    src: url('/fonts/jetbrains-mono.woff2?v=1') format('woff2');
}

When such a file does change, change the number, and every browser fetches the new one.

Another folder

static_dir in spider.config.zig names the folder; ./public is the default. null serves no static files. See Configuration.

Limits

  • A folder address, like /fonts/, is not a listing: it answers 404.
  • An address cannot reach outside the folder: /../build.zig answers 404.