Skip to content

feat: Add native esp-idf template #42

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 31, 2025
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
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ npx svelteesp32 -e psychic2 -s ../svelteapp/dist -o ../esp32project/svelteesp32.

// for ESPAsyncWebServer
npx svelteesp32 -e async -s ../svelteapp/dist -o ../esp32project/svelteesp32.h --etag=true

// for native esp-idf
npx svelteesp32 -e espidf -s ../svelteapp/dist -o ../esp32project/svelteesp32.h --etag=true
```

During the **translation process**, the processed file details are visible, and at the end, the result shows the ESP's memory allocation (gzip size)
Expand Down
3 changes: 2 additions & 1 deletion src/commandLine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { existsSync, statSync } from 'node:fs';
import { parse } from 'ts-command-line-args';

interface ICopyFilesArguments {
engine: 'psychic' | 'psychic2' | 'async';
engine: 'psychic' | 'psychic2' | 'async' | 'espidf';
sourcepath: string;
outputfile: string;
espmethod: string;
Expand All @@ -23,6 +23,7 @@ export const cmdLine = parse<ICopyFilesArguments>(
if (value === 'psychic') return 'psychic';
if (value === 'psychic2') return 'psychic2';
if (value === 'async') return 'async';
if (value === 'espidf') return 'espidf';
throw new Error(`Invalid engine: ${value}`);
},
alias: 'e',
Expand Down
21 changes: 18 additions & 3 deletions src/cppCode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { compile as handlebarsCompile, HelperOptions } from 'handlebars';

import { cmdLine } from './commandLine';

import { espidfTemplate } from './template_espidf';

export type CppCodeSource = {
filename: string;
dataname: string;
Expand Down Expand Up @@ -577,11 +579,24 @@ void {{methodName}}(AsyncWebServer * server) {
{{/each}}
}`;


const getTemplate = (engine: string): string => {
switch (engine) {
case 'psychic':
return psychicTemplate;
case 'psychic2':
return psychic2Template;
case 'espidf':
return espidfTemplate;
default:
return asyncTemplate;
}
}


