Front end: app.js ships its 137 kB of comments to every browser; serve a built copy and keep the commented source #1149
Labels
No labels
accessibility
authentication
breaking change
bug
documentation
enhancement
interface
internationalisation
observability
performance
security
tier
1
tier
2
tier
3
tier/4
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Postulo/postulo#1149
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What exists today
src/postulo/static/js/app.jsis 9,250 lines and 369,047 bytes, loaded on every page bytemplates/base.html:62(<script src="{% static 'js/app.js' %}" defer>). Measured with a Python line scanner (whole-line//and/* ... */comments; trailing comments not counted, so the real share is a little higher):1,869 lines are comments and hold 136,773 bytes (37 per cent of the file); 537 more are blank. The comments are the project's documentation of the script and must stay in the source.
The ledger's figure ("halves the transfer") holds. What changes: WhiteNoise's manifest storage gives the file a hashed name and a far-future cache, so the saving is per release and per browser (a first visit, every deploy, every private window), not per page view. The scout's "per-page split later" is a separate and larger change and is not part of this one.
How compiled assets are handled today:
app.cssis built bynpm run build:css(Tailwind), committed, and.forgejo/workflows/ci.yml:422-449rebuilds it and fails ongit diff --exit-code; the vendored scripts, icons and brand marks are checked the same way. No JavaScript build step exists and no minifier is inpackage.jsonornode_modules.What reads app.js: about 20 unit test files read the source as text (
tests/test_page_script.py:32,tests/test_board_fold.py:68,819splits a function body out by"\n }\n",tests/test_template_lint.py:157,187strips/* */before searching,tests/security/test_offline_page.py:71,tests/test_keyboard_and_focus.py:30, and others). None reads line numbers or comments as such, but several depend on the source's layout, so they must go on reading the commented source. The CSP isscript-src 'self'(config/settings/base.py:861) with no hashes, so a different file body changes nothing there.What would change
static/js/app.jsas the source. Addesbuild(one binary devDependency, MIT) and abuild:jsscript:esbuild assets/js/app.js --minify --outfile=src/postulo/static/js/app.min.jsor, to keep names readable in the browser's debugger,--minify-whitespace --minify-syntaxwithout renaming. The source should then move out ofstatic/(for example toassets/js/app.js, as the stylesheet's source lives inassets/css/) so that collectstatic does not publish both; the unit tests' path constant moves with it.base.html:62loads the built file.ci.yml's asset check gainsnpm run build:jsand agit diff --exit-codeon the built file, with the same error line asapp.css, so a stale built copy cannot reachmain.stylesstage builds it too, as it builds the stylesheet, so image and commit stay byte for byte the same.What it saves or protects
medium: the script's transfer drops from 101 kB to 50 kB gzip (82 kB to 41 kB Brotli) with comments stripped alone; once per release per browser, since the hashed name is cached for good
Accessibility
none for the change itself, which removes no code; the browser suite (
tests/e2e/, among themtest_unsaved_work.py,test_help.py,test_keyboard_*through the served page) must run against the built file so it is the file the guards coverDecisions
app.css, the icons and the vendored scripts; the application keeps running without Node.Found by the efficiency and reliability audit of 2026-10-30 (finding A1; index postulo/postulo#1108). Checked against
mainatdaee30b15(2026-10-30).