From Vite to Next.js

I made my first commit on GitHub last year by creating a repository to build a crossword game. Fast forward to February and I'm converting a whole existing codebase from one language I no zero about to one I know very little about, thanks to Trae.

This is pretty much a summary of the bugs I faced while migrating the codebase from Vite to Next.js in less than 24 hours; bugs that almost knocked me out, even with Trae for help. Thank God for chicken — no kidding.

The initial challenge: module resolution

My first major hurdle came from the different module resolution strategies between Vite and Next.js. Vite's more lenient approach to imports clashed with Next.js's stricter requirements.

The bug:

// This worked in Vite but broke in Next.js
import { SomeComponent } from 'components/SomeComponent'

The solution:

I updated the import paths and configure path aliases in tsconfig.json:

{
  "compilerOptions": {
    "paths": {
      "@/*": ["./"]
    }
  }
}

But this didn't stop there because I also had to fix import issues on multiple files, especially because Trae wasn't fixing all of them at once, which sucked big time as the coding noob that I'm.

React Router vs Next.js Router

One of the trickiest parts was dealing with routing conflicts. The codebase heavily relied on React Router, which apparently doesn't play nicely with Next.js's built-in routing.

The bug:

Multiple routing systems fighting for control led to unpredictable navigation and broken deep links.

The solution:

I gradually migrated to Next.js's App Router, converting all routes to the new format:

// Old React Router approach
<Route path="/dashboard" element={<Dashboard />} />

// New Next.js approach
// app/dashboard/page.tsx
export default function DashboardPage() {
  return <Dashboard />
}

Image optimisation challenges

Vite's approach to image handling differed significantly from Next.js's Image component requirements.

The bug:

Images that worked perfectly in Vite started throwing errors about unoptimised images in Next.js.

The solution:

I configured the Next.js Image component in next.config.js:

module.exports = {
  images: {
    domains: ['[redacted]'],
    formats: ['image/webp']
  }
}

Environment variables

Environment variable handling between Vite and Next.js required some adjustments.

The bug:

// This worked in Vite but failed in Next.js
const apiKey = import.meta.env.VITE_API_KEY

The solution:

const apiKey = process.env.NEXT_PUBLIC_API_KEY

Build configuration

The build process needed significant updates to work with Next.js's requirements.

The solution:

const nextConfig = {
  experimental: {
    esmExternals: false,
  },
  reactStrictMode: true,
  swcMinify: true,
  output: 'standalone'
}

Lessons learned

  1. Plan the migration: A gradual, feature-by-feature migration worked better than a big-bang approach.
  2. Update dependencies early: Identify and update dependencies that might conflict with Next.js.
  3. Test everything: Each migration step needs thorough testing, especially routing and data fetching.
  4. Documentation is key: Keep track of changes and solutions for future reference.

Migrating from Vite to Next.js was challenging but worthwhile. The improved performance, better SEO capabilities, and enhanced customer experience will make this really memorable. Personally tho, every bug was an opportunity to ask Claude/ChatGPT/Deepseek to explain like I'm five, so lots of (un)structured learnings.

Looking forward to the next one!

#curious cat #work