Blog
Unlocking React App Performance: A Step-by-Step Guide to Migrating from CRA to Vite

In recent years, web development has seen a significant shift towards faster and more efficient tooling. Create-React-App (CRA) has been a popular choice for bootstrapping React applications, but it has some limitations, especially when it comes to the development server's speed and optimized production builds. This is where Vite, a modern front-end build tool, comes into play.

Why migrate from CRA to Vite?

Vite addresses some of the pain points of CRA by offering a faster development experience and improved production build optimization.

  1. Fast Cold Server Start: Vite utilizes native ES modules, which enables faster module loading during development. This results in a much quicker cold server start time compared to CRA.
  2. Optimized Builds: Vite utilizes Rollup for production builds, which provides better tree shaking and code optimization compared to CRA's Webpack configuration.
  3. Out-of-the-box CSS Code Splitting: Vite offers CSS code splitting without any additional configuration, which can lead to smaller bundle sizes and faster page loads.
  4. Better TypeScript Support: Vite has built-in support for TypeScript, which eliminates the need for additional plugins and configurations compared to CRA.
  5. Flexible Configuration: Vite offers a more flexible configuration system, allowing developers to easily customize their build setup without ejecting the project.

Project Details

Before we begin, here's some information about our project:

  • It is a React application created using CRA and using Webpack version 5.
  • We used Antd Library and Formik for form elements.
  • We used styled components to define CSS.

Migration Steps

To migrate from CRA to Vite, these are the steps we followed:

1. Install Vite:

Install Vite by running

npm install -D vite

2. Update package.json:

Change your package.json scripts to use Vite. Make sure to delete react-scripts from your dependencies section.

"scripts": {
 "start": "vite",
 "build": "tsc && vite build",
 "serve": "vite preview",
},


3. Create a Vite Configuration File: Create a vite.config.js file at the root of your project with the provided content. We have also added the configuration for styled components within the Babel plugins section.

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import viteTsconfigPaths from 'vite-tsconfig-paths';

export default defineConfig({
  // depending on your application, base can also be "/"
  base: '',
  plugins: [
    react({
      include: /.(jsx|tsx)$/,
      babel: {
        plugins: ['styled-components'],
        babelrc: false,
        configFile: false,
      },
    }),
    viteTsconfigPaths(),
  ],
  define: {
    'process.env': {},
    // By default, Vite doesn't include shims for NodeJS/
    // necessary for segment analytics lib to work
    global: {},
  },
  resolve: {
    alias: [
      {
        find: 'antd/lib',
        replacement: 'antd/es',
      },
      {
        find: 'crypto',
        replacement: 'crypto-js',
      },
    ],
  },
  server: {
    // this ensures that the browser opens upon server start
    open: true,
    // this sets a default port to 3000
    port: 3000,
  },
});


4. Update your tsconfig.json

Make sure to configure your tsconfig.json file with the following settings:

  • Set the target, lib, and module type to esnext. This configuration might need to be updated in future TypeScript versions as more esnext functionality becomes part of the ECMAScript standard. Always refer to the Vite documentation for potential updates if this article is outdated.
  • Add the Vite types to the types section. This inclusion informs TypeScript about the unique Vite browser functionalities that are available for your project.
  • Enable the isolatedModules option. This setting is crucial because some modern TypeScript features are not yet supported by Vite. By setting isolatedModules to true, you ensure better compatibility with Vite. If this option is not already enabled in your configuration, make sure to add it.


{
  "compilerOptions": {
    "target": "ESNext",
    "lib": ["dom", "dom.iterable", "esnext"],
    "types": ["vite/client"],
    "allowJs": false,
    "skipLibCheck": false,
    "esModuleInterop": false,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx"
  },
  "include": ["src"]
}

5. Move the index.html File

Vite has a root directory which your files are served from. Since index.html is the entry point for Vite's server, the file needs to be in the root directory.

From the public directory, move the index.html file to the root of your project.

6. Update the context of index.html

Vite handles URLs in the index.html differently to create react app.

