sync with dev-16

This commit is contained in:
proddy
2026-04-18 18:54:33 +02:00
parent d6e00c4534
commit 86a20fc97a
23 changed files with 380 additions and 827 deletions

View File

@@ -57,7 +57,7 @@
"@types/react-dom": "^19.2.3",
"axe-core": "^4.11.3",
"concurrently": "^9.2.1",
"eslint": "^10.2.0",
"eslint": "^10.2.1",
"eslint-config-prettier": "^10.1.8",
"prettier": "^3.8.3",
"rollup-plugin-visualizer": "^7.0.1",

111
interface/pnpm-lock.yaml generated
View File

@@ -80,7 +80,7 @@ importers:
version: 7.29.0
'@eslint/js':
specifier: ^10.0.1
version: 10.0.1(eslint@10.2.0)
version: 10.0.1(eslint@10.2.1)
'@preact/preset-vite':
specifier: ^2.10.5
version: 2.10.5(@babel/core@7.29.0)(preact@10.29.1)(rollup@4.59.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.4)(terser@5.46.1))
@@ -103,11 +103,11 @@ importers:
specifier: ^9.2.1
version: 9.2.1
eslint:
specifier: ^10.2.0
version: 10.2.0
specifier: ^10.2.1
version: 10.2.1
eslint-config-prettier:
specifier: ^10.1.8
version: 10.1.8(eslint@10.2.0)
version: 10.1.8(eslint@10.2.1)
prettier:
specifier: ^3.8.3
version: 3.8.3
@@ -119,7 +119,7 @@ importers:
version: 5.46.1
typescript-eslint:
specifier: ^8.58.2
version: 8.58.2(eslint@10.2.0)(typescript@6.0.3)
version: 8.58.2(eslint@10.2.1)(typescript@6.0.3)
vite:
specifier: ^8.0.8
version: 8.0.8(@types/node@25.6.0)(esbuild@0.27.4)(terser@5.46.1)
@@ -498,12 +498,16 @@ packages:
resolution: {integrity: sha512-rZAP3aVgB9ds9KOeUSL+zZ21hPmo8dh6fnIFwRQj5EAZl9gzR7wxYbYXYysAM8CTqGmUGyp2S4kUdV17MnGuWQ==}
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
'@humanfs/core@0.19.1':
resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==}
'@humanfs/core@0.19.2':
resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==}
engines: {node: '>=18.18.0'}
'@humanfs/node@0.16.7':
resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==}
'@humanfs/node@0.16.8':
resolution: {integrity: sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==}
engines: {node: '>=18.18.0'}
'@humanfs/types@0.15.0':
resolution: {integrity: sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==}
engines: {node: '>=18.18.0'}
'@humanwhocodes/module-importer@1.0.1':
@@ -1181,8 +1185,8 @@ packages:
base64-js@1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
baseline-browser-mapping@2.10.19:
resolution: {integrity: sha512-qCkNLi2sfBOn8XhZQ0FXsT1Ki/Yo5P90hrkRamVFRS7/KV9hpfA4HkoWNU152+8w0zPjnxo5psx5NL3PSGgv5g==}
baseline-browser-mapping@2.10.20:
resolution: {integrity: sha512-1AaXxEPfXT+GvTBJFuy4yXVHWJBXa4OdbIebGN/wX5DlsIkU0+wzGnd2lOzokSk51d5LUmqjgBLRLlypLUqInQ==}
engines: {node: '>=6.0.0'}
hasBin: true
@@ -1710,8 +1714,8 @@ packages:
resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==}
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
eslint@10.2.0:
resolution: {integrity: sha512-+L0vBFYGIpSNIt/KWTpFonPrqYvgKw1eUI5Vn7mEogrQcWtWYtNQ7dNqC+px/J0idT3BAkiWrhfS7k+Tum8TUA==}
eslint@10.2.1:
resolution: {integrity: sha512-wiyGaKsDgqXvF40P8mDwiUp/KQjE1FdrIEJsM8PZ3XCiniTMXS3OHWWUe5FI5agoCnr8x4xPrTDZuxsBlNHl+Q==}
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
hasBin: true
peerDependencies:
@@ -2019,8 +2023,8 @@ packages:
resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
engines: {node: '>= 0.4'}
hasown@2.0.2:
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
hasown@2.0.3:
resolution: {integrity: sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==}
engines: {node: '>= 0.4'}
he@1.2.0:
@@ -3693,9 +3697,9 @@ snapshots:
'@esbuild/win32-x64@0.27.4':
optional: true
'@eslint-community/eslint-utils@4.9.1(eslint@10.2.0)':
'@eslint-community/eslint-utils@4.9.1(eslint@10.2.1)':
dependencies:
eslint: 10.2.0
eslint: 10.2.1
eslint-visitor-keys: 3.4.3
'@eslint-community/regexpp@4.12.2': {}
@@ -3716,9 +3720,9 @@ snapshots:
dependencies:
'@types/json-schema': 7.0.15
'@eslint/js@10.0.1(eslint@10.2.0)':
'@eslint/js@10.0.1(eslint@10.2.1)':
optionalDependencies:
eslint: 10.2.0
eslint: 10.2.1
'@eslint/object-schema@3.0.5': {}
@@ -3727,13 +3731,18 @@ snapshots:
'@eslint/core': 1.2.1
levn: 0.4.1
'@humanfs/core@0.19.1': {}
'@humanfs/node@0.16.7':
'@humanfs/core@0.19.2':
dependencies:
'@humanfs/core': 0.19.1
'@humanfs/types': 0.15.0
'@humanfs/node@0.16.8':
dependencies:
'@humanfs/core': 0.19.2
'@humanfs/types': 0.15.0
'@humanwhocodes/retry': 0.4.3
'@humanfs/types@0.15.0': {}
'@humanwhocodes/module-importer@1.0.1': {}
'@humanwhocodes/retry@0.4.3': {}
@@ -4166,15 +4175,15 @@ snapshots:
dependencies:
'@types/node': 25.6.0
'@typescript-eslint/eslint-plugin@8.58.2(@typescript-eslint/parser@8.58.2(eslint@10.2.0)(typescript@6.0.3))(eslint@10.2.0)(typescript@6.0.3)':
'@typescript-eslint/eslint-plugin@8.58.2(@typescript-eslint/parser@8.58.2(eslint@10.2.1)(typescript@6.0.3))(eslint@10.2.1)(typescript@6.0.3)':
dependencies:
'@eslint-community/regexpp': 4.12.2
'@typescript-eslint/parser': 8.58.2(eslint@10.2.0)(typescript@6.0.3)
'@typescript-eslint/parser': 8.58.2(eslint@10.2.1)(typescript@6.0.3)
'@typescript-eslint/scope-manager': 8.58.2
'@typescript-eslint/type-utils': 8.58.2(eslint@10.2.0)(typescript@6.0.3)
'@typescript-eslint/utils': 8.58.2(eslint@10.2.0)(typescript@6.0.3)
'@typescript-eslint/type-utils': 8.58.2(eslint@10.2.1)(typescript@6.0.3)
'@typescript-eslint/utils': 8.58.2(eslint@10.2.1)(typescript@6.0.3)
'@typescript-eslint/visitor-keys': 8.58.2
eslint: 10.2.0
eslint: 10.2.1
ignore: 7.0.5
natural-compare: 1.4.0
ts-api-utils: 2.5.0(typescript@6.0.3)
@@ -4182,14 +4191,14 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/parser@8.58.2(eslint@10.2.0)(typescript@6.0.3)':
'@typescript-eslint/parser@8.58.2(eslint@10.2.1)(typescript@6.0.3)':
dependencies:
'@typescript-eslint/scope-manager': 8.58.2
'@typescript-eslint/types': 8.58.2
'@typescript-eslint/typescript-estree': 8.58.2(typescript@6.0.3)
'@typescript-eslint/visitor-keys': 8.58.2
debug: 4.4.3
eslint: 10.2.0
eslint: 10.2.1
typescript: 6.0.3
transitivePeerDependencies:
- supports-color
@@ -4212,13 +4221,13 @@ snapshots:
dependencies:
typescript: 6.0.3
'@typescript-eslint/type-utils@8.58.2(eslint@10.2.0)(typescript@6.0.3)':
'@typescript-eslint/type-utils@8.58.2(eslint@10.2.1)(typescript@6.0.3)':
dependencies:
'@typescript-eslint/types': 8.58.2
'@typescript-eslint/typescript-estree': 8.58.2(typescript@6.0.3)
'@typescript-eslint/utils': 8.58.2(eslint@10.2.0)(typescript@6.0.3)
'@typescript-eslint/utils': 8.58.2(eslint@10.2.1)(typescript@6.0.3)
debug: 4.4.3
eslint: 10.2.0
eslint: 10.2.1
ts-api-utils: 2.5.0(typescript@6.0.3)
typescript: 6.0.3
transitivePeerDependencies:
@@ -4241,13 +4250,13 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/utils@8.58.2(eslint@10.2.0)(typescript@6.0.3)':
'@typescript-eslint/utils@8.58.2(eslint@10.2.1)(typescript@6.0.3)':
dependencies:
'@eslint-community/eslint-utils': 4.9.1(eslint@10.2.0)
'@eslint-community/eslint-utils': 4.9.1(eslint@10.2.1)
'@typescript-eslint/scope-manager': 8.58.2
'@typescript-eslint/types': 8.58.2
'@typescript-eslint/typescript-estree': 8.58.2(typescript@6.0.3)
eslint: 10.2.0
eslint: 10.2.1
typescript: 6.0.3
transitivePeerDependencies:
- supports-color
@@ -4325,7 +4334,7 @@ snapshots:
base64-js@1.5.1: {}
baseline-browser-mapping@2.10.19: {}
baseline-browser-mapping@2.10.20: {}
bin-build@3.0.0:
dependencies:
@@ -4386,7 +4395,7 @@ snapshots:
browserslist@4.28.2:
dependencies:
baseline-browser-mapping: 2.10.19
baseline-browser-mapping: 2.10.20
caniuse-lite: 1.0.30001788
electron-to-chromium: 1.5.340
node-releases: 2.0.37
@@ -4898,9 +4907,9 @@ snapshots:
escape-string-regexp@4.0.0: {}
eslint-config-prettier@10.1.8(eslint@10.2.0):
eslint-config-prettier@10.1.8(eslint@10.2.1):
dependencies:
eslint: 10.2.0
eslint: 10.2.1
eslint-scope@9.1.2:
dependencies:
@@ -4913,15 +4922,15 @@ snapshots:
eslint-visitor-keys@5.0.1: {}
eslint@10.2.0:
eslint@10.2.1:
dependencies:
'@eslint-community/eslint-utils': 4.9.1(eslint@10.2.0)
'@eslint-community/eslint-utils': 4.9.1(eslint@10.2.1)
'@eslint-community/regexpp': 4.12.2
'@eslint/config-array': 0.23.5
'@eslint/config-helpers': 0.5.5
'@eslint/core': 1.2.1
'@eslint/plugin-kit': 0.7.1
'@humanfs/node': 0.16.7
'@humanfs/node': 0.16.8
'@humanwhocodes/module-importer': 1.0.1
'@humanwhocodes/retry': 0.4.3
'@types/estree': 1.0.8
@@ -5169,7 +5178,7 @@ snapshots:
get-proto: 1.0.1
gopd: 1.2.0
has-symbols: 1.1.0
hasown: 2.0.2
hasown: 2.0.3
math-intrinsics: 1.1.0
get-proto@1.0.1:
@@ -5302,7 +5311,7 @@ snapshots:
dependencies:
has-symbols: 1.1.0
hasown@2.0.2:
hasown@2.0.3:
dependencies:
function-bind: 1.1.2
@@ -5412,7 +5421,7 @@ snapshots:
is-core-module@2.16.1:
dependencies:
hasown: 2.0.2
hasown: 2.0.3
is-cwebp-readable@3.0.0:
dependencies:
@@ -6390,13 +6399,13 @@ snapshots:
dependencies:
typescript: 6.0.3
typescript-eslint@8.58.2(eslint@10.2.0)(typescript@6.0.3):
typescript-eslint@8.58.2(eslint@10.2.1)(typescript@6.0.3):
dependencies:
'@typescript-eslint/eslint-plugin': 8.58.2(@typescript-eslint/parser@8.58.2(eslint@10.2.0)(typescript@6.0.3))(eslint@10.2.0)(typescript@6.0.3)
'@typescript-eslint/parser': 8.58.2(eslint@10.2.0)(typescript@6.0.3)
'@typescript-eslint/eslint-plugin': 8.58.2(@typescript-eslint/parser@8.58.2(eslint@10.2.1)(typescript@6.0.3))(eslint@10.2.1)(typescript@6.0.3)
'@typescript-eslint/parser': 8.58.2(eslint@10.2.1)(typescript@6.0.3)
'@typescript-eslint/typescript-estree': 8.58.2(typescript@6.0.3)
'@typescript-eslint/utils': 8.58.2(eslint@10.2.0)(typescript@6.0.3)
eslint: 10.2.0
'@typescript-eslint/utils': 8.58.2(eslint@10.2.1)(typescript@6.0.3)
eslint: 10.2.1
typescript: 6.0.3
transitivePeerDependencies:
- supports-color

