mirror of
https://github.com/alexhopeoconnor/DFTE.git
synced 2026-10-04 04:28:10 +10:00
docs: refine template engine guides and validation
This commit is contained in:
@@ -33,3 +33,4 @@ jobs:
|
||||
python-version: '3.11'
|
||||
- run: python -m pip install --upgrade platformio==6.1.19
|
||||
- run: ./scripts/test.sh compile --platform ${{ matrix.platform }}
|
||||
- run: ./scripts/test.sh examples --platform ${{ matrix.platform }}
|
||||
|
||||
@@ -18,7 +18,9 @@ jobs:
|
||||
python-version: '3.11'
|
||||
- run: python -m pip install --upgrade platformio==6.1.19
|
||||
- run: ./scripts/test.sh compile --platform esp8266
|
||||
- run: ./scripts/test.sh examples --platform esp8266
|
||||
- run: ./scripts/test.sh compile --platform esp32
|
||||
- run: ./scripts/test.sh examples --platform esp32
|
||||
- run: ./scripts/check-docs.sh
|
||||
- run: ./scripts/prepare-release.sh "$GITHUB_REF_NAME"
|
||||
- run: ./scripts/release-notes.sh "$GITHUB_REF_NAME" > "$RUNNER_TEMP/release-notes.md"
|
||||
|
||||
@@ -1,25 +1,18 @@
|
||||
# Device Framework Template Engine
|
||||
|
||||
DFTE streams HTML and text for ESP8266 and ESP32 without constructing a giant response in RAM. It combines PROGMEM templates, live getters, nested layouts, conditions, and iterators with request-safe asynchronous HTTP rendering.
|
||||
DFTE streams HTML and text from ESP8266 and ESP32 firmware without constructing a complete response in RAM. Store layouts in PROGMEM, resolve changing values through getters, and render fixed-size chunks directly to serial or an asynchronous HTTP response.
|
||||
|
||||
## Why use it
|
||||
|
||||
- **Predictable memory:** render fixed-size chunks instead of one large `String`.
|
||||
- **Reusable templates:** keep layouts, partials, CSS, and HTML in flash.
|
||||
- **Live device data:** resolve values from getters only when a chunk is rendered.
|
||||
- **Safe async responses:** use one render context per HTTP request while sharing one prepared registry.
|
||||
|
||||
## Try it
|
||||
## Render a first template
|
||||
|
||||
```cpp
|
||||
#include <TemplateEngine.h>
|
||||
|
||||
static const char PAGE[] PROGMEM = "<h1>%TITLE%</h1>";
|
||||
Serial.begin(115200);
|
||||
PlaceholderRegistry registry;
|
||||
TemplateContext context;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
registry.registerProgmemData(PSTR("%TITLE%"), PSTR("Hello DFTE"));
|
||||
registry.registerProgmemTemplate(PSTR("%PAGE%"), PAGE);
|
||||
context.setRegistry(®istry);
|
||||
@@ -34,14 +27,23 @@ void loop() {
|
||||
}
|
||||
```
|
||||
|
||||
## Featured examples
|
||||
Build [Hello Placeholder](examples/HelloPlaceholder/) to see the rendered result over serial.
|
||||
|
||||
| Goal | Example |
|
||||
## Choose an example
|
||||
|
||||
| Example | What you will build |
|
||||
| --- | --- |
|
||||
| Smallest placeholder render | [HelloPlaceholder](examples/HelloPlaceholder/) |
|
||||
| Layouts, partials, and conditions | [NestedLayouts](examples/NestedLayouts/) |
|
||||
| Async HTTP streaming | [StreamingAsync](examples/StreamingAsync/) |
|
||||
| Dashboard, iterators, and telemetry | [AsyncDashboardDemo](examples/AsyncDashboardDemo/) |
|
||||
| [Hello Placeholder](examples/HelloPlaceholder/) | the smallest registry, context, and serial-rendering flow |
|
||||
| [Nested Layouts](examples/NestedLayouts/) | reusable partials, conditions, and iterator sections |
|
||||
| [Streaming Async](examples/StreamingAsync/) | a streamed ESPAsyncWebServer response over a SoftAP |
|
||||
| [Async Dashboard Demo](examples/AsyncDashboardDemo/) | a live dashboard with iterator rows and captive-portal access |
|
||||
|
||||
## Why DFTE
|
||||
|
||||
- **Bounded response memory:** render fixed-size chunks instead of allocating one large `String`.
|
||||
- **Flash-resident layouts:** keep templates, CSS, and shared fragments in PROGMEM.
|
||||
- **Live values:** resolve dynamic information only as the active response needs it.
|
||||
- **Async-safe rendering:** each HTTP request owns its rendering context while sharing the prepared registry.
|
||||
|
||||
## Install
|
||||
|
||||
@@ -50,23 +52,6 @@ lib_deps =
|
||||
DeviceFrameworkTemplateEngine=https://github.com/alexhopeoconnor/DFTE.git#v1.1.0
|
||||
```
|
||||
|
||||
PlatformIO checks out the Git ref after `#`; GitHub Release assets are unrelated. DFTE’s supported release targets are ESP8266 and ESP32.
|
||||
PlatformIO checks out the Git ref after `#`; GitHub Release assets are unrelated. DFTE supports ESP8266 and ESP32 Arduino projects.
|
||||
|
||||
## Documentation
|
||||
|
||||
Read the [documentation index](docs/README.md) for template syntax, async web responses, per-context memory sizing, examples, tests, and releases.
|
||||
|
||||
## Development and releases
|
||||
|
||||
```bash
|
||||
./scripts/bump-version.sh vMAJOR.MINOR.PATCH
|
||||
# Replace the generated CHANGELOG TODO with the release summary.
|
||||
./scripts/test.sh compile --platform esp8266
|
||||
./scripts/test.sh compile --platform esp32
|
||||
./scripts/check-docs.sh
|
||||
./scripts/prepare-release.sh vMAJOR.MINOR.PATCH --tag
|
||||
```
|
||||
|
||||
Tagging repeats the board-free compile checks, validates the package, and creates a GitHub Release from the matching changelog section. It does not publish to the PlatformIO Registry or deploy firmware.
|
||||
|
||||
See the [changelog](CHANGELOG.md) and [licence](LICENSE).
|
||||
See [getting started](docs/GETTING_STARTED.md), the [documentation index](docs/README.md), [examples](examples/README.md), [changelog](CHANGELOG.md), and [licence](LICENSE).
|
||||
|
||||
+1
-9
@@ -1,20 +1,12 @@
|
||||
# DFTE documentation
|
||||
|
||||
DFTE documentation is organised by the rendering problem being solved.
|
||||
|
||||
| I want to… | Read |
|
||||
| --- | --- |
|
||||
| Render a first template | [Getting started](GETTING_STARTED.md) |
|
||||
| Use placeholders, templates, conditions, dynamic fragments, or iterators | [Template language](TEMPLATE_LANGUAGE.md) |
|
||||
| Stream a response through ESPAsyncWebServer | [Async web responses](ASYNC_WEB.md) |
|
||||
| Change buffer, stack, or placeholder limits safely | [Configuration](CONFIGURATION.md) |
|
||||
| Build the standalone examples | [Examples](../examples/README.md) |
|
||||
| Build, flash, and observe a complete example | [Examples](../examples/README.md) |
|
||||
| Run checks or prepare a release | [Testing](TESTING.md) · [Development](DEVELOPMENT.md) |
|
||||
|
||||
## Documentation rules
|
||||
|
||||
- The template-language guide owns DFTE semantics and lifecycle contracts.
|
||||
- The configuration guide owns ABI-sensitive build flags.
|
||||
- The project README is an entry point and example chooser, not a full API manual.
|
||||
|
||||
Back to the [project overview](../README.md).
|
||||
|
||||
+9
-9
@@ -1,22 +1,22 @@
|
||||
# DFTE examples
|
||||
|
||||
Every example is a standalone PlatformIO project. Build, upload, and monitor from its directory:
|
||||
Every example is a standalone PlatformIO project. Build, upload, and monitor from the repository root:
|
||||
|
||||
```bash
|
||||
pio run -d examples/HelloPlaceholder -e example_esp8266
|
||||
pio run -d examples/HelloPlaceholder -e example_esp8266 -t upload
|
||||
pio run -d examples/HelloPlaceholder -e example_esp8266 -t monitor
|
||||
pio device monitor -d examples/HelloPlaceholder -e example_esp8266
|
||||
```
|
||||
|
||||
Choose the ESP32 environment where provided.
|
||||
Choose the corresponding ESP32 environment where provided. The examples use the checked-out DFTE source, so they double as practical integration checks for this repository.
|
||||
|
||||
| Example | What it demonstrates |
|
||||
| Example | Start here when you want to… |
|
||||
| --- | --- |
|
||||
| [HelloPlaceholder](HelloPlaceholder/) | Smallest registry/context/chunk flow over serial |
|
||||
| [NestedLayouts](NestedLayouts/) | Templates, partials, conditionals, and iterators without a web server |
|
||||
| [StreamingAsync](StreamingAsync/) | Request-scoped streaming HTTP response through a SoftAP portal |
|
||||
| [AsyncDashboardDemo](AsyncDashboardDemo/) | Dashboard telemetry, iterator rows, and captive-portal flow |
|
||||
| [HelloPlaceholder](HelloPlaceholder/) | understand the smallest registry/context/chunk flow over serial |
|
||||
| [NestedLayouts](NestedLayouts/) | compose a page with partials, conditions, and repeating data |
|
||||
| [StreamingAsync](StreamingAsync/) | serve one streamed page through an asynchronous web server |
|
||||
| [AsyncDashboardDemo](AsyncDashboardDemo/) | inspect a richer browser-facing dashboard without buffering the response |
|
||||
|
||||
The SoftAP examples print their network names and passwords to serial. They are demonstrations, not production provisioning implementations.
|
||||
The SoftAP examples print their network names and passwords to serial. They are self-contained browser demonstrations, not Wi-Fi provisioning implementations.
|
||||
|
||||
Back to [DFTE documentation](../docs/README.md) · [project overview](../README.md).
|
||||
|
||||
@@ -1,20 +1,24 @@
|
||||
# Streaming Async
|
||||
|
||||
Small ESPAsyncWebServer demo that exposes a captive portal over a SoftAP and renders a DFTE template directly to the HTTP response stream. It highlights:
|
||||
This ESPAsyncWebServer example exposes a captive portal over a SoftAP and streams a DFTE template directly to each HTTP response. It demonstrates:
|
||||
|
||||
- Per-request `TemplateContext` ownership to avoid concurrent request clashes
|
||||
- PROGMEM template with shared CSS/header/footer snippets
|
||||
- Runtime data from RAM getters (uptime, connected station count)
|
||||
- Captive portal DNS redirect so clients automatically receive the dashboard
|
||||
- one request-scoped `TemplateContext` per response;
|
||||
- a PROGMEM page with shared CSS/header/footer snippets;
|
||||
- runtime getters for uptime and connected-station count;
|
||||
- a captive-portal DNS redirect for browsers that support it.
|
||||
|
||||
## Build
|
||||
|
||||
```
|
||||
```bash
|
||||
pio run -d examples/StreamingAsync -e example_esp8266
|
||||
|
||||
See the shared [examples guide](../README.md) and [async web guidance](../../docs/ASYNC_WEB.md).
|
||||
pio run -d examples/StreamingAsync -e example_esp32
|
||||
```
|
||||
|
||||
Flash the board, connect to the SoftAP announced by the device (`DFTE-Portal-8266` or `DFTE-Portal-ESP32`, password `dfte-demo`), and your browser should automatically present the streamed dashboard. If it does not, navigate manually to `http://192.168.4.1/`.
|
||||
## Run
|
||||
|
||||
1. Flash your target with `pio run -d examples/StreamingAsync -e <env> -t upload --upload-port <port>`.
|
||||
2. Open the serial monitor at 115200 baud and confirm the SoftAP credentials.
|
||||
3. Connect to `DFTE-Portal-8266` or `DFTE-Portal-ESP32` using password `dfte-demo`.
|
||||
4. Browse to `http://192.168.4.1/` if the captive portal does not open automatically.
|
||||
|
||||
See the shared [examples guide](../README.md) and [async web guidance](../../docs/ASYNC_WEB.md).
|
||||
|
||||
@@ -25,4 +25,21 @@ while IFS= read -r -d '' markdown; do
|
||||
done < <(sed -nE 's/.*\]\(([^ )]+)( "[^"]*")?\).*/\1/p' "$markdown")
|
||||
done < <(find "$root" -path "$root/.git" -prune -o -path '*/.pio' -prune -o -name '*.md' -type f -print0)
|
||||
|
||||
while IFS= read -r example; do
|
||||
for required in README.md platformio.ini; do
|
||||
[[ -f "$example/$required" ]] || { echo "Incomplete example: ${example#$root/} is missing $required" >&2; exit 1; }
|
||||
done
|
||||
find "$example/src" -type f \( -name '*.ino' -o -name '*.cpp' \) -print -quit | grep -q . || {
|
||||
echo "Incomplete example: ${example#$root/} has no source" >&2
|
||||
exit 1
|
||||
}
|
||||
done < <(find "$root/examples" -mindepth 2 -maxdepth 2 -type f -name platformio.ini -printf '%h\n' | sort)
|
||||
|
||||
while IFS= read -r markdown; do
|
||||
(( $(grep -Ec '^[[:space:]]*```' "$markdown") % 2 == 0 )) || {
|
||||
echo "Unclosed code fence in ${markdown#$root/}" >&2
|
||||
exit 1
|
||||
}
|
||||
done < <(find "$root" -path "$root/.git" -prune -o -path '*/.pio' -prune -o -name '*.md' -type f -print)
|
||||
|
||||
echo "Documentation links and required files passed"
|
||||
|
||||
+25
-7
@@ -2,18 +2,36 @@
|
||||
set -euo pipefail
|
||||
|
||||
usage() {
|
||||
echo "Usage: $0 compile --platform esp8266|esp32" >&2
|
||||
echo "Usage: $0 compile|examples --platform esp8266|esp32" >&2
|
||||
exit 2
|
||||
}
|
||||
|
||||
[[ "${1:-}" == "compile" && "${2:-}" == "--platform" && $# -eq 3 ]] || usage
|
||||
|
||||
[[ $# -eq 3 && ( "${1:-}" == "compile" || "${1:-}" == "examples" ) && "${2:-}" == "--platform" ]] || usage
|
||||
case "${3:-}" in
|
||||
esp8266) environment="test_template_engine_8266" ;;
|
||||
esp32) environment="test_template_engine_esp32" ;;
|
||||
esp8266|esp32) platform="$3" ;;
|
||||
*) usage ;;
|
||||
esac
|
||||
|
||||
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
pio test -d "$root" -e "$environment" --without-uploading --without-testing
|
||||
echo "DFTE compile check passed for ${3}"
|
||||
if [[ "$1" == "compile" ]]; then
|
||||
case "$platform" in
|
||||
esp8266) test_environment="test_template_engine_8266" ;;
|
||||
esp32) test_environment="test_template_engine_esp32" ;;
|
||||
esac
|
||||
pio test -d "$root" -e "$test_environment" --without-uploading --without-testing
|
||||
echo "DFTE compile check passed for $platform"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
suffix="$platform"
|
||||
mapfile -t examples < <(find "$root/examples" -mindepth 2 -maxdepth 2 -type f -name platformio.ini -printf '%h\n' | sort)
|
||||
if (( ${#examples[@]} == 0 )); then
|
||||
echo "No example projects found" >&2
|
||||
exit 1
|
||||
fi
|
||||
for example in "${examples[@]}"; do
|
||||
env_name="example_$suffix"
|
||||
[[ "$(basename "$example")" == "AsyncDashboardDemo" ]] && env_name="dashboard_$suffix"
|
||||
pio run -d "$example" -e "$env_name" </dev/null
|
||||
done
|
||||
echo "DFTE examples compile check passed for $platform"
|
||||
|
||||
Reference in New Issue
Block a user