Feat/lazy loading#1156
Merged
Merged
Conversation
…chunk All page-level components in the router are now loaded via React.lazy(), so CodeMirror, react-markdown, rehype plugins and KaTeX are no longer part of the initial bundle. A dedicated 'codemirror' manual chunk groups @codemirror, @lezer and @fsegurai packages separately from the main chunk.
Replaced the static mermaid import in useMermaidInjector with a cached dynamic import(). Also removed the mermaid manualChunks entry — it was causing Rolldown to include the 841 kB (gzip) mermaid bundle in the initial HTML modulepreload regardless of whether it was ever needed. Mermaid now loads on-demand the first time a page with a diagram is viewed.
Vite now generates .gz files (level 9) for all JS and CSS assets after each build. The Go router serves the pre-compressed variant with Content-Encoding: gzip and Vary: Accept-Encoding when the client supports it, falling back to uncompressed files otherwise. No CPU overhead per request — compression is done once at build time.
…azy chunks - Add spinner as Suspense fallback so lazy chunk load doesn't show a blank screen - Set Vary: Accept-Encoding on the uncompressed static fallback path so caching proxies don't serve the wrong variant to gzip-capable clients - Use base: './' in production builds so Vite emits relative asset paths; the preload-helper then resolves CSS/JS URLs via import.meta.url and correctly includes the runtime-configured sub-path (e.g. /wiki/) without any server-side string replacement - removes the now-redundant /static/ rewrite in router.go
Contributor
There was a problem hiding this comment.
Pull request overview
This PR aims to reduce initial frontend bundle cost by introducing lazy-loading for major UI routes and Mermaid, and to improve frontend asset delivery by generating and serving pre-gzipped static assets.
Changes:
- Switch route components to
React.lazy()and wrap the router in a top-levelSuspensefallback. - Lazy-load Mermaid via dynamic
import('mermaid')and update bundling strategy (manual chunks) for editor-related deps. - Generate
.gzfiles for built JS/CSS and serve them from the Go server when the client supports gzip.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| ui/leafwiki-ui/vite.config.ts | Sets production base behavior, adjusts chunk splitting, and adds a build-time gzip step for JS/CSS outputs. |
| ui/leafwiki-ui/src/features/router/router.tsx | Converts route components to React.lazy() to defer loading until needed. |
| ui/leafwiki-ui/src/features/preview/useMermaidInjector.ts | Defers Mermaid load/initialization until a diagram is actually rendered. |
| ui/leafwiki-ui/src/App.tsx | Adds a Suspense boundary (spinner fallback) around RouterProvider to support lazy routes. |
| internal/http/router.go | Adds gzip-aware static serving for embedded /static assets and removes now-obsolete HTML path rewriting. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Gzip compression should be handled by nginx, not the Go server.
Relative base ('./') broke SPA routing — the browser resolved asset URLs
relative to the current route URL instead of the document root.
Reverts to absolute paths (Vite default) with Go patching /static/ →
{basePath}/static/ in the HTML when a base path is configured.
… sub-path serving With base: './' Vite generates ./static/... relative asset paths. Lazy chunks resolve correctly at any base path via import.meta.url. Go rewrites the initial ./static/ references in the HTML to absolute paths so they load correctly when index.html is served for deep SPA routes. No <base> tag needed — anchor hash navigation in page content stays unaffected.
Converts all 21 dialog components and the Search sidebar panel from eager to lazy imports, reducing the main JS bundle from 503 kB to 346 kB (−31%). Adds Suspense boundaries in DialogManager and Sidebar to support lazy rendering.
Extracts lazy() declarations from router.tsx and registries/index.tsx into lazy-routes.tsx and lazy-dialogs.tsx respectively. Each new file exports only components, satisfying the react-refresh/only-export-components rule.
BasePath and faviconFile were injected into HTML attributes without escaping, making them potential XSS vectors if misconfigured. Use html.EscapeString consistently for all injected values. Also corrects the vite.config comment to accurately describe the Go-side asset path rewriting mechanism.
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.
No description provided.