View File

@@ -24,20 +24,26 @@ let bundleStats = {
other: { count: 0, uncompressed: 0, compressed: 0 }
};
const generateWWWClass =
() => `typedef std::function<void(const char * uri, const String & contentType, const uint8_t * content, size_t len, const String & hash)> RouteRegistrationHandler;
// Bundle Statistics:
// AsyncWebHandler that performs the lookup.
const generateWWWClass = () => `// Bundle Statistics:
// - Total compressed size: ${(totalSize / 1000).toFixed(1)} KB
// - Total uncompressed size: ${(Object.values(bundleStats).reduce((sum, stat) => sum + stat.uncompressed, 0) / 1000).toFixed(1)} KB
// - Compression ratio: ${(((Object.values(bundleStats).reduce((sum, stat) => sum + stat.uncompressed, 0) - totalSize) / Object.values(bundleStats).reduce((sum, stat) => sum + stat.uncompressed, 0)) * 100).toFixed(1)}%
// - Generated on: ${new Date().toISOString()}
class WWWData {
${INDENT}public:
${INDENT.repeat(2)}static void registerRoutes(RouteRegistrationHandler handler) {
${fileInfo.map((f) => `${INDENT.repeat(3)}handler("${f.uri}", "${f.mimeType}", ${f.variable}, ${f.size}, ${f.hash});`).join('\n')}
${INDENT.repeat(2)}}
struct WWWAsset {
${INDENT}const char * uri;
${INDENT}const char * contentType;
${INDENT}const uint8_t * content;
${INDENT}size_t len;
${INDENT}const char * etag; // already includes enclosing double quotes
};
static const WWWAsset WWW_ASSETS[] = {
${fileInfo.map((f) => `${INDENT}{"${f.uri}", "${f.mimeType}", ${f.variable}, ${f.size}, "\\"${f.rawHash}\\""},`).join('\n')}
};
static constexpr size_t WWW_ASSETS_COUNT = sizeof(WWW_ASSETS) / sizeof(WWW_ASSETS[0]);
`;
const getFilesSync = (dir, files = []) => {
@@ -72,6 +78,7 @@ const writeFile = (relativeFilePath, buffer) => {
const zipBuffer = zlib.gzipSync(buffer, { level: 9 });
// const hash = crypto.createHash('sha256').update(zipBuffer).digest('hex');
const hash = etag(zipBuffer); // use smaller md5 instead of sha256
const rawHash = hash.replace(/^"|"$/g, '');
zipBuffer.forEach((b) => {
if (!(size % bytesPerLine)) {
@@ -94,7 +101,8 @@ const writeFile = (relativeFilePath, buffer) => {
mimeType,
variable,
size,
hash
hash,
rawHash
});
totalSize += size;

View File

@@ -166,6 +166,51 @@ const createManualChunks = (detailed = false) => {
};
};
// Rolldown-native codeSplitting groups for the production build.
// See: https://rolldown.rs/reference/outputoptions.codesplitting
const createRolldownCodeSplitting = () => ({
groups: [
{ name: '@preact', test: /[\\/]node_modules[\\/].*preact/, priority: 100 },
{
name: '@react-router',
test: /[\\/]node_modules[\\/].*react-router/,
priority: 95
},
{
name: '@mui-material',
test: /[\\/]node_modules[\\/]@mui[\\/]material/,
priority: 95
},
{
name: '@mui-icons',
test: /[\\/]node_modules[\\/]@mui[\\/]icons-material/,
priority: 95
},
{ name: '@alova', test: /[\\/]node_modules[\\/].*alova/, priority: 90 },
{ name: '@i18n', test: /[\\/]node_modules[\\/].*typesafe-i18n/, priority: 90 },
{
name: '@toastify',
test: /[\\/]node_modules[\\/].*react-toastify/,
priority: 90
},
{
name: '@table-library',
test: /[\\/]node_modules[\\/]@table-library/,
priority: 90
},
{ name: 'vendor', test: /[\\/]node_modules[\\/]/, priority: 10 },
// Collapse the lazy-loaded route stubs + shared app/components/utils
// code into one chunk. This cuts firmware-side route count roughly in
// half and speeds up route-matching on every incoming HTTP request.
{
name: 'app',
test: /[\\/](app|components|utils)[\\/]/,
priority: 5
},
{ name: 'api', test: /[\\/]api[\\/]/, priority: 5 }
]
});
// Common build base configuration
const createBaseBuildConfig = () => ({
target: ES_TARGET,
@@ -330,10 +375,17 @@ export default defineConfig(
chunkFileNames: 'assets/[name]-[hash].js',
entryFileNames: 'assets/[name]-[hash].js',
assetFileNames: 'assets/[name]-[hash].[ext]',
// Kept as a no-op for documentation/fallback. With Vite 8
manualChunks: createManualChunks(true),
sourcemap: false
}
}
},
rolldownOptions: {
output: {
codeSplitting: createRolldownCodeSplitting()
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} as any
}
};
}