WebFront C++23
FR ↗GitHub ↗

CHAPTER 05 / WEBFRONT

Choosing an interface model

The facilities provided by the C++ DOM, forms and React adapter.

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.

Facilities introduced in version 0.6

Version 0.6.0 adds several ways to construct the presentation of a C++ application. A simple panel can be created directly in C++. A form can be generated from a description of its fields. A larger interface can be written in TypeScript with React.

The choice depends on the amount of presentation code required and where its description should be maintained. All three approaches can use the same application logic.

Building a panel in C++

The embedded fallback page contains an empty region named root. We shall call such a region an island: the page lends its contents to C++ code.

ui.document() provides access to the connection’s document. The following code, placed before app.show(), creates a button and changes its text on a click. Writes are batched before being sent to the browser.

Document operations must execute on the server context: in a callback, in onUIStarted, or in a WebFront task. Reloading the page creates a new document.

C++23
app.onUIStarted([](auto ui) {
    auto doc = ui.document();
    auto root = doc.island();
    auto button = doc.element("button");
    auto label = doc.text("Click me");
    button.append(label);
    button.listen("click", [label](std::string) { label.setText("Clicked"); });
    root.append(button);
});

Describing form fields

A descriptor collects field names, labels, bounds and accessors. Three functions use this description to produce different representations:

  • forms::form() constructs an editable form.
  • forms::inspector() constructs a read-only view.
  • forms::typescriptDeclaration() produces a TypeScript declaration for use with wf check.

The example uses C++23 descriptors. A separate C++26 reflection layer is qualified with GCC 16. Generating a declaration does not change the types supported by the binary bridge.

C++23
#include <webfront/components/forms/Form.hpp>
struct Settings { int speed{5}; bool wrap{true}; };
auto description = webfront::forms::Description<Settings>{
    .name = "Settings",
    .fields = {
        webfront::forms::field("speed", &Settings::speed, "Speed",
                              webfront::forms::Bounds{1, 10}),
        webfront::forms::field("wrap", &Settings::wrap, "Wrap")
    }
};
// Use the description with forms::form(), forms::inspector(),
// or forms::typescriptDeclaration().

Combining React with a C++ panel

The optional @webfront/react package supplies createStore, useStore and Island. A store sends C++ state snapshots, coalesced for each browser. An Island component lends an empty subtree to C++.

Ownership of that subtree must remain explicit. React must not modify the nodes created there by C++. Before unmounting the component, both parties must follow the release protocol described in the React guide.

Connections and events

app.broadcast(name, options)(...) sends a call to ready browsers, sharing the encoded frame. maxPendingWrites can retain only the latest held state for a slow browser. This is useful for telemetry that need not display every intermediate state. forEachUI visits ready connections.

A UI value identifies the application, connection and connection generation. An old value therefore cannot reach a later connection that reuses the same identifier. Never use it after the application has been destroyed.

A task can express a sequence of C++ dialogues by waiting for an event with co_await node.next(...). The task remains owned by WebFront.

CMake options in version 0.7

From version 0.7.0, testing and instrumentation options require the WEBFRONT_ prefix. Use WEBFRONT_ENABLE_TESTING, WEBFRONT_ENABLE_FUZZING, WEBFRONT_ENABLE_COVERAGE and WEBFRONT_ENABLE_SANITIZER_*.

The old ENABLE_* variables, including existing cache entries, no longer configure WebFront. Set the new options explicitly when upgrading.

The library and development environment have independent versions: library 0.7.0 pins environment 0.6.3. The APIs remain experimental.

SYSTEM TERMINAL
# WebFront 0.7.0: use the prefixed options explicitly.
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release \
  -DWEBFRONT_EMBED_CEF=OFF -DWEBFRONT_ENABLE_TESTING=ON
cmake --build build --parallel 2
ctest --test-dir build --output-on-failure

Check your understanding

Which option enables WebFront 0.7.0 tests?