index.html with CRA:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <!--
      manifest.json provides metadata used when your web app is installed on a
      user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
    -->
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <!--
      Notice the use of %PUBLIC_URL% in the tags above.
      It will be replaced with the URL of the `public` folder during the build.
      Only files inside the `public` folder can be referenced from the HTML.

      Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
      work correctly both with client-side routing and a non-root public URL.
      Learn how to configure a non-root public URL by running `npm run build`.
    -->
    <title>React App</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
    <!--
      This HTML file is a template.
      If you open it directly in the browser, you will see an empty page.

      You can add webfonts, meta tags, or analytics to this file.
      The build step will place the bundled scripts into the <body> tag.

      To begin the development, run `npm start` or `yarn start`.
      To create a production bundle, use `npm run build` or `yarn build`.
    -->
  </body>
</html>


Remove any %PUBLIC_URL% references from the file. Just replace that string with "". Add a script tag with the project entry point index.html with Vite:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="apple-touch-icon" href="/logo192.png" />
    <!--
      manifest.json provides metadata used when your web app is installed on a
      user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
    -->
    <link rel="manifest" href="/manifest.json" />
    <!--
      Notice the use of %PUBLIC_URL% in the tags above.
      It will be replaced with the URL of the `public` folder during the build.
      Only files inside the `public` folder can be referenced from the HTML.

      Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
      work correctly both with client-side routing and a non-root public URL.
      Learn how to configure a non-root public URL by running `npm run build`.
    -->
    <title>React App</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
    <!--
      This HTML file is a template.
      If you open it directly in the browser, you will see an empty page.

      You can add webfonts, meta tags, or analytics to this file.
      The build step will place the bundled scripts into the <body> tag.

      To begin the development, run `npm start` or `yarn start`.
      To create a production bundle, use `npm run build` or `yarn build`.
    -->
     <!-- Like below. This is the script tag for bootstrapping your Vite application -->
  <script type="module" src="/src/index.tsx"></script>
  </body>
</html>


7. Update Environment Variables

Vite uses a different naming convention and access method for environment variables compared to Create React App. To update your environment variables, follow these steps:

  • Rename your environment variables to start with VITE_. For example, replace REACT_APP_MY_VAR with VITE_MY_VAR.

.env file with CRA:

REACT_APP_BE_URL=https://react.dev/
REACT_APP_SECRET_KEY = "CRATOVITEMIGRATION"

.env file with Vite:

VITE_BE_URL=https://react.dev/
VITE_SECRET_KEY = "CRATOVITEMIGRATION"

  • Vite uses the ECMAScript module import.meta properties to pass environment variables to the modules. To access these environment variables, change all process.env. references to import.meta.env..

You can easily search and replace these occurrences in your codebase.

Here's an example of how to access an environment variable in Vite:

const myVar = import.meta.env.VITE_MY_VAR;

8. Add missing missing Node polyfills:

You might face issues with your application not rendering correctly, accompanied by warnings like Module "buffer" has been externalized for browser compatibility. This issue arises due to missing Node polyfills in your bundled web application, as the polyfills provided by our SDK are not compatible with Vite.

To resolve this, you can specify your own compatible polyfills in your Vite configuration.

This package offers a collection of polyfills for Node packages that are compatible with Vite.

To install using npm, run:

npm i --save-dev vite-plugin-node-polyfills

Alternatively, to install using yarn, run:

yarn add --dev vite-plugin-node-polyfills

9. Configuring Vite to use the plugin

Navigate to your Vite configuration file, typically located in the root of your project and named either vite.config.js or vite.config.ts. From here, add the line import { nodePolyfills } from 'vite-plugin-node-polyfills' to the top, and add nodePolyfills() to the plugins array inside defineConfig  as in the example below.

For a complete list of available polyfills, refer to the official documentation.

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import viteTsconfigPaths from 'vite-tsconfig-paths';
import { nodePolyfills } from 'vite-plugin-node-polyfills';

