mirror of
https://github.com/lukaszraczylo/traefik-llmgateway.git
synced 2026-10-19 05:47:48 +00:00
perf(admin): stop wrapping baked assets in a 7500-literal + chain
webui/generate.mjs split each admin-panel asset's base64 into 120-char Go string literals joined with `+` (~7,550 literals, ~7,538 `+` ops across index.html + the JS/CSS bundle). A compiled Go binary folds that at compile time for free, but this plugin loads under Yaegi (github.com/traefik/yaegi), which folds a chain of N literal `+` operations at import time by repeatedly reallocating and copying the whole already-folded prefix: O(N^2). Measured: ~186ms of a ~223-240ms package import was this folding alone, versus ~3-4ms to decode the asset bytes. Replace the 120-char LINE_WIDTH with a 1,000,000-char CHUNK_CHARS cap. Every asset this panel ships today (largest ~516,000 base64 chars) fits in a single literal, so goBase64Expr now emits one decodeAdminAsset call with zero `+` folds per asset. The cap still bounds a future, much larger bundle to a small number of large chunks rather than one unbounded line; single-line Go string literals in this size class were verified against gofmt/go vet/go build before picking the constant. No behavior change: decoded asset bytes, contentType strings, and the asset map keys are unaffected by how the base64 is chunked into source literals — see the following regen commit for the byte-identity proof.
This commit is contained in:
+26
-6
@@ -111,16 +111,36 @@ function goStringLiteral(s) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* goBase64Expr renders base64Body (a base64 string) as a Go expression
|
* goBase64Expr renders base64Body (a base64 string) as a Go expression
|
||||||
* calling decodeAdminAsset, split into LINE_WIDTH-character chunks joined
|
* calling decodeAdminAsset, split into at most CHUNK_CHARS-character
|
||||||
* with `+` — a single 400KB-wide line is valid Go but painful for humans
|
* literals joined with `+`.
|
||||||
* and diff tools alike; chunking keeps every line reviewable.
|
*
|
||||||
|
* This used to split at a human-readable LINE_WIDTH of 120 chars —
|
||||||
|
* ~7,550 literals / ~7,538 `+` operations for this panel's ~680KB of
|
||||||
|
* base64. That's fine for a compiled Go binary (constant string
|
||||||
|
* concatenation folds at compile time), but this plugin is loaded by
|
||||||
|
* Yaegi (github.com/traefik/yaegi — Traefik's plugin interpreter), which
|
||||||
|
* folds a chain of N literal `+` operations at *import* time, by
|
||||||
|
* repeatedly reallocating and copying the whole already-folded prefix:
|
||||||
|
* O(N^2). Measured: that alone cost ~186ms of a ~223-240ms package
|
||||||
|
* import — the dominant share of Traefik's plugin-boot latency for this
|
||||||
|
* repo, versus ~3-4ms for decoding the asset bytes themselves.
|
||||||
|
*
|
||||||
|
* CHUNK_CHARS is set well above this panel's current largest asset
|
||||||
|
* (~516,000 base64 chars for the main JS bundle), so every asset today
|
||||||
|
* emits exactly one literal — zero `+` folds, zero O(N^2) cost. It still
|
||||||
|
* caps chunk size (rather than emitting one unbounded literal) so a
|
||||||
|
* future, much larger bundle degrades to a handful of large chunks
|
||||||
|
* instead of one arbitrarily long source line; gofmt/go vet/go build
|
||||||
|
* were verified against single-line string literals in this size class
|
||||||
|
* (see the perf-fix commit that introduced this constant), so this cap
|
||||||
|
* sits well inside that verified range.
|
||||||
*/
|
*/
|
||||||
const LINE_WIDTH = 120
|
const CHUNK_CHARS = 1_000_000
|
||||||
function goBase64Expr(base64Body) {
|
function goBase64Expr(base64Body) {
|
||||||
if (base64Body.length === 0) return 'decodeAdminAsset("")'
|
if (base64Body.length === 0) return 'decodeAdminAsset("")'
|
||||||
const chunks = []
|
const chunks = []
|
||||||
for (let i = 0; i < base64Body.length; i += LINE_WIDTH) {
|
for (let i = 0; i < base64Body.length; i += CHUNK_CHARS) {
|
||||||
chunks.push(goStringLiteral(base64Body.slice(i, i + LINE_WIDTH)))
|
chunks.push(goStringLiteral(base64Body.slice(i, i + CHUNK_CHARS)))
|
||||||
}
|
}
|
||||||
return `decodeAdminAsset(\n\t\t${chunks.join(' +\n\t\t')},\n\t)`
|
return `decodeAdminAsset(\n\t\t${chunks.join(' +\n\t\t')},\n\t)`
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user