Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci-dev.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [22.x, 20.x, 18.x]
node-version: [24.x, 22.x, 20.x]

steps:
- uses: actions/checkout@v4
Expand Down
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.9.3] - 2025-11-01

### Added

- ETag validation support for ESP-IDF engine (`httpd_req_get_hdr_value_len` and `httpd_req_get_hdr_value_str`)
- HTTP 304 Not Modified response handling for ESP-IDF engine, matching behavior of other engines

### Changed

- Optimized generated C++ code for ESPAsyncWebServer engine:
- Optimized If-None-Match header lookups (single call instead of `hasHeader()` + `getHeader()`)
- Removed unnecessary `String()` temporary objects in ETag comparisons (use `.equals()` directly)
- Optimized generated C++ code for PsychicHttpServer engines (psychic, psychic2):
- Removed unnecessary `String()` temporary objects in ETag comparisons (use `.equals()` directly)

## [1.9.2] - 2025-10-18

### Changed
Expand Down
39 changes: 36 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,12 @@ npx tsx src/index.ts -e psychic -s ./demo/svelte/dist -o ./output.h --etag=true
1. **File Collection** (`src/file.ts`): Scans source directory recursively using glob, skips pre-compressed files (.gz, .br) if originals exist, detects duplicate files via SHA256 hashing
2. **Content Analysis** (`src/index.ts`): Determines MIME types using `mime-types` library, calculates MD5 hashes for ETag generation, groups files by extension for statistics
3. **Compression** (`src/index.ts`): Applies gzip level 9 compression, uses compressed version only when size reduction >15% and original >1024 bytes
4. **Code Generation** (`src/cppCode.ts`, `src/cppCodeEspIdf.ts`): Uses Handlebars templates with custom helpers (switch/case), generates engine-specific C++ code with conditional compilation support
5. **Output**: Writes optimized header with embedded binary data arrays, route handlers, ETag strings, and C++ defines for validation
4. **Code Generation** (`src/cppCode.ts`, `src/cppCodeEspIdf.ts`): Uses Handlebars templates with custom helpers (switch/case), generates optimized engine-specific C++ code with:
- Inlined lambda handlers (ESPAsyncWebServer)
- Optimized header lookups for ETag validation (all engines)
- Proper const-correctness and modern C++ patterns
- Conditional compilation support for etag/gzip options
5. **Output**: Writes optimized header with embedded binary data arrays, route handlers with ETag validation, ETag MD5 strings, and C++ defines for build-time validation

### Supported Engines

Expand All @@ -94,11 +98,12 @@ npx tsx src/index.ts -e psychic -s ./demo/svelte/dist -o ./output.h --etag=true
### Key Features

- **Automatic Gzip Compression**: Compresses assets when size reduction >15% and >1024 bytes
- **ETag Support**: HTTP cache validation for reduced network traffic
- **ETag Support**: HTTP cache validation for reduced network traffic with 304 Not Modified responses across all engines (psychic, psychic2, async, espidf)
- **Cache Control**: Configurable browser caching with `--cachetime`
- **Multi-Engine Support**: Generate code for different ESP web server libraries
- **File Type Analysis**: Groups files by extension with count statistics
- **Memory Optimization**: Binary data stored as const arrays in program memory
- **Optimized C++ Code**: Generated code uses modern C++ best practices with minimal overhead

## Development Environment

Expand Down Expand Up @@ -131,6 +136,8 @@ The `package.script` executable generates 36 test header files (9 combinations o
- `index.html` or `index.htm` files are automatically set as the default route for "/"
- Pre-compressed files (.gz, .br, .brottli) in the source directory are skipped if the original file exists
- The build uses `--clean` and `--force` flags to ensure clean builds without incremental compilation
- ESP-IDF engine includes required headers (`string.h`, `stdlib.h`) for ETag validation support
- All engines now fully support HTTP 304 Not Modified responses for efficient caching

## Template System

Expand All @@ -141,6 +148,32 @@ The code generation uses Handlebars with custom helpers:
- **Engine-specific templates**: Each engine (psychic, psychic2, async, espidf) has its own template in `src/cppCode.ts` or `src/cppCodeEspIdf.ts`
- **Data transformation**: Binary content is converted to comma-separated byte arrays in the template data

## Generated C++ Code Quality

The generated C++ code follows modern best practices and is optimized for performance and maintainability:

### ETag Validation Implementation

All four engines support ETag validation with HTTP 304 Not Modified responses:

- **ESPAsyncWebServer (`async`)**: Uses `const AsyncWebHeader*` for proper const-correctness, single `getHeader()` call instead of `hasHeader()` + `getHeader()`, inlined lambda handlers
- **PsychicHttpServer (`psychic`, `psychic2`)**: Uses `request->header().equals()` for direct string comparison without temporary objects
- **ESP-IDF (`espidf`)**: Uses `httpd_req_get_hdr_value_len()` and `httpd_req_get_hdr_value_str()` for header validation with proper memory management (malloc/free)

### Code Optimizations

- **No intermediate variables**: Lambda handlers are inlined directly in route registration (ESPAsyncWebServer)
- **Optimized header lookups**: Single API call instead of redundant checks
- **No temporary String objects**: Uses `.equals()` method directly instead of `== String()` wrapper
- **Proper const-correctness**: All pointer declarations use `const` where appropriate
- **Minimal overhead**: Generated code has minimal runtime performance impact

### Memory Management

- **ESP32 (psychic, psychic2, espidf)**: Const arrays automatically placed in program memory (flash)
- **ESP8266 (async)**: PROGMEM directive explicitly used for flash storage
- **ESP-IDF ETag validation**: Temporary header value buffers are properly allocated and freed

## Generated C++ Defines

The generated header file includes C++ defines for build-time validation:
Expand Down
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ const char * etag_assets_index_Soe6cpLA_css = "d4f23bc45ef67890ab12...";
void initSvelteStaticFiles(PsychicHttpServer * server) {
server->on("/assets/index-KwubEIf-.js", HTTP_GET, [](PsychicRequest * request) {
if (request->hasHeader("If-None-Match") &&
request->header("If-None-Match") == String(etag_assets_index_KwubEIf__js)) {
request->header("If-None-Match").equals(etag_assets_index_KwubEIf__js)) {
PsychicResponse response304(request);
response304.setCode(304);
return response304.send();
Expand All @@ -192,7 +192,7 @@ void initSvelteStaticFiles(PsychicHttpServer * server) {

server->on("/assets/index-Soe6cpLA.css", HTTP_GET, [](PsychicRequest * request) {
if (request->hasHeader("If-None-Match") &&
request->header("If-None-Match") == String(etag_assets_index_Soe6cpLA_css)) {
request->header("If-None-Match").equals(etag_assets_index_Soe6cpLA_css)) {
PsychicResponse response304(request);
response304.setCode(304);
return response304.send();
Expand Down Expand Up @@ -242,6 +242,8 @@ Since microcontroller data traffic is moderately expensive, it is an individual

The use of ETag is **not enabled by default**, this can be achieved with the `--etag=true` switch.

All four engines (psychic, psychic2, async, espidf) fully support ETag validation with HTTP 304 Not Modified responses, reducing bandwidth usage when clients have valid cached content.

> This setting has three states: yes, no, and compiler mode is available. In compiler mode, you can disable/enable ETag by setting the `SVELTEESP32_ENABLE_ETAG` c++ compiler directive. For example, if using platformio, just type `-D SVELTEESP32_ENABLE_ETAG`.

### Cache-control
Expand Down
Loading