export default defineConfig({
  // depending on your application, base can also be "/"
  base: '',
  plugins: [
    react({
      include: /.(jsx|tsx)$/,
      babel: {
        plugins: ['styled-components'],
        babelrc: false,
        configFile: false,
      },
    }),
    viteTsconfigPaths(),
    nodePolyfills({
      include: ['buffer', 'fs', 'stream', 'util'],
    }),
  ],
  define: {
    'process.env': {},
    // By default, Vite doesn't include shims for NodeJS/
    // necessary for segment analytics lib to work
    global: {},
  },
  resolve: {
    alias: [
      {
        find: 'antd/lib',
        replacement: 'antd/es',
      },
      {
        find: 'crypto',
        replacement: 'crypto-js',
      },
    ],
  },
  server: {
    // this ensures that the browser opens upon server start
    open: true,
    // this sets a default port to 3000
    port: 3000,
  },
});


Note:If you are transitioning from CRA to Vite and relied on CRA for automatic routing, you will need to manually remap the routing when using Vite.

Conclusion

In summary, migrating from Create-React-App (CRA) to Vite offers numerous benefits, including faster development server start times, optimized production builds, and better TypeScript support. To migrate, you can follow the outlined steps, such as installing Vite, updating package.json scripts, creating a Vite configuration file, updating tsconfig.json, moving the index.html file, updating its context, updating environment variables, and adding missing Node polyfills. By doing so, we reduced the build time by 50%.

React Development; Vite; CRA-to-Vite;
Unlocking React App Performance: A Step-by-Step Guide to Migrating from CRA to Vite

In recent years, web development has seen a significant shift towards faster and more efficient tooling. Create-React-App (CRA) has been a popular choice for bootstrapping React applications, but it has some limitations, especially when it comes to the development server's speed and optimized production builds. This is where Vite, a modern front-end build tool, comes into play.

Why migrate from CRA to Vite?

Vite addresses some of the pain points of CRA by offering a faster development experience and improved production build optimization.

  1. Fast Cold Server Start: Vite utilizes native ES modules, which enables faster module loading during development. This results in a much quicker cold server start time compared to CRA.
  2. Optimized Builds: Vite utilizes Rollup for production builds, which provides better tree shaking and code optimization compared to CRA's Webpack configuration.
  3. Out-of-the-box CSS Code Splitting: Vite offers CSS code splitting without any additional configuration, which can lead to smaller bundle sizes and faster page loads.
  4. Better TypeScript Support: Vite has built-in support for TypeScript, which eliminates the need for additional plugins and configurations compared to CRA.
  5. Flexible Configuration: Vite offers a more flexible configuration system, allowing developers to easily customize their build setup without ejecting the project.

Project Details

Before we begin, here's some information about our project:

  • It is a React application created using CRA and using Webpack version 5.
  • We used Antd Library and Formik for form elements.
  • We used styled components to define CSS.

Migration Steps

To migrate from CRA to Vite, these are the steps we followed:

1. Install Vite:

Install Vite by running

npm install -D vite

2. Update package.json:

Change your package.json scripts to use Vite. Make sure to delete react-scripts from your dependencies section.

"scripts": {
 "start": "vite",
 "build": "tsc && vite build",
 "serve": "vite preview",
},


3. Create a Vite Configuration File: Create a vite.config.js file at the root of your project with the provided content. We have also added the configuration for styled components within the Babel plugins section.

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import viteTsconfigPaths from 'vite-tsconfig-paths';

export default defineConfig({
  // depending on your application, base can also be "/"
  base: '',
  plugins: [
    react({
      include: /.(jsx|tsx)$/,
      babel: {
        plugins: ['styled-components'],
        babelrc: false,
        configFile: false,
      },
    }),
    viteTsconfigPaths(),
  ],
  define: {
    'process.env': {},
    // By default, Vite doesn't include shims for NodeJS/
    // necessary for segment analytics lib to work
    global: {},
  },
  resolve: {
    alias: [
      {
        find: 'antd/lib',
        replacement: 'antd/es',
      },
      {
        find: 'crypto',
        replacement: 'crypto-js',
      },
    ],
  },
  server: {
    // this ensures that the browser opens upon server start
    open: true,
    // this sets a default port to 3000
    port: 3000,
  },
});


4. Update your tsconfig.json

