Volume II / CHAPTER 05
For understanding and contributing
Pages and tools
The browser requests a page. It may come from disk, the program itself or another provider.
Notation conventions
Function names, types, commands, options and filenames appear in monospace, for example describe, wf test or main.cpp. Italics introduce a term at its definition. Code blocks give the fragments to enter; the preceding text states their location and prerequisites.
Finding a page’s bytes
In the development version, we edit a file and the browser displays the result. In the distributed version, the same page may be contained in the executable. The HTTP server need not know the difference to answer the request.
It asks a provider whose open(std::filesystem::path) operation returns a std::optional<fs::File>. If the provider does not know the resource, it returns no result. fs::Multi lets us try several providers in a defined order; the first answer supplies the file.
We can thus choose storage without changing page URLs. That choice does not remove lifetime questions: if a file borrows bytes, their owner must retain them throughout the read.
Provider order matters
For an application image, giving the development directory precedence is useful: the file we just edited appears immediately. For bridge code, the same choice would be dangerous. An old WebFront.js left in that directory might no longer match the C++ codec.
The default composition therefore protects bridge modules. It then consults permitted providers and the development document root before the fallback page. If no document root was supplied, it opens no local files.
The core’s small resource set is maintained as a closed list. MinimalCoreAssets and the ADR-016 budget help us notice an accidental dependency. Adding a tool to that list needs an architectural decision, not merely another include.
The tools need not travel everywhere
To develop the interface, we need the compiler and test tools. Someone using the finished application usually does not. Bootstrap lets us load a pinned developer distribution separately, after checking its integrity.
Within that environment, package resolution, esbuild-wasm compilation, type checking and tests run in the browser. The project retains exact versions and integrity data so that another machine can obtain the same dependencies.
The WebFront repository uses these tools too, through --manifest-dir js/developer. We therefore need to rebuild the environment from a known bootstrap. When publishing, we first verify the new archive at its distribution address; the pin can then be changed to select it.
Two kinds of generated header
We shall find generated resources in two places while reading the repository. They are easy to confuse at first.
Core sources live in js/core/. CMake tools turn them into versioned headers consumed by ordinary C++ builds. Tests check that these headers still correspond to the readable sources.
Our application’s resources follow another path. wf embed compiles its interface and produces its C++ provider. That provider lets the application find its pages without loading development tools.
In both cases, the server still has to choose an acceptable encoding and apply decoding limits. A correct filename tells us neither whether its bytes are valid nor how much space they will occupy after decoding.
Check your understanding