diff --git a/docs/APSC174_OPTIMIZATION.md b/docs/APSC174_OPTIMIZATION.md new file mode 100644 index 0000000..68afe2f --- /dev/null +++ b/docs/APSC174_OPTIMIZATION.md @@ -0,0 +1,226 @@ +# APSC174 Backend Optimization Guide + +Repository: `github.com/JackSwitzerSchool/APSC174` +Site: `apsc174.jackswitzer.com` + +## Current Tech Stack + +| Component | Version | Notes | +|-----------|---------|-------| +| Next.js | 14.2.23 | App Router | +| React | 18.2.0 | | +| TypeScript | 5.3.3 | | +| Tailwind CSS | 3.4.1 | | +| MDX | next-mdx-remote 4.4.1 | Runtime serialization | +| KaTeX | 0.16.9 | Math rendering | +| Deployment | Vercel | Single region (iad1) | + +## Identified Performance Issues + +### Critical (Causing Slow TTFB/LCP) + +1. **No Static Generation** + - File: `app/[...slug]/page.tsx` + - Issue: Missing `generateStaticParams()` - all 58 pages are SSR'd on every request + - Impact: ~500-1500ms added per page load + +2. **Client-Side Only MDX** + - File: `app/[...slug]/page.tsx` (line 7-10) + - Issue: `dynamic(() => import(...), { ssr: false })` prevents server rendering + - Impact: Content requires JS hydration to display + +3. **Runtime MDX Serialization** + - File: `lib/content.ts` (line 97) + - Issue: `serialize()` runs on every request instead of build time + - Impact: ~200-500ms per page + +### High + +4. **External KaTeX CSS** + - File: `app/layout.tsx` (line 57-61) + - Issue: CDN fetch blocks rendering + - Fix: Self-host with `import 'katex/dist/katex.min.css'` + +5. **Single Region Deployment** + - File: `vercel.json` (line 6) + - Issue: `"regions": ["iad1"]` - only Virginia + - Fix: Add `["iad1", "sfo1", "cdg1"]` for US West + Europe + +### Medium + +6. **Overly Broad Middleware** + - File: `middleware.ts` + - Issue: Runs on every non-static request + - Fix: Narrow matcher to only `/content/:path*` + +7. **Unnecessary API Route** + - File: `app/api/content/route.ts` + - Issue: Re-serializes MDX on every API call + - Fix: Remove entirely - not needed with static generation + +8. **Manual Terser Config** + - File: `next.config.js` (line 21-32) + - Issue: Next.js handles this automatically + - Fix: Remove the custom webpack optimization block + +## Fix Implementation + +### 1. Add Static Generation (HIGHEST PRIORITY) + +In `app/[...slug]/page.tsx`, add: + +```tsx +import { getNotes } from '@/app/notes/utils' + +export const revalidate = 3600 // ISR: revalidate hourly + +export async function generateStaticParams() { + const notes = await getNotes() + + return [ + ...notes.map((note) => ({ slug: ['notes', note.slug] })), + { slug: ['course-resources'] }, + { slug: ['tutorials'] }, + { slug: ['internships'] }, + ] +} +``` + +### 2. Enable Server-Side MDX Rendering + +In `app/[...slug]/page.tsx`, change: + +```tsx +// FROM: +const MDXContent = dynamic(() => import('@/app/components/mdx-content'), { + ssr: false, + loading: () =>
Loading...
+}) + +// TO: +import MDXContent from '@/app/components/mdx-content' +``` + +In `app/components/mdx-content.tsx`, remove: +```tsx +'use client' // DELETE THIS LINE +``` + +And remove all `memo()` wrappers (not needed for server components). + +### 3. Self-Host KaTeX CSS + +```bash +# KaTeX is already installed, just need to import differently +``` + +In `app/layout.tsx`: + +```tsx +// ADD at top: +import 'katex/dist/katex.min.css' + +// REMOVE the entire block with the CDN link +``` + +### 4. Multi-Region Deployment + +In `vercel.json`: + +```json +{ + "regions": ["iad1", "sfo1", "cdg1"] +} +``` + +### 5. Simplify Middleware + +Replace `middleware.ts` with: + +```tsx +import { NextResponse } from 'next/server' +import type { NextRequest } from 'next/server' + +export default function middleware(request: NextRequest) { + const pathname = request.nextUrl.pathname + + if (pathname.startsWith('/content/notes/')) { + const slug = pathname.split('/').slice(3).join('/') + return NextResponse.redirect(new URL(`/notes/${slug}`, request.url)) + } + + if (pathname.startsWith('/content/assets/')) { + const assetPath = pathname.split('/').slice(3).join('/') + return NextResponse.redirect(new URL(`/assets/${assetPath}`, request.url)) + } + + if (pathname.startsWith('/content/')) { + const path = pathname.split('/').slice(2).join('/') + return NextResponse.redirect(new URL(`/${path}`, request.url)) + } + + return NextResponse.next() +} + +export const config = { + matcher: ['/content/:path*'] +} +``` + +### 6. Clean Up next.config.js + +Remove the entire webpack optimization block (lines 15-33). Next.js handles minification automatically. + +### 7. Delete API Route + +Remove the entire `app/api/content/` directory. + +### 8. Add ISR to Notes Page + +In `app/notes/page.tsx`, add at top level: + +```tsx +export const revalidate = 3600 +``` + +## Expected Impact + +| Metric | Before | After | +|--------|--------|-------| +| TTFB | 800-1500ms | 50-200ms | +| LCP | 2-4s | 0.5-1.5s | +| FCP | 1.5-3s | 0.3-0.8s | +| Build time | ~30s | ~60s | +| Runtime compute | Every request | Zero (pre-built) | + +## Content Structure Reference + +``` +content/ +└── notes/ # 58 markdown files + ├── Sets.md + ├── Mapping.md + ├── basis.md + ├── eigen-stuff.md + └── ... +``` + +## Key Files to Modify + +1. `app/[...slug]/page.tsx` - Add generateStaticParams, remove dynamic import +2. `app/components/mdx-content.tsx` - Remove 'use client' and memo +3. `app/layout.tsx` - Self-host KaTeX CSS +4. `app/notes/page.tsx` - Add revalidate +5. `middleware.ts` - Simplify and narrow scope +6. `next.config.js` - Remove Terser config +7. `vercel.json` - Add regions +8. `app/api/content/route.ts` - DELETE + +## Coherence with JackSwitzer.com + +The optimized APSC174 will mirror JackSwitzer.com patterns: +- Both use `generateStaticParams` for static generation +- Similar simplified next.config.js +- Consistent Vercel analytics/speed-insights usage +- Same Geist font configuration +- Matching tailwind setup