Purpose
- Capture high-impact, prioritized, and actionable tasks derived from the recent Next.js portfolio audit (bundle analysis, metadata, images, fonts, client/server component split, and SEO schema).
- For each task: include a short contract, files to change, implementation steps, validation commands, acceptance criteria, and estimated effort.
How to use this file
- Pick tasks in priority order (P0 -> P1 -> P2). Each task is actionable and small enough to implement, test, and iterate.
- After implementing a task, run the verification commands (build/analyze + Lighthouse) and mark it Done.
Summary of priorities
- P0 — Critical: affects initial page load, LCP, or large shared bundles. Fix these first.
- P1 — High: meaningful impact on JS/CSS or SEO but lower immediate risk.
- P2 — Nice-to-have: incremental gains, content improvements, or documentation.
P0 — Immediate (highest impact)
- Extract top modules from the large shared chunks and create per-module plan
- Contract: Produce an exact list of modules that compose the two ~50KB shared chunks reported by the build analyzer. Output the top 6 contributors (by bytes) and map them to source files/components.
- Files touched: none (analysis step). Optionally create a follow-up branch/PR per module.
- Steps:
- Generate production analyzer (already done) and open the client analyzer report:
.next/analyze/client.html. - Use the analyzer UI to inspect chunk contents and note module paths, or use source-map tools if you prefer CLI (productionBrowserSourceMaps is enabled).
- For each top module, decide: (a) dynamic import (lazy), (b) replace with CSS/inline SVG, or (c) swap for a lighter library.
- Generate production analyzer (already done) and open the client analyzer report:
- Validation:
- Run
ANALYZE=true npm run buildthen open.next/analyze/client.htmland confirm the list. - Acceptance: a concrete list of the top 6 modules with recommended remediation for each.
- Run
- Est. effort: 15–30 min.
Commands:
ANALYZE=true npm run build
open .next/analyze/client.html
# optional: analyze a bundle file with source-map-explorer (requires installing it)
# npx source-map-explorer .next/static/chunks/<chunk>.js .next/static/chunks/<chunk>.js.map- Eliminate framer-motion from initial render path (site-wide sweep)
- Contract: Replace framer-motion usage in components that affect initial render (Hero, Navbar, Header, Footer, and any SSR/Server components rendered on first paint) with either CSS transitions or lazy/dynamic import of framer-motion.
- Files to change (examples):
components/hero.tsx(already done)components/navbar/index.tsx(already done)components/header.tsxcomponents/footer.tsxcomponents/blog/blog-card.tsxcomponents/project-card.tsxcomponents/featured-projects.tsx- other components that import
framer-motion
- Steps:
- Find remaining framer-motion imports: search for "framer-motion".
- For components that are part of the first meaningful paint, remove framer-motion and implement simple CSS animations/transitions.
- For non-critical interactive animations, use dynamic import:
const Motion = dynamic(() => import('framer-motion'), { ssr: false })and wire small wrappers so the component only loads it on interaction. - Rebuild and re-run analyzer.
- Validation:
- Acceptance: initial First Load JS shared by all decreases by at least 20–30 KB (or top framer-motion modules no longer present in the shared chunks).
- Re-run
ANALYZE=true npm run buildand verify.next/analyze/client.htmlshows framer-motion code removed from initial chunks.
- Est. effort: 1–3 hours depending on number of uses.
- Icon strategy: stop importing large icon libraries into shared bundle
- Contract: Replace broad imports from
lucide-react,react-icons, or@radix-ui/react-iconsthat pull whole icon sets into the shared chunk. Use per-icon direct imports, inline optimized SVG, or a lightweight icon sprite. - Files to change (examples):
components/header.tsx,components/footer.tsx,components/theme-switcher.tsx,components/ui/*components that import icons
- Steps:
- Find all imports from icon libraries:
grep -R "from 'lucide-react'" -nand similar forreact-icons.
- For each icon, change to per-icon import pattern (if library supports it), or copy the minimal SVG into a small
icons/folder and export a React component. - Replace icons in footer/header/header-nav and theme toggle.
- Rebuild and analyze.
- Find all imports from icon libraries:
- Validation:
- Acceptance: icon library code no longer appears in the top shared chunks; total JS decreases appropriately (measure with analyzer).
- Est. effort: 1–2 hours.
- Contract: Convert any remaining inlined
<img>markup that appears in blog data or components tonext/imagewhen images are part of content rendered by Next, and ensure explicit width/height,decoding="async",loading="lazy"(for non-LCP), and modern formats (AVIF/WebP). - Files to change:
lib/blog-data.ts(some fixes already done)- Components that still render
<img>directly (search for<imgoccurrences)
- Steps:
- Audit
public/Imagesand compress convert to AVIF/WebP with a tool likesquooshorsharpbased scripts. Keep fallbacks if needed. - Replace
<img>withImagefromnext/imageand add explicit sizes. - Preload LCP image (hero/profile) in
app/layout.tsxorapp/page.tsxwith<link rel="preload" as="image" href="/path/to/lcp.avif">and ensurepriorityset for next/image on that image.
- Audit
- Validation:
- Acceptance: LCP image served in modern format where supported; Lighthouse LCP improves; no remaining unoptimized
<img>for hero/critical images.
- Acceptance: LCP image served in modern format where supported; Lighthouse LCP improves; no remaining unoptimized
- Est. effort: 30–90 min.
P1 — High priority
- Audit and reduce client components (convert to server where possible)
- Contract: Find components that are currently client-only ("use client") but do not use client-only features (state/hooks/browser APIs) and convert them back to server components. This reduces client bundle size and tree-shakes dependencies.
- Files to check:
components/ui/*,components/blog/*,components/navbar/*,components/header.tsxetc. - Steps:
- Search for "use client" across the codebase and document each file.
- For each file: reason about whether it needs client behavior; if not, remove "use client" and adjust interactions to use progressive enhancement (e.g., use small client wrappers only where necessary).
- Rebuild and check bundle sizes.
- Validation:
- Acceptance: measurable reduction in First Load JS and/or removal of large imports from client-bundles.
- Est. effort: 1–3 hours (depends on codebase size).
- Dynamic import large feature components and pages
- Contract: Lazy load non-critical UI and feature modules (blog preview cards, project-card, featured-projects, heatmap, charts) using
dynamic()orReact.lazy+ Suspense to ensure they load only when needed. - Files to change:
components/blog/blog-card.tsx-> lazy in blog listingcomponents/project-card.tsx-> lazy for project gridcomponents/featured-projects.tsx-> lazy on homepage if below the foldcomponents/github-contribution-heatmap.tsx-> load client-only and dynamiccomponents/stats-charts.tsx(already dynamic) — confirm
- Steps:
- Identify components used below-the-fold or in lists.
- Wrap them with
const Comp = dynamic(() => import('./comp'), { ssr: false })or use{ssr: true, loading: () => <Skeleton />}depending on need. - Add lightweight placeholders/skeletons to avoid layout shift.
- Rebuild and analyze.
- Validation:
- Acceptance: decreased initial bundle and improved Lighthouse "Reduce unused JS" metric.
- Est. effort: 1–4 hours across components.
- Fonts: preload & subset critical fonts
- Contract: Preload only the fonts required for initial render and ensure the font CSS uses
font-display: swap. Consider subsetted variable fonts for the site to reduce font bytes. - Files to change:
app/layout.tsx(or head/metadata) to add link rel=preload- font CSS or tailwind config if custom fonts used
- Steps:
- Identify fonts used on first paint (hero and nav).
- Add
<link rel="preload" href="/fonts/xxx.woff2" as="font" type="font/woff2" crossorigin>for only the critical fonts. - Use a subset or variable font when possible.
- Check
font-displayin CSS.
- Validation:
- Acceptance: reduced FOIT/CLS and improved Lighthouse fonts metrics.
- Est. effort: 30–90 min.
P2 — Medium / Lower priority
- Improve metadataBase & canonical host wiring
- Contract: Ensure
metadataBaseis set fromSITE_URLinapp/metadata.tsandapp/layout.tsx(already present but double-check during build). Add canonical tags and open graph image optimization. - Steps:
- Confirm the SITE_URL env/constant is correct for production builds.
- Add canonical link tags in per-page metadata when required.
- Validation:
- Acceptance: no metadataBase warning at build time; correct canonical URLs in page source.
- Est. effort: 15–30 min.
- Content/SEO improvements (schema, internal linking). Note: /hire page was removed per request.
- Contract: Continue to expand per-post structured data (if blog author varies), add internal linking for high-value keywords (e.g., "full stack developer Shailesh Chaudhari") and target high-value pages with clear CTAs.
- Steps:
- Audit blog posts for H1/H2 usage and keyword presence.
- Expand JSON-LD where appropriate (BreadcrumbList, Organization if needed).
- Validation:
- Acceptance: structured data tests pass (Rich Results Test); on-page headings include primary keywords.
- Est. effort: 1–6 hours (content work varies).
- Build & CI checks: add automated analyzer runs and Lighthouse (LHCI) to CI
- Contract: Add a CI job that runs
npm run build,ANALYZE=true npm run build(or a smaller analyzer job), and a Lighthouse audit (or LHCI) for the main pages to detect regressions automatically. - Steps:
- Add a GitHub Actions workflow that runs on PR and pushes to main.
- Run build, export analyzer artifacts (as job artifacts), run LHCI to record performance metrics.
- Validation:
- Acceptance: CI artifacts contain analyzer HTML and LHCI summaries; PRs fail if key thresholds are exceeded.
- Est. effort: 1–3 hours.
Quality gates and verification
- Always run these after each change:
npm run build
ANALYZE=true npm run build # check .next/analyze/client.html
# Run a local Lighthouse audit or LHCI
npx lhci autorun --collect.collectUrl=http://localhost:3000 --upload.target=temporary-public-storage- Minimum acceptance criteria for major tasks:
- P0 tasks: decrease First Load JS by measurable bytes and remove the heavy module from the
shared by allchunks. - LCP: improve or keep stable after image optimizations.
- No new build errors or type errors.
- P0 tasks: decrease First Load JS by measurable bytes and remove the heavy module from the
Notes & edge cases
- Some visual animations removed for performance may reduce polish. Prefer to replace with lightweight CSS transitions.
- Dynamic-importing too aggressively can hurt UX (content not present until JS loads). Use skeletons and placeholders.
- On external image hosting or CDNs, verify CORS/headers for
next/imagewhen switching to AVIF/WebP.
Next immediate actions (what I recommend doing now)
- Parse
.next/analyze/client.htmlto extract the exact module list for the two large shared chunks (task #1). I can do this and produce a prioritized per-file remediation list. - Sweep remaining
framer-motionimports and plan replacements/dynamic imports (task #2).
If you want, I can start with the analyzer parsing now and open a PR for the top 2–3 targeted code changes (for example: icon strategy + dynamic framer-motion import for blog cards).
Revision history
- 2025-10-04: Created by automated audit assistant; covers audit findings and prioritized todos for performance and SEO.