Skip to content

feat: migrate to Next.js 15, React 19, and Tailwind CSS 4#3

Open
hellodun wants to merge 8 commits into
mainfrom
feat/nextjs-15-migration
Open

feat: migrate to Next.js 15, React 19, and Tailwind CSS 4#3
hellodun wants to merge 8 commits into
mainfrom
feat/nextjs-15-migration

Conversation

@hellodun

Copy link
Copy Markdown
Owner

Summary

This PR upgrades the entire project from Next.js 13.4.9 to the latest modern architecture, fixing anti-patterns along the way and bringing all dependencies to their current major versions.

Dependency upgrades

  • next 13.4.9 → 15.x (Turbopack enabled for dev)
  • react / react-dom 18.2.0 → 19.x
  • tailwindcss 3.3.3 → 4.x
  • next-themes 0.2.1 → 0.4.4 (React 19 support)
  • lucide-react 0.260 → 0.474
  • eslint 8 → 9, typescript 5.1 → 5.7
  • Move type defs and dev tools to devDependencies

Config file migrations

  • next.config.jsnext.config.ts (typed NextConfig)
  • tailwind.config.js deleted — custom theme colors now live in globals.css via the Tailwind v4 @theme directive
  • postcss.config.js updated to use @tailwindcss/postcss
  • .eslintrc.jsoneslint.config.mjs (ESLint 9 flat config)
  • tsconfig.json: target es5es2017, moduleResolution nodebundler

Tailwind class renames

Tailwind CSS 4 @theme generates kebab-case utility names. All custom color classes updated across components:

  • primaryLightprimary-light
  • secondaryLightsecondary-light
  • primaryDarkprimary-dark
  • secondaryDarksecondary-dark

Mobile menu refactor

MenuButton.tsx and MobileMenu.tsx used document.getElementById / classList to communicate — a React anti-pattern. Replaced with a single MobileNav.tsx client component that manages visibility via useState and cleans up a resize listener via useEffect.

Component and module fixes

  • Links.tsx split into two files: Links.tsx (server-safe plain data) and NavLinks.tsx (client component with JSX icons), properly respecting the Next.js 15 server/client module boundary
  • Sidebar.tsx marked "use client" since it renders client-provided JSX from NavLinks.tsx
  • providers.tsxJSX.ElementReactNode (global JSX namespace removed in React 19)
  • FooterNote.tsx — hardcoded 2023{new Date().getFullYear()}
  • lib/styles.ts created to hold childrenCommonStyles, removing a circular import from the layout file
  • suppressHydrationWarning removed from <main> (was masking the now-fixed DOM anti-pattern)

Cleanup

  • Removed unused public/next.svg and public/vercel.svg
  • Updated README.md with current tech stack, full project structure, and getting-started instructions

Test plan

  • npm install completes without errors
  • npm run build compiles and statically generates all routes
  • npm run lint reports no warnings or errors
  • npm run dev starts Turbopack dev server on localhost:3000
  • All 4 pages render correctly
  • Dark/light theme toggle works on desktop and mobile
  • Mobile menu opens, closes on button click, link click, and resize to desktop width
  • Footer shows current year dynamically
  • No hydration warnings in the browser console

Duncan Gatuthu and others added 7 commits March 24, 2026 11:54
Upgrade all core dependencies to their latest major versions:
- next 13.4.9 → 15.2.0+
- react/react-dom 18.2.0 → 19.0.0+
- tailwindcss 3.3.3 → 4.0.0+
- next-themes 0.2.1 → 0.4.4+
- lucide-react 0.260.0 → 0.474.0+
- eslint 8 → 9, typescript 5.1 → 5.7+

Move type definitions, linting, and build tools to devDependencies.
Add @tailwindcss/postcss and @eslint/eslintrc for v4/v9 compatibility.
Enable Turbopack in dev script. Remove autoprefixer (built into Tailwind 4).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace next.config.js with next.config.ts (typed NextConfig)
- Delete tailwind.config.js, move to CSS-first config in globals.css
  using @import "tailwindcss" and @theme directive for custom colors
- Update postcss.config.js to use @tailwindcss/postcss plugin
- Replace .eslintrc.json with eslint.config.mjs (ESLint 9 flat config)
- Update tsconfig.json: target es5 → es2017, moduleResolution node → bundler

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tailwind CSS 4 @theme directive produces kebab-case utility names.
Rename all custom color references across components and pages:
- primaryLight → primary-light
- secondaryLight → secondary-light
- primaryDark → primary-dark
- secondaryDark → secondary-dark

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove MenuButton.tsx and MobileMenu.tsx which used direct DOM
manipulation (document.getElementById, classList.add/remove) to
communicate — a React anti-pattern.

Replace with MobileNav.tsx, a single client component that manages
menu open/close state via useState and handles resize cleanup via
useEffect. Update Navbar.tsx to use MobileNav instead of MenuButton.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Split Links.tsx into server-safe data (Links.tsx) and client-side
  JSX with icons (NavLinks.tsx with "use client") to properly handle
  the server/client module boundary in Next.js 15
- Add "use client" to Sidebar.tsx since it renders client-provided JSX
- Fix providers.tsx: replace deprecated JSX.Element with ReactNode
  (global JSX namespace removed in React 19)
- Fix FooterNote.tsx: dynamic copyright year, remove unused React import
- Extract childrenCommonStyles to lib/styles.ts to avoid circular
  imports from layout files; update all page imports

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Delete next.svg and vercel.svg from public/ — leftover boilerplate
from create-next-app that are not referenced anywhere in the project.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rewrite README to reflect the upgraded tech stack:
- Updated tech stack section (Next.js 15, React 19, Tailwind CSS 4)
- Added complete project structure tree
- Added Getting Started section with prerequisites, install, dev,
  build, and lint instructions
- Updated features list

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@vercel

vercel Bot commented Mar 24, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
duncan-site-5lx1 Ready Ready Preview, Comment Mar 24, 2026 9:24am

Add engines field to package.json and .nvmrc file specifying Node.js
24.x. Vercel discontinued Node.js 18.x — this ensures the deployment
platform uses a supported runtime version.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant