Upgrade from Create React App to Vite
While most projects will rely on modern and feature-complete React frameworks like Next.js, you may have to work on a project that is still based on Create React App.
Create React App used (also knows as CRA) used to be the go-to tool to quickly create React projects, but it's now getting old and deprecated. And it's slow. Very slow. Vite is a modern tool that is way faster. By migrating a medium-size project from Create React App to Vite, I could cut the build time of a project from 15 minutes to less than 5 minutes on a CI server, and from 3 minutes to 30 seconds locally.
It is therefore really worth migrating a project based on CRA to Vite. This article will show you how to do it step by step. The migration should be a pretty straightforward process, but there are a few things to know to make it work.
Before you start
It may be a good idea to create a side default project with Vite to be able to look at its structure, and to be able to copy/paste some files from it.
npm create vite@latest
Choose following options :
- React
- JavaScript + SWC (I didn't choose TypeScript as the project I migrated was in JS)
Upgrade package.json file
Open the package.json
file of your project and copy all devDependencies from the Vite project you created in the previous step to your project's package.json
file.
In my case:
{
// ...
"devDependencies": {
"devDependencies": {
"@types/react": "^18.2.15",
"@types/react-dom": "^18.2.7",
"@vitejs/plugin-react-swc": "^3.3.2",
"eslint": "^8.45.0",
"eslint-plugin-react": "^7.32.2",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.3",
"vite": "^4.4.5"
}
}
Set your project type as module:
{
// ...
"type": "module"
}
Replace scripts section with Vite's one (keep your own custom scripts if you have some):
{
// ...
"scripts": {
"dev": "vite",
"build": "vite build",
"lint": "eslint src --ext js,jsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
}
}
Remove eslintConfig
and browserslist
entries from package.json
file.
Copy vite.config.js
file from the sample project you created earlier to your project's root directory.
Remove Create React App
Remove at least the react-scripts
package:
npm remove react-scripts
You can also clean up some other dependencies and files:
npm remove web-vitals
And delete the following files:
src/reportWebVitals.js
Remove this line from src/index.jsx
:
import reportWebVitals from "./reportWebVitals";
along with the call to the reportWebVitals()
function.
Update index.html file
- Move
index.html
file frompublic
directory to the root's directory of the project. - Inside that file, replace
%PUBLIC_URL%/
with/
inindex.html
file.
After the following line:
<div id="root"></div>
Add:
<script type="module" src="/src/index.jsx"></script>
Again, you can have a look at the index.html file from the sample project you created earlier to make sure you have the right content.
Update environment variables
Environment variables are now handled differently in Vite, and you will have to update your codebase to make it work.
Replace in your project's code (.js
and .jsx
, and .env
file itself):
process.env
->import.meta.env
REACT_APP_
->VITE_
(use case sensitive search)
SVG files
If you import some SVG files as components, you will have to update your code to make it work with Vite, as this is not supported by default. To check whether you have some SVG files imported as components, search for import { ReactComponent as
in your codebase. Full example :
import { ReactComponent as Logo } from './logo.svg'
Add the vite-plugin-svgr
plugin to your project:
npm i vite-plugin-svgr
Configure it in vite.config.js:
import svgr from 'vite-plugin-svgr'
//...
export default defineConfig({
plugins: [
react(),
svgr(),
// ...
],
})
Rename .js files that are using JSX to .jsx
You may have used the .js
extension including for files that are not purely Javascript, but that are using JSX. This was possible with Create React App, but is not supported by Vite. All files that contain some React components should have the .jsx
extension.
- Search for files with the
.js
extension that are using JSX (search forimport React
may be a good way to check it). - Copy all paths of the files matching the search. A good way to do it may be to use the VS Code's "Open in Editor" feature and then copy all paths from the editor.
- Rename all these files to
.jsx
using the rename command of your editor. This may be done by writing a small Bash script that you will execute in the terminal. Your script may look like a list ofmv
commands like this:
mv src/components/MyComponent.js src/components/MyComponent.jsx
mv src/components/MyOtherComponent.js src/components/MyOtherComponent.jsx
Alias updates
Aliases are an excellent way to make your imports shorter, more readable, and easier to maitain. If you have a lot of imports using relative paths like this:
import { Button } from '../../components/Button'
I really recommend you to use aliases to make them look like this:
import { Button } from '@components/Button'
You get two main benefits from this:
- No need to type tons of
../
to go up in the directory tree, and having to count them - Files can be easily moved around without having to update all the imports.
You may have used aliases in your project, and you will have to update them to make them work with Vite.
In Create React App, you may have used the jsconfig.json
file to define aliases. Example:
{
"compilerOptions": {
"baseUrl": "src"
},
"include": ["src"]
}
To make it work with Vite, you will have to update it like this:
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"src/*": ["src/*"]
}
}
}
And add to the vite.config.js
file:
resolve: {
alias: {
src: '/src',
},
},
Now, any file in the src
directory can be imported using the src
alias. Example:
import { Button } from 'src/components/Button'
Automatically open the browser when running the dev server
By default, Vite doesn't open the browser when running the dev server. To make it work, add the open
option to the vite.config.js
file:
//...
export default defineConfig(() => {
return {
server: {
open: true,
},
// ...
}
})
Note that by default, you will run the dev server with the npm run dev
command instead of npm start
.
Keep the build directory
By default, Vite builds the project in a dist
directory. If you want to keep the build
directory, you can add the build.outDir
option to the vite.config.js
file:
//...
export default defineConfig(() => {
return {
plugins: [
// ...
],
// ...
build: {
outDir: './build',
},
}
})
You should now be able to run the dev server with npm run dev
and build the project with npm run build
.
Add some ESLint rules
The default Vite configuration enables an ESLint rule to make sure fast refresh works properly and get a warning if some files need to be refactored. If you are using ESLint (which is highly recommended), you may want to add this rule to your project. To do so, add the following lines to your .eslintrc
file:
module.exports = {
// ...
rules: {
// ...
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
},
}
That's it! You should now have a working project with Vite. You can now enjoy the speed of the dev server and the build process!