TaskFlow Workshop — Challenge 23 of 26
Add code splitting and skeleton loading states to TaskFlow so that heavy pages are loaded on-demand instead of bundled together with the initial JavaScript.
- Use
React.lazyto split page components into separate chunks - Wrap lazy components with
<Suspense>and meaningful fallback UIs - Build skeleton loaders that reflect the actual shape of the UI (not spinners)
- Understand route-level vs component-level code splitting
- Measure real bundle-size impact with Vite's build output
Open src/App.tsx. The panel is currently imported eagerly:
import { ProjectDetailPanel } from './pages/ProjectDetailPanel'Change it to a lazy import:
const ProjectDetailPanel = React.lazy(() => import('./pages/ProjectDetailPanel'))React.lazy requires the module's default export.
Open src/pages/ProjectDetailPanel.tsx and confirm it exports:
export function ProjectDetailPanel() { ... } // named — kept for tests
export default ProjectDetailPanel // default — required by lazyRepeat the same process for NewProjectPage.
Create the following skeleton components inside src/components/skeletons/:
| File | Used as fallback for |
|---|---|
ProjectDetailSkeleton.tsx |
ProjectDetailPanel |
FormSkeleton.tsx |
NewProjectPage |
PageSkeleton.tsx |
Generic full-page fallback |
Skeleton elements should use the .skeleton CSS class defined in App.css
(shimmer animation). Show UI shapes that match the real content layout — not a
spinner or a blank screen.
In src/App.tsx, wrap each lazy component with its skeleton fallback:
<Route
path=":projectId"
element={
<Suspense fallback={<ProjectDetailSkeleton />}>
<ProjectDetailPanel />
</Suspense>
}
>Do the same for the /projects/new route using <FormSkeleton />.
Run npm run build and inspect the output:
npm run build
You should see separate chunk files for ProjectDetailPanel and NewProjectPage.
Compare total bundle size before and after your changes.
The start/ directory is identical to Challenge 22's solution with one
exception: all page imports are eager (no React.lazy, no <Suspense>,
no skeleton components exist yet).
-
ProjectDetailPanelis loaded viaReact.lazy -
NewProjectPageis loaded viaReact.lazy - Each lazy component has a matching
<Suspense>boundary with a skeleton fallback - Skeleton components render shape-based placeholders (not spinners)
-
npm run buildproduces separate chunk files for lazy-loaded pages - All existing tests still pass:
npm test - TypeScript strict-mode —
npm run buildmust succeed with zero errors
cd start # or cd solution
npm install
npx msw init public/ # generates public/mockServiceWorker.js
npm run devOpen http://localhost:5173 in your browser.
npm test