| name | wsh-lazy-modal |
| description | Lazy loading modal containers and route components to reduce initial bundle size — CrokContainer, NewPostModalContainer |
WSH: Lazy Loading Modals and Route Components
Reducing initial bundle size by lazy-loading components that are not needed on first render.
Use this skill when eager imports of modals or route containers bloat the main JS bundle.
Techniques
React.lazy for Route Components
import { CrokContainer } from "./CrokContainer";
const CrokContainer = React.lazy(() =>
import("./CrokContainer").then((m) => ({ default: m.CrokContainer }))
);
Dynamic Import for Modals
Modals rendered outside routes (e.g., NewPostModalContainer always mounted in AppContainer) need special handling:
const NewPostModalContainer = React.lazy(() =>
import("./NewPostModalContainer").then((m) => ({ default: m.NewPostModalContainer }))
);
<Suspense fallback={null}>
<NewPostModalContainer id={newPostModalId} />
</Suspense>
SSR Considerations
When using React.lazy with SSR (hydrateRoot), the lazy component must be resolvable during hydration. If the component is not rendered during SSR (modals are typically hidden), this is safe. The chunk will be loaded on-demand when the modal opens.
Pitfalls
| Pitfall | Symptom | Fix |
|---|
| Named export mismatch | "Element type is invalid" error | Use .then(m => ({ default: m.NamedExport })) wrapper |
| Missing Suspense boundary | React error about missing Suspense | Wrap lazy component with <Suspense> |
| SSR hydration mismatch | Hydration warning in console | Ensure lazy components not rendered in SSR output |
VRT Risks
| Change | Visual Impact | Mitigation |
|---|
| Lazy-loaded modals | Slight delay on first open | Use fallback={null} — modal not visible until loaded |
| Route lazy loading | Flash of empty content | Existing <Suspense fallback={<div />}> handles this |
Project-Specific Notes
CrokContainer imports: react-markdown, rehype-katex, react-syntax-highlighter (very heavy)
NewPostModalContainer imports: convert_movie.ts (canvas/MediaRecorder), convert_image.ts
- Both are only needed on specific user actions, not on initial page load
- The existing AppContainer already has
<Suspense> around <Routes> — CrokContainer inside routes benefits automatically
- NewPostModalContainer is rendered outside Routes and needs its own Suspense wrapper