Make sure to configure your tsconfig.json file with the following settings:

  • Set the target, lib, and module type to esnext. This configuration might need to be updated in future TypeScript versions as more esnext functionality becomes part of the ECMAScript standard. Always refer to the Vite documentation for potential updates if this article is outdated.
  • Add the Vite types to the types section. This inclusion informs TypeScript about the unique Vite browser functionalities that are available for your project.
  • Enable the isolatedModules option. This setting is crucial because some modern TypeScript features are not yet supported by Vite. By setting isolatedModules to true, you ensure better compatibility with Vite. If this option is not already enabled in your configuration, make sure to add it.


{
  "compilerOptions": {
    "target": "ESNext",
    "lib": ["dom", "dom.iterable", "esnext"],
    "types": ["vite/client"],
    "allowJs": false,
    "skipLibCheck": false,
    "esModuleInterop": false,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx"
  },
  "include": ["src"]
}

5. Move the index.html File

Vite has a root directory which your files are served from. Since index.html is the entry point for Vite's server, the file needs to be in the root directory.

From the public directory, move the index.html file to the root of your project.

6. Update the context of index.html

Vite handles URLs in the index.html differently to create react app.

index.html with CRA:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <!--
      manifest.json provides metadata used when your web app is installed on a
      user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
    -->
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <!--
      Notice the use of %PUBLIC_URL% in the tags above.
      It will be replaced with the URL of the `public` folder during the build.
      Only files inside the `public` folder can be referenced from the HTML.

      Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
      work correctly both with client-side routing and a non-root public URL.
      Learn how to configure a non-root public URL by running `npm run build`.
    -->
    <title>React App</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
    <!--
      This HTML file is a template.
      If you open it directly in the browser, you will see an empty page.

      You can add webfonts, meta tags, or analytics to this file.
      The build step will place the bundled scripts into the <body> tag.

      To begin the development, run `npm start` or `yarn start`.
      To create a production bundle, use `npm run build` or `yarn build`.
    -->
  </body>
</html>


Remove any %PUBLIC_URL% references from the file. Just replace that string with "". Add a script tag with the project entry point index.html with Vite:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="apple-touch-icon" href="/logo192.png" />
    <!--
      manifest.json provides metadata used when your web app is installed on a
      user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
    -->
    <link rel="manifest" href="/manifest.json" />
    <!--
      Notice the use of %PUBLIC_URL% in the tags above.
      It will be replaced with the URL of the `public` folder during the build.
      Only files inside the `public` folder can be referenced from the HTML.

      Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
      work correctly both with client-side routing and a non-root public URL.
      Learn how to configure a non-root public URL by running `npm run build`.
    -->
    <title>React App</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
    <!--
      This HTML file is a template.
      If you open it directly in the browser, you will see an empty page.

      You can add webfonts, meta tags, or analytics to this file.
      The build step will place the bundled scripts into the <body> tag.

      To begin the development, run `npm start` or `yarn start`.
      To create a production bundle, use `npm run build` or `yarn build`.
    -->
     <!-- Like below. This is the script tag for bootstrapping your Vite application -->
  <script type="module" src="/src/index.tsx"></script>
  </body>
</html>


7. Update Environment Variables

Vite uses a different naming convention and access method for environment variables compared to Create React App. To update your environment variables, follow these steps:

  • Rename your environment variables to start with VITE_. For example, replace REACT_APP_MY_VAR with VITE_MY_VAR.

.env file with CRA:

REACT_APP_BE_URL=https://react.dev/
REACT_APP_SECRET_KEY = "CRATOVITEMIGRATION"

.env file with Vite:

VITE_BE_URL=https://react.dev/
VITE_SECRET_KEY = "CRATOVITEMIGRATION"

  • Vite uses the ECMAScript module import.meta properties to pass environment variables to the modules. To access these environment variables, change all process.env. references to import.meta.env..

You can easily search and replace these occurrences in your codebase.

Here's an example of how to access an environment variable in Vite:

const myVar = import.meta.env.VITE_MY_VAR;

8. Add missing missing Node polyfills:

