How to Transition from CRA to Vite: A Step-by-Step Guide


CRA has been one of my favorite tool. It gave us superpower to spin up react app with out of the box support for eslint , postcss , testing library,Web vitals and many more..
Since CRA has been depreciated and now React team recommend using frameworks like next.js, remix…. which are not only huge, but they have framework specific features.
But these are not necessary for small projects that we already built. Or we just want the same flavour as CRA gave as. Why not migrate to Vite.
As you already know about Vite. if not then, Vite is a modern front-end build tool that offers fast development and optimized production builds.
CRA used to depend upon webpack for its build task and all, but it has huge configuration under the hood.
Migration steps
These migration steps assume that we have a CRA project with Typescript.
Removing CRA dependencies
Installing Vite and its dependencies
Moving index.html
Adding vite.config.ts
Replacing react scripts to Vite scripts
Fixing the env
Optional steps
Configuring eslint
Setting up tailwind for Vite
1. Removing the CRA dependencies
First step includes removing all the CRA dependencies which is surprisingly only react-scripts but behind the scenes it has a lot of dependencies. Now, it feels like react-scripts is bloaty. But it is the thing that made React this much popular. It made react apps do the things which were easily not available to setup from scratch.
npm rm react-scripts
But for now, goodbye react-scripts. we will miss you. JSX has never been evolved if you were not there.
2. Installing Vite and its dependencies
Now moving towards the second step, which is letting the damn thing in. Installing the Vite. Vite will be installed as dev dependency since it is only required for building and development purpose.
npm install vite -D
Only Vite is not enough. Since Vite is bundler, which is not specifically for react, so we need to install its additional dependencies for React app.
@vitejs/plugin-react-swc
– A faster, Rust-based plugin for handling React (recommended over the older Babel-based@vitejs/plugin-react
).vite-tsconfig-paths
– Helps Vite resolve TypeScript path aliases.
npm install @vitejs/plugin-react-swc vite-tsconfig-paths
Note: Depending on your specific needs, you can choose a different plugin from the official Vite plugins documentation.
3. Moving index.html
Index.html file is not same in CRA and Vite.
In a Create React App (CRA) project, the index.html
file is located inside the public/
folder. It serves as the main HTML template where the React app is injected.
Key Points:
CRA does not use this file for JavaScript imports; instead, React is injected via
index.js
orindex.tsx
.%PUBLIC_URL%
is a placeholder that gets replaced with the actual public URL at build time.
So, move index.html
file in public/
folder to the root of your project.
And in Vite’s index.html
is directly used as the entry point and includes the script reference manually!
<!-- index.html -->
<body>
.................
.................
<!-- Add this script tag before closing body tag -->
<script type="module" src="/src/index.tsx"></script>
</body>
And replace %PUBLIC_URL%
with / or better use dynamic path to ensure that the assets are referenced correctly in Vite, as Vite does not process %PUBLIC_URL%
like CRA does.
CRA uses
%PUBLIC_URL%
to dynamically inject the base URL, useful when deploying to subdirectories.Vite doesn't need
%PUBLIC_URL%
; it serves static assets directly from/public/
.
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!-- Change like this -->
......
<link rel="manifest" href="/manifest.json" />
<!-- Or better like this -->
........
<link rel="manifest" href="manifest.json" />/>
4. Adding vite.config.ts
create a vite.config.ts
file in root folder of your project and configure for React app using @vitejs/plugin-react-swc
plugin.
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react-swc'
// https://vitejs.dev/config/
export default defineConfig({
base: '/',
plugins: [react()]
})
5. Replacing react scripts to Vite scripts
Updating the scripts
section in package.json
is crucial.
// from this
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
// to this
"scripts": {
"start": "vite",
"build": "tsc && vite build",
"serve": "vite preview"
}
Ensure your package.json
contains:
{
"type": "module"
}
6. fixing the env
In Vite, environment variables must start with VITE_
to be exposed to the frontend.
Rename Environment Variables
Replace REACT_APP_
prefixes with VITE_
in your .env
file:
VITE_API_URL=https://api.example.com
VITE_APP_NAME=My Vite App
Access Environment Variables in Code
Use import.meta.env
instead of process.env
:
console.log(import.meta.env.VITE_API_URL)
console.log(import.meta.env.VITE_APP_NAME)
Enable TypeScript Support for Vite Env Variables
Create a vite-env.d.ts
file inside the src/
directory with the following content:
/// <reference types="vite/client" />
This ensures TypeScript recognizes Vite-specific features like import.meta.env
.
Remove Unnecessary React-Specific Files
If your project has a react-app-env.d.ts
file inside the src/
directory, delete it, as it's only relevant for Create React App (CRA).
7. Configuring eslint (Optional)
This ESLint setup follows the Vite starter template.
Install ESLint and Required Plugins
Run the following command to install ESLint and necessary dependencies:
npm install eslint globals @eslint/js typescript-eslint eslint-plugin-react-hooks eslint-plugin-react-refresh
Create eslint.config.js
In the root of your project, create a new file named eslint.config.js
and add the following configuration:
import js from "@eslint/js";
import globals from "globals";
import reactHooks from "eslint-plugin-react-hooks";
import reactRefresh from "eslint-plugin-react-refresh";
import tseslint from "typescript-eslint";
export default tseslint.config(
{ ignores: ["dist"] },
{
extends: [js.configs.recommended, ...tseslint.configs.recommended],
files: ["**/*.{ts,tsx}"],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
plugins: {
"react-hooks": reactHooks,
"react-refresh": reactRefresh,
},
rules: {
...reactHooks.configs.recommended.rules,
"react-refresh/only-export-components": [
"warn",
{ allowConstantExport: true },
],
},
}
);
Alternative: Using ESLint Official Setup
If you prefer the official ESLint setup, you can run:
npm init @eslint/config@latest
However, this setup is stricter and may not be ideal for all projects.
8. Setting up tailwind for Vite (Optional)
If you're already using Tailwind CSS, you'll need to reconfigure it. For a fresh installation, refer to the official Tailwind CSS documentation for Vite.
Install Tailwind CSS for Vite
Run the following command to install the required dependency:
npm install @tailwindcss/vite
Configure Tailwind in vite.config.ts
Update your vite.config.ts
to include the Tailwind CSS Vite plugin:
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react-swc'
import tailwindcss from '@tailwindcss/vite'
// https://vitejs.dev/config/
export default defineConfig({
base: '/',
plugins: [
react(),
tailwindcss(),
],
})
This ensures Tailwind CSS is properly integrated into your Vite-powered React app.
Subscribe to my newsletter
Read articles from Ahmadullah Mirza directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
