From 7f50abe86649f097b935aff3dd34452e5825a4c9 Mon Sep 17 00:00:00 2001 From: policyengine-bot Date: Sat, 9 May 2026 16:04:53 +0000 Subject: [PATCH] Add Vite to Next.js migration skill for legacy apps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Captures learnings from cbo-baseline-tracker migration (PR #4): - Framework-only migration strategy (preserve UI layer) - index.html → app/layout.tsx (Metadata API, JSON-LD, GA4) - main.tsx + App.tsx → app/page.tsx + providers.tsx - Client Component marking ('use client' for hooks, browser APIs) - Environment variable migration (VITE_* → NEXT_PUBLIC_*) - Public asset path changes (/public/* → /*) - Common gotchas (dynamic imports, window undefined, default exports) Distinct from policyengine-frontend-builder-spec (new apps) — this skill is for migrating existing Mantine/Plotly/other-framework apps to Next.js without forcing a full rewrite to ui-kit. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../SKILL.md | 480 ++++++++++++++++++ 1 file changed, 480 insertions(+) create mode 100644 skills/tools-and-apis/policyengine-vite-to-nextjs-migration-skill/SKILL.md diff --git a/skills/tools-and-apis/policyengine-vite-to-nextjs-migration-skill/SKILL.md b/skills/tools-and-apis/policyengine-vite-to-nextjs-migration-skill/SKILL.md new file mode 100644 index 0000000..1a294c2 --- /dev/null +++ b/skills/tools-and-apis/policyengine-vite-to-nextjs-migration-skill/SKILL.md @@ -0,0 +1,480 @@ +--- +name: policyengine-vite-to-nextjs-migration +description: Migrating legacy Vite-based PolicyEngine apps (using Mantine, Plotly, or other UI frameworks) to Next.js App Router while preserving existing UI code +--- + +# Vite to Next.js migration for legacy PolicyEngine apps + +How to migrate existing Vite-based PolicyEngine apps to Next.js App Router when they use UI frameworks other than the current standard (@policyengine/ui-kit + Tailwind). + +## When to use this skill + +**Use this skill when:** +- Migrating an existing Vite app to Next.js for consistency with PolicyEngine's deployment stack +- The app uses Mantine, Chakra UI, Material UI, or other component libraries +- The goal is framework migration only (not a full UI rewrite) +- You want to preserve the existing UI code while modernizing the build/deployment layer + +**Do NOT use this skill when:** +- Building a new dashboard or tool from scratch (use `policyengine-frontend-builder-spec` instead — all new apps must use Next.js + Tailwind + ui-kit) +- The app is already on Next.js +- You're doing a full rewrite (in that case, follow the standard stack requirements) + +## Migration strategy + +The migration is **framework-only**: move from Vite bundler + SPA routing to Next.js App Router while keeping all existing UI components and styling unchanged. + +### Core principle: Preserve the UI layer + +Unlike new apps (which must use @policyengine/ui-kit + Tailwind), legacy migrations can retain their existing component library (Mantine, Chakra, etc.) to minimize diff size and risk. + +**What changes:** +- Build system: `vite` → `next build` +- Routing: React Router → App Router file-based routing +- Entry point: `index.html` + `main.tsx` → `app/layout.tsx` + `app/page.tsx` +- Dev server: `vite dev` → `next dev` +- Deployment: Static export via `output: 'export'` in `next.config.ts` + +**What stays the same:** +- All existing components (Mantine, Plotly, etc.) +- All existing styles (CSS modules, component library themes, etc.) +- All existing business logic and state management +- Package manager (keep using `bun`) + +## Migration steps + +### 1. Install Next.js dependencies + +```bash +bun add next react react-dom +bun add -D @types/react @types/react-dom @types/node +``` + +**Remove Vite dependencies:** +```bash +bun remove vite @vitejs/plugin-react +``` + +### 2. Create Next.js configuration + +**next.config.ts:** +```ts +import type { NextConfig } from 'next'; + +const nextConfig: NextConfig = { + output: 'export', // Static export for Vercel deployment + trailingSlash: true, + reactStrictMode: true, +}; + +export default nextConfig; +``` + +**tsconfig.json updates:** +```json +{ + "compilerOptions": { + "target": "ES2020", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "jsx": "preserve", + "module": "ESNext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "allowJs": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "skipLibCheck": true, + "allowSyntheticDefaultImports": true, + "forceConsistentCasingInFileNames": true, + "isolatedModules": true, + "incremental": true, + "plugins": [{ "name": "next" }], + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], + "exclude": ["node_modules"] +} +``` + +### 3. Move from index.html to App Router + +**Old structure (Vite):** +``` +index.html # Entry point with + + + ); +} +``` + +### 6. Google Analytics + +Move GA4 script from `index.html` to `layout.tsx` using `next/script` with `strategy="afterInteractive"`: + +```tsx +import Script from 'next/script'; + +export default function RootLayout({ children }) { + return ( + + + {children} + + + + ); +} +``` + +## Deployment + +Follow standard PolicyEngine Vercel deployment: + +1. Ensure `next.config.ts` has `output: 'export'` +2. Deploy to Vercel under `policy-engine` scope +3. Verify static export works (`bun run build` produces `out/` directory) + +See `policyengine-vercel-deployment-skill` for full deployment instructions. + +## Testing strategy + +**Minimal test changes:** If the app already has tests, they should continue working with minimal changes: + +- If using Vitest: Keep `vitest.config.ts`, update any imports that changed +- If using Jest: May need to update config for Next.js compatibility +- Component tests: Should work unchanged if using Testing Library + +**Focus testing on:** +- [ ] Pages render correctly in both dev and production builds +- [ ] All interactive features work (forms, buttons, charts) +- [ ] API calls succeed +- [ ] Routing works (if multi-page app) + +## When to consider a full rewrite instead + +This migration strategy preserves the existing UI framework. Consider a **full rewrite to the standard PolicyEngine stack** (Next.js + Tailwind + ui-kit) if: + +- The app is small (< 1000 lines of component code) +- The UI framework is outdated or has security issues +- You're making significant UX changes anyway +- The app will receive ongoing development (not a static analysis tool) + +For small tools and active projects, the standard stack provides better long-term maintainability. + +## Related skills + +- **policyengine-frontend-builder-spec** — Required stack for all new PolicyEngine apps +- **policyengine-vercel-deployment-skill** — Deployment patterns +- **policyengine-interactive-tools-skill** — Building new standalone tools (use standard stack)