You might face issues with your application not rendering correctly, accompanied by warnings like Module "buffer" has been externalized for browser compatibility. This issue arises due to missing Node polyfills in your bundled web application, as the polyfills provided by our SDK are not compatible with Vite.

To resolve this, you can specify your own compatible polyfills in your Vite configuration.

This package offers a collection of polyfills for Node packages that are compatible with Vite.

To install using npm, run:

npm i --save-dev vite-plugin-node-polyfills

Alternatively, to install using yarn, run:

yarn add --dev vite-plugin-node-polyfills

9. Configuring Vite to use the plugin

Navigate to your Vite configuration file, typically located in the root of your project and named either vite.config.js or vite.config.ts. From here, add the line import { nodePolyfills } from 'vite-plugin-node-polyfills' to the top, and add nodePolyfills() to the plugins array inside defineConfig  as in the example below.

For a complete list of available polyfills, refer to the official documentation.

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import viteTsconfigPaths from 'vite-tsconfig-paths';
import { nodePolyfills } from 'vite-plugin-node-polyfills';

export default defineConfig({
  // depending on your application, base can also be "/"
  base: '',
  plugins: [
    react({
      include: /.(jsx|tsx)$/,
      babel: {
        plugins: ['styled-components'],
        babelrc: false,
        configFile: false,
      },
    }),
    viteTsconfigPaths(),
    nodePolyfills({
      include: ['buffer', 'fs', 'stream', 'util'],
    }),
  ],
  define: {
    'process.env': {},
    // By default, Vite doesn't include shims for NodeJS/
    // necessary for segment analytics lib to work
    global: {},
  },
  resolve: {
    alias: [
      {
        find: 'antd/lib',
        replacement: 'antd/es',
      },
      {
        find: 'crypto',
        replacement: 'crypto-js',
      },
    ],
  },
  server: {
    // this ensures that the browser opens upon server start
    open: true,
    // this sets a default port to 3000
    port: 3000,
  },
});


Note:If you are transitioning from CRA to Vite and relied on CRA for automatic routing, you will need to manually remap the routing when using Vite.

Conclusion

In summary, migrating from Create-React-App (CRA) to Vite offers numerous benefits, including faster development server start times, optimized production builds, and better TypeScript support. To migrate, you can follow the outlined steps, such as installing Vite, updating package.json scripts, creating a Vite configuration file, updating tsconfig.json, moving the index.html file, updating its context, updating environment variables, and adding missing Node polyfills. By doing so, we reduced the build time by 50%.

Subscribe To Our Newsletter

Do get in touch with us to understand more about how we can help your organization in building meaningful and in-demand products
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.
Blog

Unlocking React App Performance: A Step-by-Step Guide to Migrating from CRA to Vite

Written by:  

Nidhi Mittal

June 14, 2024

7 min read

Unlocking React App Performance: A Step-by-Step Guide to Migrating from CRA to Vite

In recent years, web development has seen a significant shift towards faster and more efficient tooling. Create-React-App (CRA) has been a popular choice for bootstrapping React applications, but it has some limitations, especially when it comes to the development server's speed and optimized production builds. This is where Vite, a modern front-end build tool, comes into play.

Why migrate from CRA to Vite?

Vite addresses some of the pain points of CRA by offering a faster development experience and improved production build optimization.

  1. Fast Cold Server Start: Vite utilizes native ES modules, which enables faster module loading during development. This results in a much quicker cold server start time compared to CRA.
  2. Optimized Builds: Vite utilizes Rollup for production builds, which provides better tree shaking and code optimization compared to CRA's Webpack configuration.
  3. Out-of-the-box CSS Code Splitting: Vite offers CSS code splitting without any additional configuration, which can lead to smaller bundle sizes and faster page loads.
  4. Better TypeScript Support: Vite has built-in support for TypeScript, which eliminates the need for additional plugins and configurations compared to CRA.
  5. Flexible Configuration: Vite offers a more flexible configuration system, allowing developers to easily customize their build setup without ejecting the project.

Project Details

Before we begin, here's some information about our project:

  • It is a React application created using CRA and using Webpack version 5.
  • We used Antd Library and Formik for form elements.
  • We used styled components to define CSS.

