Skip to main content

CRA to Vite.js migration guide

Dictionary#

NameDescription
CTACreate React App is React's default scaffolding tool to create new React projects. Click here for more information. Initially, it was the default starting point for new Eva Suite modules.
Vite.jsIt's a new popular framework. Vite is 10-20 times faster that CRA because it uses esbuild instead of webpack under the hood. Click here for more information.
RollupRollup is a module bundler for JavaScript which compiles small pieces of code into something larger and more complex, such as a library or application. It uses the new standardized format for code modules included in the ES6 revision of JavaScript, instead of previous idiosyncratic solutions such as CommonJS and AMD. Click here for more information.

Mandatory steps#

These are all the steps one must take to migrate from CRA to Vite.js

  • Start with installing vite, vite-preset-react and vite-plugin-svgr
npm install vite vite-preset-react vite-plugin-svgr --save-dev
  • Continue by replacing react-scripts with vite in package.json
   "dependencies": {-    "react-scripts": "^4.0.3"   },+  "devDependencies": {+    "vite-preset-react": "^1.4.2",+    "vite": "^2.5.8"+  }
  • Change the scripts section in package.json
  "scripts": {-   "start": "react-scripts start",-   "build": "react-scripts build",-   "test": "react-scripts test",-   "eject": "react-scripts eject",+   "start": "vite",+   "build": "tsc && vite build",+   "serve": "vite preview",+   "test": "vite test",  },
  • Remove react-app-env.d.ts file if you have it in your project
  • Remove the node_modules folder
  • Vite requires Node.js version >=12.0.0. If you're not using this version you need to upgrade first.
  • Run npm install
  • Add the vite.config.ts file to the root of your project. We add some adjustments to make absolute paths working together with Rollup. Other solution would be to rewrite all the imports as relative imports. You need vite-plugin-svgr if you've used svg imports in your app. Instead of @vitejs/plugin-react-refresh we use the wrapper project vite-preset-react because there we can constrol the default import of React with.
/* eslint-disable import/no-extraneous-dependencies */import { defineConfig } from 'vite';import svgr from 'vite-plugin-svgr';import path from 'path';import presetReact from 'vite-preset-react';import { readdirSync } from 'fs';
const absolutePathAliases: { [key: string]: string } = {};
const srcPath = path.resolve('./src');// Don't forget to adjust the regex here so it can include .vue, .js, .jsx, etc... files from the src/ folder.// In my case, I'm writing React + TypeScript so the regex find files with .ts?(x) extensions only.//const srcRootContent = readdirSync(srcPath, { withFileTypes: true }).map((dirent) =>  dirent.name.replace(/(\.ts){1}(x?)/, ''),);
srcRootContent.forEach((directory) => {  absolutePathAliases[directory] = path.join(srcPath, directory);});
// https://vitejs.dev/config///export default defineConfig({  // This changes the out put dir from dist to build  // comment this out if that isn't relevant for your project  //  base: '/myawesomemodule',  build: {    outDir: 'build',  },  resolve: {    alias: { ...absolutePathAliases },  },  plugins: [presetReact(), svgr()],});
  • I'll advice you to add an .eslintignore file that contains the Vite.js config file (vite.config.ts) because your editor will throw unwanted eslint errors in that file otherwise.
  • Update your tsconfig.json You must set the tsconfig.json. to use esnext as a target, lib and module type. This might change in future versions of TypeScript as more esnext functionality is added to the ES standard for a given year so check the Vite site for updated config. Add the Vite.js types to the types section. This tells TypeScript about the special Vite.js browser functionality that it provides for us. Finally don’t forget to set isolatedModules to true if you don’t have that already. There is some modern Typescript functionally that is not supported by Vite.js yet. If you don't want to get into a world of TypeScript hurt, you should also set skipLibCheck to true.
{  "compilerOptions": {    "target": "ESNext",    "lib": ["dom", "dom.iterable", "esnext"],    "types": ["vite/client", "vite-plugin-svgr/client"],    "allowJs": false,    "skipLibCheck": true,    "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"]}
  • Change your .env variables to the 'Vite way' of dealing with variables.
# Define custom env variable (.env file)-  REACT_APP_NAME=My App+  VITE_NAME=My App# Access custom env variable (e.g. React component)-  process.env.REACT_APP_NAME+  import.meta.env.VITE_NAME
  • Move public/index.html to index.html (project root folder).
  • Remove %PUBLIC_URL% from index.html:
-  <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />+  <link rel="icon" href="/favicon.ico" />-  <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />+  <link rel="apple-touch-icon" href="/logo192.png" />-  <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />+  <link rel="manifest" href="/manifest.json" />
  • PUBLIC_URL can be remove from Netlify toml file (netlify.toml) Instead we will set the base property in the Vite configuration (vite.config.ts) like so
export default defineConfig({  base: '/myawesomemodule',  ...});
  • Add entry point in index.html:
   <noscript>You need to enable JavaScript to run this app.</noscript>   <div id="root"></div>+  <script type="module" src="/src/index.tsx"></script>
  • Fix TypeScript errors. You're probably going to get new and exciting TypeScript errors when you run npm run build. So the next step is to fix all these errors before you proceed.
  • If you encounter this error:
[vite:css] Preprocessor dependency "sass" not found. Did you install it?

just install sass globally e.g. npm install sass -g

  • If you have SCSS imports error from Style Sheets from node modules using the tilde ~ like for example @import '~@springtree/eva-suite-ui/dist/css/index.css'; just remove the tilde ~.

  • Please note that some node modules are not ready to work together will Rollup.js. Take for example this issue with file-saver

  • So Rollup.js doesn't play nice with default React import in tsx files. You either choose not to import React anywhere in your tsx files, or you choose to import it everywhere by default. If you choose the latter one, you need to specify in Rollup plugin plugin-react-refresh plugin:

    plugin: [  reactRefresh({     // injectReact: false,   }),]