Serving static files in aWOT 4

The published awot-static command in awot-scripts 3.1.2 converts a directory of browser assets into gzipped flash data and a Router in StaticFiles.h. Its output has been compiled with aWOT 4.0.0. The converter’s package version is independent of the library version; install the library with Arduino Library Manager and create the sketch manually as shown in Hello world.

In an existing Vite frontend, install the pinned converter:

npm install --save-dev --save-exact awot-scripts@3.1.2
mkdir WebServer

Add these fields to package.json, keeping your existing dependencies and scripts. Vite’s react-ts template uses tsc -b && vite build for build:

{
  "scripts": {
    "build": "tsc -b && vite build",
    "build:firmware": "npm run build && awot-static"
  },
  "awot-static": {
    "sources": "./dist",
    "indexFile": "index.html",
    "sketchDir": "./WebServer",
    "exclude": ["*.map"]
  }
}

Keep the generated Vite TypeScript configuration and package-lock.json. Use Node.js 22.12 or newer for this workflow. Run:

npm run build:firmware

The build creates dist/ and then WebServer/StaticFiles.h. Each generated handler sets Content-Type, Content-Encoding: gzip, Content-Length, cache headers, and writes the compressed bytes with res.writeP(). The browser receives and decompresses those assets. The configured index is served at /; other files use their generated paths. This converter does not supply a generic client-side router fallback for arbitrary URLs.

Create WebServer/WebServer.ino with this complete ESP32 sketch. Set your Wi-Fi credentials before uploading:

#include <WiFi.h>
#include <aWOT.h>
#include "StaticFiles.h"

WiFiServer server(80);
App app;

void health(Request& req, Response& res) {
  res.set("Content-Type", "text/plain");
  res.print("ok");
}

void setup() {
  Serial.begin(115200);
  WiFi.begin("YOUR_SSID", "YOUR_PASSWORD");
  while (WiFi.status() != WL_CONNECTED) delay(500);
  Serial.println(WiFi.localIP());
  app.get("/api/health", health);
  app.use(staticFiles());
  server.begin();
}

void loop() {
  WiFiClient client = server.available();
  if (client.connected()) {
    app.process(&client);
    client.stop();
  }
}

Mount staticFiles() once in setup, after the API routes. The generated function returns a pointer to a static router, which outlives its use by app. Generate the header again whenever frontend assets change, then rebuild and upload the firmware. The assets occupy flash; their size must fit your board’s application partition. This workflow does not measure or promise an AVR memory budget.

The full stack tutorial adds a Vite development proxy, frontend API calls, and LED control. The 3.x static-file instructions are archived for older projects.