Chapter 48 / 51
Volume 5 · Extensions, Ops & Projects

Single-file deployment

The name says "single binary" — this chapter cashes that check: config, static site, C sources and TLS certificates all packed into one exe. Copy it away and it's deployed.

Overview

Positioning: the endpoint of every deployment shape. All applications built in earlier chapters (xs.json + sources + wwwroot + certificates) converge here into a single file — a site VFS (app pack) appended to the xs binary, auto-detected on zero-argument startup. Outputs tagged live-run verified come from actually running the packed exe.

48.1 Pack and run

xs ships its own packing subcommand — no external tools needed (no Python dependency):

Live run · pack in three steps
# pack (the site directory must contain xs.json; base = the running xs itself)
xs.exe pack site/ -o app.exe
[pack] base 6202368 bytes + 30 files, compressing...
[pack] 30/30 compressed
[pack] app.exe: 30 entries (lzma 28, store 2), archive 575363 bytes

# deploy: copy this one file to the target machine, zero-arg start
app.exe
[xs] app pack: 30 entries
[xs] config loaded: app-pack:xs.json (1 servers)
[xs] http host 'site' static root '...\wwwroot' on disk missing, serving from app pack

Compression is per-entry LZMA (auto-STORE when there is no gain) — the demo site packs 1.7 MB of text into 542 KB. Combined with the webview extension (the 14th library), the artifact becomes a double-click desktop application.

48.2 Disk priority: hot-fix without repacking

Single-file mode has exactly one file-read rule: disk wins, the pack is the fallback.

ScenarioOn-disk wwwroot/Result
Pure packabsentevery entry served from the pack (pRoot becomes an empty path)
Hot-fixempty dir + override filesoverride files come from disk, the rest fall back to the pack
Restoreoverride file deletedthat file automatically reverts to the packed version
Certificates work the same way: after renewal, drop the new cert.pem next to the exe and it takes effect — path reads go through the unified entry point (disk first, pack fallback), so writing a file naturally invalidates the stale packed copy. Pair it with xsTlsRefresh (the hot certificate-swap API) for a fully automated renewal loop.

Note: the disk-override scenario requires the wwwroot directory to exist at startup (the static root handle is opened once) — create an empty directory before launch.

48.3 Toolchain & debugging

Live run · the four pack commands
xs pack --list app.exe            # entry listing (method/size/CRC/path)
xs pack --extract app.exe -d out/  # unpack for forensics (diff = byte-identical to the source)
xs pack --strip app.exe -o orig.exe # restore the pristine binary (cmp = byte-identical)
app.exe --no-vfs                   # ignore the app pack, debug in directory mode

The archive format is guarded by four CRC levels (trailer → archive header → index → entry after decompression); a corrupt pack is rejected at load time. Repacking automatically strips the previous pack (stripped only after CRC confirmation, to protect unrelated binaries). The field-by-field format spec lives in the repo at docs/站点VFS设计.md.

48.4 Memory & threading model

  • Index: loaded once at startup, immutable — lock-free concurrent binary search across workers
  • Content: lazily decompressed on first access and cached for the process lifetime (the whole 1.7 MB demo site is the ceiling; cold files never occupy memory)
  • Compressed data region: never enters memory — read by offset from the exe file, heat left to the OS file cache
  • Startup cost: probing reads the last 24 bytes of itself; zero cost without a pack

Common mistakes

Pit: disk override has no effectThe wwwroot directory must exist at startup (the static root handle is opened once) — mkdir an empty directory before launch, and only then do runtime-delivered files become visible to the disk layer.
Pit: the repacked exe doubled in sizepack strips the old pack automatically, but if the base exe carries a pack whose CRC fails it is treated as packless — restore with --strip first, or make sure the base is a clean build artifact.
Pit: dev_inc can't find headersPacked source headers mount under the /xs/site/<relative path> virtual root; dev_inc absolute paths get the appPath prefix stripped and mapped — check that entry paths in pack --list match the config (case-sensitive).

Exercises

Basic
Pack the Volume-2 companion static site, confirm the entry count with --list, then --strip and verify byte-identity with cmp.
Intermediate
After packing, drop an overriding index.html next to the exe and walk the three scenarios: disk priority, then delete-to-restore.
Challenge
Pack an openssl self-signed certificate, start https and verify with curl -k that the certificate is decompressed from the pack (hint: chapter 12).

Summary

pack site/ -o app.exe = single-file deployment · disk wins, the pack falls back = hot-fix without repacking · --list / --extract / --strip = built-in tooling · --no-vfs = directory-mode debugging · per-entry LZMA + four-level CRC = the format floor