Skip to content

perf(web): minify static assets and lazy-load Settings/Saved/Mirror#234

Open
Danialsamadi wants to merge 3 commits into
sartoopjj:mainfrom
Danialsamadi:claude/competent-wilson-f18677
Open

perf(web): minify static assets and lazy-load Settings/Saved/Mirror#234
Danialsamadi wants to merge 3 commits into
sartoopjj:mainfrom
Danialsamadi:claude/competent-wilson-f18677

Conversation

@Danialsamadi

Copy link
Copy Markdown
Contributor

Summary

  • Serve embedded CSS/JS/HTML through a one-time startup minification pass (tdewolff/minify) instead of raw bytes, cutting bytes sent per request.
  • Stop shipping Settings, Saved Messages, and Mirror's JS/CSS on every page load — they now load on first use via a new loadFeature() helper in core.js. The default Feed view no longer pays for code most sessions never touch.
  • Fixed two bugs this uncovered: .msg-save-btn and .sm-header-actions/.saved-channel-entry had their base CSS rules living in the now-lazy saved.css, but the elements they style render unconditionally on the default view — moved those base rules into the eager stylesheets (media.css/layout.css) that actually load on first paint. Without this, both showed up as visibly duplicated/stray buttons in the chat header.
  • Also fixes profile re-import creating a duplicate profile when the same domain+key config is imported twice.

Verification

  • go build ./... and go test ./internal/web/... pass.
  • Rebuilt the client binary and confirmed in the running app that the header no longer shows the duplicate search icon, and re-audited every class defined in saved.css against all eagerly-loaded JS/HTML — no other instances of the same bug pattern.
  • Independent model review (second pass) confirmed: loadFeature() is safe against a double-click race (second call chains onto the same in-flight promise, no duplicate <script>/<link> injection), and the HTML minifier doesn't corrupt the inline theme/first-run-language scripts in index.html.

Known follow-up (out of scope here)

  • Profile-import dedup only compares Domain+Key; re-importing the same domain/key with a different ServerKey/resolver list silently drops the new config's other fields. Tracked separately, not touched in this PR beyond the exact-duplicate case.

Test plan

  • Load the Feed view fresh and confirm no console errors, header renders once (no duplicate search/save icons)
  • Open Settings, Saved Messages, and Mirror and confirm each still works after lazy-loading
  • Re-import the same resolver config twice and confirm no duplicate profile is created

🤖 Generated with Claude Code

Danialsamadi and others added 3 commits July 1, 2026 15:22
Rebasing our fork's main onto upstream/main (which independently gained
an equivalent Remove(size, crc) for the same saved-media feature)
produced a duplicate method declaration that fails to build. Keep
upstream's version — it already maintains curBytes accounting that
ours skipped.
Serve embedded CSS/JS/HTML through a one-time startup minification pass
(tdewolff/minify) instead of raw bytes, and stop shipping Settings,
Saved Messages, and Mirror's JS/CSS on every page load — they now load
on first use via loadFeature() in core.js. Cuts initial payload and
parse time for the default Feed view, which is what most sessions only
ever touch.

Moves .msg-save-btn and .sm-header-actions/.saved-channel-entry base
rules from the now-lazy saved.css into the eager stylesheets they
actually need to apply in, since those elements render unconditionally
on the default view.

Also fixes profile re-import creating a duplicate profile when the
same domain+key config is imported twice.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@Danialsamadi

Copy link
Copy Markdown
Contributor Author

Reopening — this was the intended target after all.

@Danialsamadi Danialsamadi reopened this Jul 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant