How To Convert CRA To Vite

Introduction

This article explains how to transition your project from Create React App (CRA) to Vite. I want to share my experience and the benefits of making this switch.

In my own development work, I experienced significant performance issues with Create React App, especially in these areas:

  • Slow project startup: Starting a development server in CRA took a considerably long time, especially for larger projects. Waiting for Webpack to bundle everything could take several minutes, which wasted time that could have been spent building.
  • Slow package installation: Installing new packages in a CRA project could take time because of the large number of dependencies CRA manages. This often resulted in longer wait times during development.

When I switched to Vite, the improvement was immediately noticeable:

  • Instant development server startup: Vite's development server starts almost instantly. That means I can start coding and see changes immediately.
  • Faster package installation: Vite has fewer dependencies compared to CRA, which results in faster package installation times.

One primary reason for this change is that CRA stopped receiving major updates and was deprecated by the React team in 2023.

To avoid future issues, I transitioned from CRA to Vite and started taking advantage of these modern improvements to keep projects fast, efficient, and easy to maintain.

Prerequisites

Before starting the conversion from Create React App to Vite, make sure the following requirements are in place.

  1. Node.js and npm

    Ensure you have Node.js and npm installed on your system, preferably version 14.x or higher, since Vite requires Node.js 14.18+. I was using Node.js version 20.7.0. You can verify your installation with:

    node -v
    npm -v
    
  2. Basic understanding of Vite

    I started the conversion by first familiarizing myself with Vite's basics by reading the official Vite documentation. You can also create a fresh Vite project to understand the differences in structure between Vite and CRA.

  3. Back up your project

    Before making significant changes, create a backup of your current CRA project to prevent data loss. You can do this by copying the entire project directory to a safe location or by using version control such as GitHub.

  4. Install Vite

    You will need to install Vite and its dependencies in your project. This can be done through npm or yarn once you begin the conversion.

  5. Understand your project structure

    Have a good understanding of your current CRA project structure, including configuration files, entry points, and where static assets are located. This will make the migration much smoother.

Once these prerequisites are in place, you are ready to start converting your CRA project to Vite.

Steps for Conversion

1. Set Up Vite

First, set up a new Vite project within your existing CRA project. Start with these steps:

  1. Install Vite

    Navigate to your CRA project directory and install Vite along with the necessary Vite plugin for React:

    npm install vite @vitejs/plugin-react
    
  2. Update package.json scripts

    Since Vite will handle the build and development processes, react-scripts are no longer needed. Remove it from your project:

    npm uninstall react-scripts
    

    Update the scripts section in your package.json so it uses Vite instead of CRA:

    "scripts": {
      "start": "PORT=3000 NODE_ENV=development vite",
      "start-secure": "NODE_ENV=development && HTTPS=true vite",
      "build": "tsc && vite build",
      "preview": "vite preview"
    }
    

    If you already use ESLint and Prettier, you can also add:

    "format": "npx prettier --write .",
    "lint": "eslint '*/**/*.{js,ts,tsx}' --quiet --fix"
    

2. Configure Vite

Create a vite.config.ts file in the root of your project and configure Vite for your React setup. To stay as close to CRA as possible, I set the build directory to build instead of dist and used port 3000 for development:

import react from '@vitejs/plugin-react'
import path from 'path'
import { defineConfig } from 'vite'

export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
    },
  },
  build: {
    outDir: './build',
  },
  server: {
    port: 3000,
  },
})

3. Update index.html

In Vite, the entry HTML file should live in the root directory. Move your CRA public/index.html file to the project root and update the script reference.

  1. Move public/index.html to the project root.
  2. Modify the <script> tag so it points to the Vite entry file:
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1, shrink-to-fit=no, maximum-scale=1, user-scalable=no"
    />
    <link rel="shortcut icon" href="/favicon.svg" />
    <meta name="description" content="My Vite App Description" />
    <title>My Vite App</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
    <script type="module" src="/src/main.jsx"></script>
  </body>
</html>

4. Adjust Project Structure

Ensure that your index.ts or index.tsx file is in the src directory and rename it to main.tsx so it matches the script reference in index.html.

5. Update Imports

I used path aliases to keep import statements cleaner and more maintainable. In the vite.config.ts example above, the @ alias points to ./src, so you can import files like this:

import MyComponent from '@/components/MyComponent'

6. Migrate Static Assets

Vite handles static assets differently than CRA. Move your static assets from the public folder to src/assets and update import paths in the relevant components.

For example, if you have an image in public/images/logo.png, move it to src/assets/images/logo.png and update the import:

import logo from './assets/images/logo.png'

7. Install Necessary Plugins

Vite has a plugin system similar to CRA's Webpack configuration. Install any necessary plugins to support the features your project depends on, such as environment variables, CSS preprocessing, or other build-time needs.

8. TypeScript Configuration

To use TypeScript, you will need to configure both tsconfig.json and tsconfig.node.json.

  1. tsconfig.json

    Create a tsconfig.json file in the root of your project with the following configuration:

    {
      "compilerOptions": {
        "target": "ESNext",
        "useDefineForClassFields": true,
        "lib": ["DOM", "DOM.Iterable", "ESNext"],
        "allowJs": true,
        "skipLibCheck": true,
        "esModuleInterop": true,
        "noFallthroughCasesInSwitch": true,
        "allowSyntheticDefaultImports": true,
        "strict": true,
        "forceConsistentCasingInFileNames": true,
        "module": "ESNext",
        "moduleResolution": "Node",
        "resolveJsonModule": true,
        "isolatedModules": true,
        "noEmit": true,
        "baseUrl": ".",
        "paths": {
          "@/*": ["./src/*"]
        },
        "jsx": "react-jsx"
      },
      "include": ["src"],
      "references": [{ "path": "./tsconfig.node.json" }]
    }
    
  2. tsconfig.node.json

    Create a tsconfig.node.json file for Vite-specific TypeScript settings:

    {
      "compilerOptions": {
        "composite": true,
        "module": "ESNext",
        "moduleResolution": "bundler",
        "isolatedModules": true,
        "esModuleInterop": true,
        "skipLibCheck": true
      },
      "include": ["vite.config.ts"]
    }
    

    You can read more about these options in the TypeScript documentation.

9. Remove react-env.d.ts and Add vite-env.d.ts

Replace react-env.d.ts with vite-env.d.ts to ensure the correct TypeScript types are used for Vite.

  1. Remove react-env.d.ts

    Delete the react-env.d.ts file from your project.

  2. Add vite-env.d.ts

    Create a new file named vite-env.d.ts in the src directory with:

    /// <reference types="vite/client" />
    

10. Test and Debug

Start the Vite development server to make sure everything is working correctly:

npm run start

11. Build for Production

To build the project for production:

npm run build

This will generate a production-ready build in the build directory, similar to CRA.

12. Test the Build Output

After building the project for production, serve the build output locally to make sure the app works as expected:

npx serve -s build