Migration Steps

To migrate from CRA to Vite, these are the steps we followed:

1. Install Vite:

Install Vite by running

npm install -D vite

2. Update package.json:

Change your package.json scripts to use Vite. Make sure to delete react-scripts from your dependencies section.

"scripts": {
 "start": "vite",
 "build": "tsc && vite build",
 "serve": "vite preview",
},


3. Create a Vite Configuration File: Create a vite.config.js file at the root of your project with the provided content. We have also added the configuration for styled components within the Babel plugins section.

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import viteTsconfigPaths from 'vite-tsconfig-paths';

export default defineConfig({
  // depending on your application, base can also be "/"
  base: '',
  plugins: [
    react({
      include: /.(jsx|tsx)$/,
      babel: {
        plugins: ['styled-components'],
        babelrc: false,
        configFile: false,
      },
    }),
    viteTsconfigPaths(),
  ],
  define: {
    'process.env': {},
    // By default, Vite doesn't include shims for NodeJS/
    // necessary for segment analytics lib to work
    global: {},
  },
  resolve: {
    alias: [
      {
        find: 'antd/lib',
        replacement: 'antd/es',
      },
      {
        find: 'crypto',
        replacement: 'crypto-js',
      },
    ],
  },
  server: {
    // this ensures that the browser opens upon server start
    open: true,
    // this sets a default port to 3000
    port: 3000,
  },
});


4. Update your tsconfig.json

Make sure to configure your tsconfig.json file with the following settings:

  • Set the target, lib, and module type to esnext. This configuration might need to be updated in future TypeScript versions as more esnext functionality becomes part of the ECMAScript standard. Always refer to the Vite documentation for potential updates if this article is outdated.
  • Add the Vite types to the types section. This inclusion informs TypeScript about the unique Vite browser functionalities that are available for your project.
  • Enable the isolatedModules option. This setting is crucial because some modern TypeScript features are not yet supported by Vite. By setting isolatedModules to true, you ensure better compatibility with Vite. If this option is not already enabled in your configuration, make sure to add it.


{
  "compilerOptions": {
    "target": "ESNext",
    "lib": ["dom", "dom.iterable", "esnext"],
    "types": ["vite/client"],
    "allowJs": false,
    "skipLibCheck": false,
    "esModuleInterop": false,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx"
  },
  "include": ["src"]
}

5. Move the index.html File

Vite has a root directory which your files are served from. Since index.html is the entry point for Vite's server, the file needs to be in the root directory.

From the public directory, move the index.html file to the root of your project.

6. Update the context of index.html

Vite handles URLs in the index.html differently to create react app.

index.html with CRA:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <!--
      manifest.json provides metadata used when your web app is installed on a
      user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
    -->
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <!--
      Notice the use of %PUBLIC_URL% in the tags above.
      It will be replaced with the URL of the `public` folder during the build.
      Only files inside the `public` folder can be referenced from the HTML.

      Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
      work correctly both with client-side routing and a non-root public URL.
      Learn how to configure a non-root public URL by running `npm run build`.
    -->
    <title>React App</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
    <!--
      This HTML file is a template.
      If you open it directly in the browser, you will see an empty page.

      You can add webfonts, meta tags, or analytics to this file.
      The build step will place the bundled scripts into the <body> tag.

      To begin the development, run `npm start` or `yarn start`.
      To create a production bundle, use `npm run build` or `yarn build`.
    -->
  </body>
</html>


Remove any %PUBLIC_URL% references from the file. Just replace that string with "". Add a script tag with the project entry point index.html with Vite:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="apple-touch-icon" href="/logo192.png" />
    <!--
      manifest.json provides metadata used when your web app is installed on a
      user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
    -->
    <link rel="manifest" href="/manifest.json" />
    <!--
      Notice the use of %PUBLIC_URL% in the tags above.
      It will be replaced with the URL of the `public` folder during the build.
      Only files inside the `public` folder can be referenced from the HTML.

      Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
      work correctly both with client-side routing and a non-root public URL.
      Learn how to configure a non-root public URL by running `npm run build`.
    -->
    <title>React App</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
    <!--
      This HTML file is a template.
      If you open it directly in the browser, you will see an empty page.

      You can add webfonts, meta tags, or analytics to this file.
      The build step will place the bundled scripts into the <body> tag.

      To begin the development, run `npm start` or `yarn start`.
      To create a production bundle, use `npm run build` or `yarn build`.
    -->
     <!-- Like below. This is the script tag for bootstrapping your Vite application -->
  <script type="module" src="/src/index.tsx"></script>
  </body>
