Why you should prefer Vite over Create-React-App

Why you should prefer Vite over Create-React-App

1. What is Vite?

Vite is a next-generation, front-end tool that focuses on speed and performance.

Vite is created by Evan You, who is the creator of Vue.js, but it's not a Vue-only tool. It can be used for React, Preact, Svelte, Vue, Vanilla JS, and LitElements.

It consists of two major parts:

  • A development server that provides rich feature enhancements over native ES modules: fast Hot Module Replacement (HMR), pre-bundling, support for typescript, jsx, and dynamic import.

  • A build command that bundles your code with Rollup, pre-configured to output optimized static assets for production.

Benefits of Vite:

  • Instant Server Start: On demand file serving over native ESM, no bundling required!

  • Lightning Fast HMR: Hot Module Replacement (HMR) that stays fast regardless of app size.

  • Rich Features: Out-of-the-box support for TypeScript, JSX, CSS and more.

  • Optimized Build: Pre-configured Rollup build with multi-page and library mode support.

  • Universal Plugins: Rollup-superset plugin interface shared between dev and build.

  • Fully Typed APIs: Flexible programmatic APIs with full TypeScript typing.

  • Supports React, Vue, Preact, Svelte.

2. Compare Vite and CRA

CRA uses Webpack to bundle the code. Webpack bundles the entire code, so if your codebase is very large more than 10k lines you might see a slower start in the development server and a long waiting time to see the changes made.


Vite uses esbuild which is written in Go and pre-bundles dependencies 10–100x faster than JavaScript-based bundlers.

Vite improves the development server start time by dividing the modules of an application into two categories: dependencies and source code.

Dependencies are mostly plain JavaScript that does not change often during development. Some large dependencies (e.g. AntD) are also quite expensive to process. As dependencies do not change, they can also be cached and we can skip pre-bundling.

Source code often contains non-plain JavaScript that needs transforming (e.g. JSX, CSS or etc components), and will be edited very often. Also, not all source code needs to be loaded at the same time (e.g. with route-based code-splitting). Vite serves source code over native ESM (EMACScript modules - a recent addition to the JavaScript language specification that deals with how modules are loaded in the Javascript application)


There is no need for bundling. That’s a big chunk of work that you don’t have to do anymore. Vite only needs to transform and serve source code on demand, when the browser requests it. Code-behind conditional dynamic imports are only processed if actually used on the current screen.

-> This increases development time, as we need to wait for less for each change, and production build time, and it might take less time to deploy a quick fix.

3. Steps to migrate CRA to Vite

  1. Remove the react-scripts dependency from the package.json.

  2. Add sass in package.json, if you are using CSS or SCSS.

yarn add -D sass
npm i --save-dev sass

3. Add vite and @vitejs/plugin-react as dev dependencies.

"devDependencies": {
 "@vitejs/plugin-react": "1.3.2",
 "vite": "2.7.0"

4. Replace the start and build scripts as below:

"scripts": {
  "start": "vite",
  "build": "vite build"

5. Create a file vite.config.js in the root of the project with the below code:

import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";

export default () => {
  return defineConfig({
    plugins: [react()],

6. Move the index.html file from the public folder to the root of the project.

7. Remove all the occurrences of %PUBLIC_URL% from index.html.
The lines affected should look like the following lines after the change:

<link rel="icon" href="/favicon.ico" />
<link rel="manifest" href="/manifest.json" />
<link rel="apple-touch-icon" href="/logo192.png" />

8. Add the script tag below into the body of index.html:

<script type="module" src="/src/index.jsx"></script>

NOTE: In CRA, src/index has extension of .js, change it to jsx.

9. Change the extension of .js files to .jsx, if they contain jsx syntax.
If not changed, you will get the following error:

[plugin:vite:import-analysis] Failed to parse source for import analysis because the content contains invalid JS syntax. If you are using JSX, make sure to name the file with the .jsx or .tsx extension.

Want to know why this change is needed?
Read through Evan You’s tweet explaining why components containing jsx syntax should have a .jsx extension.

10. Update all environment variables from REACT_APP to VITE.

11. Vite does not support absolute path by default.
You need to either use a relative path or add an alias.

import App from "components/search/App"; // Not supported
import App from '../src/components/search/App'; // Use relative path

You can add an alias in vite.config.js as below:

export default () => {
  return defineConfig({
    plugins: [react()],
    resolve: {
      alias: {
        '@': path.resolve(__dirname, './src'),

Now, you can use the next line:

import App from '@/components/search/App'

Finally installing dependencies using:

yarn install or npm install

12. Start your application with, as shown below:

yarn start
npm start

Voila! Your application has migrated from CRA to Vite! Pretty smooth.