let switchValue: string;
export const getCppCode = (sources: CppCodeSources, filesByExtension: ExtensionGroups): string =>
handlebarsCompile(
cmdLine.engine === 'psychic' ? psychicTemplate : cmdLine.engine === 'psychic2' ? psychic2Template : asyncTemplate
)(
handlebarsCompile(getTemplate(cmdLine.engine))(
{
commandLine: process.argv.slice(2).join(' '),
now: `${new Date().toLocaleDateString()} ${new Date().toLocaleTimeString()}`,
Expand Down
187 changes: 187 additions & 0 deletions src/template_espidf.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
export const espidfTemplate = `
//engine: espidf
//cmdline: {{{commandLine}}}
{{#if created }}
//created: {{now}}
{{/if}}
//
{{#switch etag}}
{{#case "true"}}
#ifdef {{definePrefix}}_ENABLE_ETAG
#warning {{definePrefix}}_ENABLE_ETAG has no effect because it is permanently switched ON
#endif
{{/case}}
{{#case "false"}}
#ifdef {{definePrefix}}_ENABLE_ETAG
#warning {{definePrefix}}_ENABLE_ETAG has no effect because it is permanently switched OFF
#endif
{{/case}}
{{/switch}}
{{#switch gzip}}
{{#case "true"}}
#ifdef {{definePrefix}}_ENABLE_GZIP
#warning {{definePrefix}}_ENABLE_GZIP has no effect because it is permanently switched ON
#endif
{{/case}}
{{#case "false"}}
#ifdef {{definePrefix}}_ENABLE_GZIP
#warning {{definePrefix}}_ENABLE_GZIP has no effect because it is permanently switched OFF
#endif
{{/case}}
{{/switch}}
//
{{#if version }}
#define {{definePrefix}}_VERSION "{{version}}"
{{/if}}
#define {{definePrefix}}_COUNT {{fileCount}}
#define {{definePrefix}}_SIZE {{fileSize}}
#define {{definePrefix}}_SIZE_GZIP {{fileGzipSize}}
//
{{#each sources}}
#define {{../definePrefix}}_FILE_{{this.datanameUpperCase}}
{{/each}}
//
{{#each filesByExtension}}
#define {{../definePrefix}}_{{this.extension}}_FILES {{this.count}}
{{/each}}
#include <stdint.h>
#include <esp_err.h>
#include <esp_http_server.h>
//
{{#switch gzip}}
{{#case "true"}}
{{#each sources}}
const char datagzip_{{this.dataname}}[{{this.lengthGzip}}] = { {{this.bytesGzip}} };
{{/each}}
{{/case}}
{{#case "false"}}
{{#each sources}}
const char data_{{this.dataname}}[{{this.length}}] = { {{this.bytes}} };
{{/each}}
{{/case}}
{{#case "compiler"}}
#ifdef {{definePrefix}}_ENABLE_GZIP
{{#each sources}}
const char datagzip_{{this.dataname}}[{{this.lengthGzip}}] = { {{this.bytesGzip}} };
{{/each}}
#else
{{#each sources}}
const char data_{{this.dataname}}[{{this.length}}] = { {{this.bytes}} };
{{/each}}
Comment on lines +60 to +77
Copy link

@coderabbitai coderabbitai bot Mar 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Data type inconsistency with other templates.

The data arrays are defined as const char in this template while other templates use uint8_t. According to the learning from your feedback, you intended to keep the data as uint8_t arrays for compatibility.

-const char datagzip_{{this.dataname}}[{{this.lengthGzip}}] = { {{this.bytesGzip}} };
+const uint8_t datagzip_{{this.dataname}}[{{this.lengthGzip}}] = { {{this.bytesGzip}} };

And similar changes for the other data definitions on lines 66, 72, and 76.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{{#each sources}}
const char datagzip_{{this.dataname}}[{{this.lengthGzip}}] = { {{this.bytesGzip}} };
{{/each}}
{{/case}}
{{#case "false"}}
{{#each sources}}
const char data_{{this.dataname}}[{{this.length}}] = { {{this.bytes}} };
{{/each}}
{{/case}}
{{#case "compiler"}}
#ifdef {{definePrefix}}_ENABLE_GZIP
{{#each sources}}
const char datagzip_{{this.dataname}}[{{this.lengthGzip}}] = { {{this.bytesGzip}} };
{{/each}}
#else
{{#each sources}}
const char data_{{this.dataname}}[{{this.length}}] = { {{this.bytes}} };
{{/each}}
{{#each sources}}
-const char datagzip_{{this.dataname}}[{{this.lengthGzip}}] = { {{this.bytesGzip}} };
+const uint8_t datagzip_{{this.dataname}}[{{this.lengthGzip}}] = { {{this.bytesGzip}} };
{{/each}}
{{/case}}
{{#case "false"}}
{{#each sources}}
-const char data_{{this.dataname}}[{{this.length}}] = { {{this.bytes}} };
+const uint8_t data_{{this.dataname}}[{{this.length}}] = { {{this.bytes}} };
{{/each}}
{{/case}}
{{#case "compiler"}}
#ifdef {{definePrefix}}_ENABLE_GZIP
{{#each sources}}
-const char datagzip_{{this.dataname}}[{{this.lengthGzip}}] = { {{this.bytesGzip}} };
+const uint8_t datagzip_{{this.dataname}}[{{this.lengthGzip}}] = { {{this.bytesGzip}} };
{{/each}}
#else
{{#each sources}}
-const char data_{{this.dataname}}[{{this.length}}] = { {{this.bytes}} };
+const uint8_t data_{{this.dataname}}[{{this.length}}] = { {{this.bytes}} };
{{/each}}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lol :) correct! but no. it's fixed code for esp32, it might as well just use const char to avoid the casts.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@karlp Understood! Makes perfect sense to use const char for the ESP-IDF template to avoid unnecessary type casting in the ESP32 code. Thanks for the clarification.


✏️ Learnings added
Learnt from: karlp
PR: BCsabaEngine/svelteesp32#42
File: src/template_espidf.ts:60-77
Timestamp: 2025-03-28T14:37:30.463Z
Learning: In the ESP-IDF template for svelteesp32, `const char` should be used for data arrays instead of `uint8_t` (which is used in other templates) because it avoids type casting when working with ESP32 HTTP server APIs, resulting in cleaner and more efficient code.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

#endif
{{/case}}
{{/switch}}
//
{{#switch etag}}
{{#case "true"}}
{{#each sources}}
const char * etag_{{this.dataname}} = "{{this.md5}}";
{{/each}}
{{/case}}
{{#case "false"}}
{{/case}}
{{#case "compiler"}}
#ifdef {{definePrefix}}_ENABLE_ETAG
{{#each sources}}
const char * etag_{{this.dataname}} = "{{this.md5}}";
{{/each}}
#endif
{{/case}}
{{/switch}}
{{#each sources}}
static esp_err_t file_handler_{{this.datanameUpperCase}} (httpd_req_t *req)
{
httpd_resp_set_type(req, "{{this.mime}}");
{{#switch ../gzip}}
{{#case "true"}}
{{#if this.isGzip}}
httpd_resp_set_hdr(req, "Content-Encoding", "gzip");
{{/if}}
{{/case}}
{{#case "compiler"}}
{{#if this.isGzip}}
#ifdef {{../definePrefix}}_ENABLE_GZIP
httpd_resp_set_hdr(req, "Content-Encoding", "gzip");
#endif
{{/if}}
{{/case}}
{{/switch}}
{{#switch ../etag}}
{{#case "true"}}
{{#../cacheTime}}
httpd_resp_set_hdr(req, "Cache-Control", "max-age={{value}}");
{{/../cacheTime}}
{{^../cacheTime}}
httpd_resp_set_hdr(req, "Cache-Control", "no-cache");
{{/../cacheTime}}
httpd_resp_set_hdr(req, "ETag", etag_{{this.dataname}});
{{/case}}
{{#case "compiler"}}
#ifdef {{../definePrefix}}_ENABLE_ETAG
{{#../cacheTime}}
httpd_resp_set_hdr(req, "Cache-Control", "max-age={{value}}");
{{/../cacheTime}}
{{^../cacheTime}}
httpd_resp_set_hdr(req, "Cache-Control", "no-cache");
{{/../cacheTime}}
httpd_resp_set_hdr(req, "ETag", etag_{{this.dataname}});
#endif
{{/case}}
{{/switch}}
{{#switch ../gzip}}
{{#case "true"}}
httpd_resp_send(req, datagzip_{{this.dataname}}, {{this.lengthGzip}});
{{/case}}
{{#case "false"}}
httpd_resp_send(req, data_{{this.dataname}}, {{this.length}});
{{/case}}
{{#case "compiler"}}
#ifdef {{../definePrefix}}_ENABLE_GZIP
httpd_resp_send(req, datagzip_{{this.dataname}}, {{this.lengthGzip}});
#else
httpd_resp_send(req, data_{{this.dataname}}, {{this.length}});
#endif
{{/case}}
{{/switch}}
return ESP_OK;
}
{{#if this.isDefault}}
static const httpd_uri_t route_def_{{this.datanameUpperCase}} = {
.uri = "/",
.method = HTTP_GET,
.handler = file_handler_{{this.datanameUpperCase}},
};
{{/if}}
static const httpd_uri_t route_{{this.datanameUpperCase}} = {
.uri = "/{{this.filename}}",
.method = HTTP_GET,
.handler = file_handler_{{this.datanameUpperCase}},
};
{{/each}}
static inline void {{methodName}}(httpd_handle_t server) {
{{#each sources}}
{{#if this.isDefault}}
httpd_register_uri_handler(server, &route_def_{{this.datanameUpperCase}});
{{/if}}
httpd_register_uri_handler(server, &route_{{this.datanameUpperCase}});
{{/each}}
}`;