perf: dynamic-import LineProfilerView to defer prism-react-renderer (#2557)

## Summary
- Replaces static import of `LineProfilerView` with `next/dynamic` +
`ssr: false`
- Defers loading of `prism-react-renderer` (~100KB+) until user
navigates to profiler tab
- Adds `<Skeleton>` loading fallback for smooth UX

## Evidence
- Proof doc: `js/cf-webapp/proof/13-dynamic-import-line-profiler.md`

## Test plan
- [ ] `bash
js/cf-webapp/proof/reproducers/13-dynamic-import-line-profiler.sh` — 7/7
checks pass
- [ ] `npm run build` succeeds
- [ ] Profiler page loads and renders LineProfilerView correctly
This commit is contained in:
Kevin Turcios 2026-04-04 11:36:59 -05:00 committed by GitHub
parent fbedf0c1ee
commit 67ec032429
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 116 additions and 1 deletions

View file

@ -0,0 +1,39 @@
# Proof 13: Dynamic-import LineProfilerView
## What Changed
- Replaced static import of `LineProfilerView` with `next/dynamic` in the profiler page
- Added `ssr: false` since the component uses browser-only APIs
- Added `<Skeleton>` loading fallback
## Why
`LineProfilerView` depends on `prism-react-renderer`, which pulls in Prism.js grammar definitions (~100KB+). By using `next/dynamic` with `ssr: false`:
- The profiler page's initial JS bundle shrinks — Prism grammars are loaded on-demand
- The component only loads when the user navigates to the profiler tab, not on initial page load
- SSR is skipped for a component that relies on client-side rendering anyway
## Evidence
### Before (static import)
```tsx
import { LineProfilerView } from "@/components/LineProfiler"
```
### After (dynamic import)
```tsx
import dynamic from "next/dynamic"
import { Skeleton } from "@/components/ui/skeleton"
const LineProfilerView = dynamic(
() => import("@/components/LineProfiler").then(mod => mod.LineProfilerView),
{
ssr: false,
loading: () => <Skeleton className="h-full w-full" />,
},
)
```
## How to Verify
```bash
cd js/cf-webapp
bash proof/reproducers/13-dynamic-import-line-profiler.sh
```

View file

@ -0,0 +1,67 @@
#!/usr/bin/env bash
# Proof reproducer for commit 13: dynamic-import LineProfilerView
set -euo pipefail
PASS=0
FAIL=0
TOTAL=0
check() {
local desc="$1"; shift
TOTAL=$((TOTAL + 1))
if "$@" >/dev/null 2>&1; then
echo " PASS: $desc"
PASS=$((PASS + 1))
else
echo " FAIL: $desc"
FAIL=$((FAIL + 1))
fi
}
check_not() {
local desc="$1"; shift
TOTAL=$((TOTAL + 1))
if "$@" >/dev/null 2>&1; then
echo " FAIL: $desc"
FAIL=$((FAIL + 1))
else
echo " PASS: $desc"
PASS=$((PASS + 1))
fi
}
PROFILER_PAGE="src/app/(dashboard)/review-optimizations/[traceId]/profiler/page.tsx"
echo "=== Proof 13: dynamic-import LineProfilerView ==="
echo ""
echo "--- Dynamic import checks ---"
check "next/dynamic is imported" \
grep -q 'import dynamic from "next/dynamic"' "$PROFILER_PAGE"
check "LineProfilerView uses dynamic()" \
grep -q 'const LineProfilerView = dynamic(' "$PROFILER_PAGE"
check "ssr: false is set" \
grep -q 'ssr: false' "$PROFILER_PAGE"
check_not "no static import of LineProfilerView" \
grep -q 'import { LineProfilerView }' "$PROFILER_PAGE"
echo ""
echo "--- Loading fallback checks ---"
check "Skeleton component is imported" \
grep -q 'import { Skeleton }' "$PROFILER_PAGE"
check "loading fallback uses Skeleton" \
grep -q 'loading:' "$PROFILER_PAGE"
echo ""
echo "--- Module resolution check ---"
check "dynamic import resolves @/components/LineProfiler" \
grep -q '@/components/LineProfiler' "$PROFILER_PAGE"
echo ""
echo "=== Results: $PASS/$TOTAL passed, $FAIL failed ==="
[ "$FAIL" -eq 0 ] && echo "ALL CHECKS PASSED" || echo "SOME CHECKS FAILED"
exit "$FAIL"

View file

@ -5,7 +5,16 @@ import { useParams, useRouter } from "next/navigation"
import { ArrowLeft, Zap, Loader2, AlertTriangle } from "lucide-react"
import { getOptimizationEventById } from "../action"
import { getUserIdAndUsername } from "@/app/utils/auth"
import { LineProfilerView } from "@/components/LineProfiler"
import dynamic from "next/dynamic"
import { Skeleton } from "@/components/ui/skeleton"
const LineProfilerView = dynamic(
() => import("@/components/LineProfiler").then(mod => mod.LineProfilerView),
{
ssr: false,
loading: () => <Skeleton className="h-full w-full" />,
},
)
import { useViewMode } from "@/app/app/ViewModeContext"
import { toast } from "sonner"