Repository navigation
build: content-hashed asset copies + asset-manifest.json - #688
Merged
Randy808 merged 4 commits intoOct 6, 2026
Merged
Conversation
DeviaVir
requested review from
Randy808
and
a balanced review from Copilot
and removed request for
Randy808
October 6, 2026 08:48
DeviaVir
marked this pull request as ready for review
October 6, 2026 08:48
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
The bundled prerender service cannot locate the flavor-specific manifest, so /nojs/ pages still reference unhashed assets.
Review effort: Balanced
Findings: 1
What changed in this PR
Adds content-hashed frontend assets and manifest-based URL resolution for improved caching.
Changes:
- Generates hashed scripts, stylesheets, and fonts with
asset-manifest.json. - Updates templates and lazy loaders to use hashed paths.
- Adds tests, documentation, and prefix-safe asset URLs.
| File | Description |
|---|---|
www/style.css |
Makes the icon URL prefix-safe. |
test/hash-assets.test.js |
Tests hashing, manifests, and templates. |
scripts/hash-assets.js |
Generates hashed asset copies and manifest. |
scripts/asset-manifest.js |
Loads manifests with fallback behavior. |
render-view.js |
Supplies the manifest when rendering errors. |
README.md |
Documents hashed-asset deployment. |
prerender-server/src/server.js |
Supplies manifests to prerendered pages. |
client/src/views/lander.js |
Uses the hashed infinite-scroll script. |
client/src/driver/instascan.js |
Uses the hashed scanner script. |
client/src/app.js |
Switches between resolved LTR/RTL stylesheets. |
client/index.pug |
Renders manifest-resolved asset URLs. |
build.sh |
Integrates hashing into the build pipeline. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
The static assets are not content-hashed (app.js, style.css, ...), so any
cache in front of the explorer has to choose between long TTLs (deploys
take hours to show up, and new HTML can load old JS/CSS) and frequent
revalidation.
The build now writes content-hashed copies (sha256, 12 hex) of app.js,
style.css, style-rtl.css, instascan.min.js, js/infinite-scroll.js and the
fonts referenced from the CSS, keeps the original files, and writes
asset-manifest.json. index.html, notfound.html and the prerender server
reference the hashed names, so deployments can serve hashed files with
`Cache-Control: public, max-age=31536000, immutable` and keep only the HTML
short-lived. The stylesheet link carries data-ltr/data-rtl so the Hebrew
switch picks the hashed RTL file (HTML cached before this change still
works). Fonts are rewritten inside the CSS before the CSS is hashed.
HASH_ASSETS=0 restores the old names (no manifest, no copies).
Also fixes two absolute paths that broke when the explorer is served under
a prefix: lander.js loaded `${staticRoot}/js/infinite-scroll.js` (double
slash) and style.css used url('/img/icons/arrow-right-orange.svg').
The Docker image builds each flavor into /srv/explorer/static/<flavor>, so the default manifest path (dist/asset-manifest.json) did not exist for the bundled prerender service and /nojs/ pages kept the unhashed asset names.
DeviaVir
force-pushed
the
ci-github-actions
branch
from
October 6, 2026 09:32
41de9f8 to
824285c
Compare
DeviaVir
force-pushed
the
content-hashed-assets
branch
from
October 6, 2026 09:32
ae6547d to
a40bc21
Compare
The prerender bundle is compiled before the static builds, so envify cannot bake the hashed infinite-scroll name into it, and lander.js read the env var once at module load. The prerender server now loads the flavor's manifest once at startup and exports the lazy-script names (exportAssetEnv), and lander.js reads the name at render time. The browser bundle is unchanged: envify still inlines the literal.
Randy808
approved these changes
Oct 6, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

The static assets are not content-hashed (app.js, style.css, ...), so any
cache in front of the explorer has to choose between long TTLs (deploys
take hours to show up, and new HTML can load old JS/CSS) and frequent
revalidation.
The build now writes content-hashed copies (sha256, 12 hex) of app.js,
style.css, style-rtl.css, instascan.min.js, js/infinite-scroll.js and the
fonts referenced from the CSS, keeps the original files, and writes
asset-manifest.json. index.html, notfound.html and the prerender server
reference the hashed names, so deployments can serve hashed files with
Cache-Control: public, max-age=31536000, immutableand keep only the HTMLshort-lived. The stylesheet link carries data-ltr/data-rtl so the Hebrew
switch picks the hashed RTL file (HTML cached before this change still
works). Fonts are rewritten inside the CSS before the CSS is hashed.
HASH_ASSETS=0 restores the old names (no manifest, no copies).
Also fixes two absolute paths that broke when the explorer is served under
a prefix: lander.js loaded
${staticRoot}/js/infinite-scroll.js(doubleslash) and style.css used url('/img/icons/arrow-right-orange.svg').