Migrating from Create-React-App to Vite: Simple Tutorial
How to Migrate from Create React App to Vite
I recommend installing a new project with the Vite CLI and copying your code there. This way, you get the latest version of Vite configs, including tsconfig, etc.
- What I am using in the project:
- Sass
- SVG files
- Environment variables with the prefix
REACT_APP
- Also uses environment variables in
index.html
- Also uses environment variables in
Step 1: Set Up a New Vite Project
- Install the Vite CLI:
npm install -g create-vite
- Create a Vite project:
create-vite my-react-app --template react-ts
- Install dependencies:
npm install
Step 2: Copy Your Existing CRA Project Files
Copy files:
Copy the
src
andpublic
directories from your CRA project to your new Vite project.Install additional dependencies:
Update your
package.json
dependencies from your CRA project in the new project:
npm install
- Update
typescript
to the latest version.
npm install typescript@latest
- Uninstall
react-scripts
:
npm uninstall react-scripts
Step 3: Configure Vite
In my case, I want to keep all environment variables with the prefix
REACT_APP
. I configured it as follows:
Configure
vite.config.ts
:In my case, I use the following additional configuration for:
- Sass
npm i vite-plugin-sass-dts
npm i sass
- SVG files
npm i vite-plugin-svgr
- Keep environment variables with prefix
REACT_APP
npm i vite-plugin-env-compatible
- Populate environment variables in
index.html
npm i vite-plugin-html
Modify
vite.config.ts
to handle environment variables, SVG files, and Sass imports.I created two files for
env
andplugins
:- To use these files, extend
tsconfig.node.json
:
- Sass
-"include": ["vite.config.ts"]
+"include": ["vite.config.ts", "vite.plugins.ts", "vite.env.ts"]
vite.env.ts
:
import dotenv from "dotenv";
import dotenvExpand from "dotenv-expand";
// Load .env files
const env = dotenv.config();
dotenvExpand.expand(env);
export const REACT_APP_PREFIX = "REACT_APP_";
export const VITE_PREFIX = "VITE_";
export const getEnvVariables = () => {
const envVariables = Object.keys(process.env).reduce(
(prev: Record<string, any>, key) => {
if (key.startsWith(REACT_APP_PREFIX) || key.startsWith(VITE_PREFIX)) {
prev[key] = process.env[key];
}
return prev;
},
{}
);
return envVariables;
};
export const envVariables = getEnvVariables();
export const VITE_PUBLIC_URL = envVariables.VITE_PUBLIC_URL;
vite.plugins.ts
:
import react from "@vitejs/plugin-react";
import svgr from "vite-plugin-svgr";
import { createHtmlPlugin } from "vite-plugin-html";
import viteSassDts from "vite-plugin-sass-dts";
import env from "vite-plugin-env-compatible";
import { envVariables, REACT_APP_PREFIX } from "./vite.env";
export const configurePlugins = () => {
return [
react(),
svgr({
svgrOptions: {
exportType: "named",
ref: true,
svgo: false,
titleProp: true,
},
include: "**/*.svg",
}),
viteSassDts(),
createHtmlPlugin({
inject: {
data: {
...envVariables,
},
},
}),
env({
prefix: REACT_APP_PREFIX,
}),
];
};
vite.config.ts
:
import { defineConfig } from "vite";
import { VITE_PUBLIC_URL } from "./vite.env";
import { configurePlugins } from "./vite.plugins";
import path from "path";
export default defineConfig({
base: VITE_PUBLIC_URL,
plugins: configurePlugins(),
resolve: {
alias: {
"@": path.resolve(__dirname, "./src"),
},
},
server: {
port: 3000,
},
build: {
outDir: "build",
emptyOutDir: true,
},
});
- Install Vite plugins:
npm install @vitejs/plugin-react dotenv dotenv-expand vite-plugin-svgr vite-plugin-html vite-plugin-sass-dts vite-plugin-env-compatible
Optional: Migrate to
VITE
instead ofREACT_APP
variables:File
.env
:
VITE_MY_VARIABLE=Test
File App.tsx
:
- process.env.VITE_MY_VARIABLE
+ import.meta.env.VITE_MY_VARIABLE
SVG Files
- In your code, you can use the same approach as in CRA:
import { ReactComponent as MyIcon } from "./images/MyIcon.svg";
index.html
- Index.html - now located in the
root
folder (previously in thepublic
folder)
<html lang="en">
<head>
<meta charset="utf-8" />
+<base href="<%= VITE_PUBLIC_URL %>" />
-<base href="%PUBLIC_URL%/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="App Name" />
<title>App Name</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
+<script type="module" src="/src/index.tsx"></script>
</body>
</html>
PUBLIC_URL
Variable
PUBLIC_URL
was originally used in the router, so it is necessary to change it:
-<BrowserRouter basename={process.env.PUBLIC_URL}>
+<BrowserRouter basename={import.meta.env.VITE_PUBLIC_URL}>
<App />
</BrowserRouter>
File .env.development
:
VITE_PUBLIC_URL=/
File .env.production
:
VITE_PUBLIC_URL=/my-app
Step 4: Update package.json
Scripts Section
"scripts": {
-"start": "react-scripts start",
+"start": "vite",
-"build": "react-scripts build",
+"build": "vite build",
-"eject": "react-scripts eject",
+"preview": "vite preview"
}
Step 5: Run It 🚀
npm run start
Feel free to share your feedback and suggestions for improvements!
Thanks for reading. 👋🏻
Subscribe to my newsletter
Read articles from Jan Škoruba directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Jan Škoruba
Jan Škoruba
I am a Software Developer and Identity Consultant, specializing in securing applications and APIs using OpenID Connect and OAuth.