</html>


7. Update Environment Variables

Vite uses a different naming convention and access method for environment variables compared to Create React App. To update your environment variables, follow these steps:

  • Rename your environment variables to start with VITE_. For example, replace REACT_APP_MY_VAR with VITE_MY_VAR.

.env file with CRA:

REACT_APP_BE_URL=https://react.dev/
REACT_APP_SECRET_KEY = "CRATOVITEMIGRATION"

.env file with Vite:

VITE_BE_URL=https://react.dev/
VITE_SECRET_KEY = "CRATOVITEMIGRATION"

  • Vite uses the ECMAScript module import.meta properties to pass environment variables to the modules. To access these environment variables, change all process.env. references to import.meta.env..

You can easily search and replace these occurrences in your codebase.

Here's an example of how to access an environment variable in Vite:

const myVar = import.meta.env.VITE_MY_VAR;

8. Add missing missing Node polyfills:

You might face issues with your application not rendering correctly, accompanied by warnings like Module "buffer" has been externalized for browser compatibility. This issue arises due to missing Node polyfills in your bundled web application, as the polyfills provided by our SDK are not compatible with Vite.

To resolve this, you can specify your own compatible polyfills in your Vite configuration.

This package offers a collection of polyfills for Node packages that are compatible with Vite.

To install using npm, run:

npm i --save-dev vite-plugin-node-polyfills

Alternatively, to install using yarn, run:

yarn add --dev vite-plugin-node-polyfills

9. Configuring Vite to use the plugin

Navigate to your Vite configuration file, typically located in the root of your project and named either vite.config.js or vite.config.ts. From here, add the line import { nodePolyfills } from 'vite-plugin-node-polyfills' to the top, and add nodePolyfills() to the plugins array inside defineConfig  as in the example below.

For a complete list of available polyfills, refer to the official documentation.

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import viteTsconfigPaths from 'vite-tsconfig-paths';
import { nodePolyfills } from 'vite-plugin-node-polyfills';

export default defineConfig({
  // depending on your application, base can also be "/"
  base: '',
  plugins: [
    react({
      include: /.(jsx|tsx)$/,
      babel: {
        plugins: ['styled-components'],
        babelrc: false,
        configFile: false,
      },
    }),
    viteTsconfigPaths(),
    nodePolyfills({
      include: ['buffer', 'fs', 'stream', 'util'],
    }),
  ],
  define: {
    'process.env': {},
    // By default, Vite doesn't include shims for NodeJS/
    // necessary for segment analytics lib to work
    global: {},
  },
  resolve: {
    alias: [
      {
        find: 'antd/lib',
        replacement: 'antd/es',
      },
      {
        find: 'crypto',
        replacement: 'crypto-js',
      },
    ],
  },
  server: {
    // this ensures that the browser opens upon server start
    open: true,
    // this sets a default port to 3000
    port: 3000,
  },
});


Note:If you are transitioning from CRA to Vite and relied on CRA for automatic routing, you will need to manually remap the routing when using Vite.

Conclusion

In summary, migrating from Create-React-App (CRA) to Vite offers numerous benefits, including faster development server start times, optimized production builds, and better TypeScript support. To migrate, you can follow the outlined steps, such as installing Vite, updating package.json scripts, creating a Vite configuration file, updating tsconfig.json, moving the index.html file, updating its context, updating environment variables, and adding missing Node polyfills. By doing so, we reduced the build time by 50%.

About Greyamp

Greyamp is a boutique Management Consulting firm that works with large enterprises to help them on their Digital Transformation journeys, going across the organisation, covering process, people, culture, and technology. Subscribe here to get our latest digital transformation insights.