This post goes over how to migrate from Create React App (CRA) to Vite since the former is deprecated.
- package.json
- Environment Variables
- index.html
- vite.config.mjs
- manifest.json
- Jest
- ESLint
- TypeScript
- Port
- CI
- Example
package.json
Uninstall react-scripts:
npm uninstall react-scripts
Install vite:
npm install --save-dev vite @vitejs/plugin-react-swc
Update npm “scripts”:
{
"scripts": {
- "build": "react-scripts build",
+ "build": "vite build",
- "eject": "react-scripts eject",
- "start": "react-scripts start",
+ "start": "vite --open",
- "test": "react-scripts test"
+ "test": "jest --watch"
}
}
Environment Variables
Replace process.env.REACT_APP
with import.meta.env.VITE_APP
:
git grep -l 'process.env.REACT_APP' | xargs sed -i '' -e 's/process.env.REACT_APP/import.meta.env.VITE_APP/g'
Then replace REACT_APP
with VITE_APP
in .env
:
git grep -l REACT_APP | xargs sed -i '' -e 's/REACT_APP/VITE_APP/g'
Replace process.env.NODE_ENV
checks with import.meta.env.DEV
. For example:
-if (process.env.NODE_ENV === 'development') {
+if (import.meta.env.DEV) {
If you’re using TypeScript, create a type declaration file:
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly DEV: boolean;
readonly VITE_APP_NAME: string;
readonly VITE_APP_VERSION: string;
}
interface ImportMeta {
readonly env: ImportMetaEnv;
}
It’s good practice to consolidate all your environment variables in src/config/index.js
so that you can mock them in your tests with src/config/__mocks__/index.js
by adding the mock file to src/setupTests.js
:
echo 'jest.mock('./config');' >> src/setupTests.js
This fixes the TypeScript error:
src/config/index.ts:01:20 - error TS1343: The 'import.meta' meta-property is only allowed when the '--module' option is 'es2020', 'es2022', 'esnext', 'system', 'node16', or 'nodenext'.
01 export const DEV = import.meta.env.DEV;
~~~~~~~~~~~
index.html
Move public/index.html
to the root:
mv public/index.html .
Remove %PUBLIC_URL%
since Vite serves static assets under the public directory:
sed -i '' -e 's/%PUBLIC_URL%//g' index.html
Add the script tag to src/index.js
before the closing body tag:
<script type="module" src="src/index.js"></script>
For example:
<div id="root"></div>
<script type="module" src="src/index.js"></script>
</body>
</html>
vite.config.mjs
Create vite.config.mjs
:
import react from '@vitejs/plugin-react-swc';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [react()],
});
If you want to keep the build directory consistent with CRA:
import react from '@vitejs/plugin-react-swc';
import { defineConfig } from 'vite';
export default defineConfig({
+ build: {
+ outDir: '../build',
+ },
plugins: [react()],
});
Otherwise, Vite will build to dist
.
Now run your app:
npm start
If you get the error in your browser console:
require is not defined
Then install vite-plugin-commonjs:
npm install --save-dev vite-plugin-commonjs
And update vite.config.mjs
:
import react from '@vitejs/plugin-react-swc';
import { defineConfig } from 'vite';
+import commonjs from 'vite-plugin-commonjs'
export default defineConfig({
build: {
outDir: '../build',
},
- plugins: [react()],
+ plugins: [react(), commonjs()],
});
manifest.json
If you see the error in your browser console:
Manifest: property 'start_url' ignored, URL is invalid.
Then replace manifest.json
“start_url” with your absolute or relative URL.
For example:
- "start_url": ".",
+ "start_url": "https://example.com",
If you see the error in your browser console:
Manifest: property 'src' ignored, URL is invalid.
Then replace manifest.json
“src” with your absolute or relative URL.
For example:
"icons": [
{
- "src": "favicon.ico",
+ "src": "https://example.com/favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
- "src": "/android-chrome-192x192.png",
+ "src": "https://example.com/android-chrome-192x192.png",
"type": "image/png",
"sizes": "192x192"
},
{
- "src": "/android-chrome-512x512.png",
+ "src": "https://example.com/android-chrome-512x512.png",
"type": "image/png",
"sizes": "512x512"
}
],
Jest
Install jest
dependencies:
npm install --save-dev jest jest-environment-jsdom
If you’re using TypeScript, install ts-jest
dependencies:
npm install --save-dev ts-jest ts-node
Move your Jest config from package.json
to jest.config.js
.
This is optional but create a test directory:
mkdir -p test
Move src/setupTests.js
to the test directory and fix the imports:
mv src/setupTests.js test/setupTests.js
Create test/__mocks__/fileMock.js
:
module.exports = 'test-file-stub';
Create test/__mocks__/styleMock.js
:
module.exports = {};
Create test/__mocks__/svgMock.js
:
module.exports = {
ReactComponent: () => 'IconMock',
};
Your jest.config.js
should look like the following:
/** @type {import('jest').Config} */
const config = {
collectCoverageFrom: ['<rootDir>/src/**/*.{js,jsx}'],
coverageThreshold: {
global: {
branches: 100,
functions: 100,
lines: 100,
statements: 100,
},
},
moduleNameMapper: {
'\\.(css|less|sass|scss)$': '<rootDir>/test/__mocks__/styleMock.js',
'\\.(jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
'<rootDir>/test/__mocks__/fileMock.js',
'\\.svg$': '<rootDir>/test/__mocks__/svgMock.js',
},
// preset: 'ts-jest',
setupFilesAfterEnv: ['<rootDir>/test/setupTests.js'],
testEnvironment: 'jsdom',
};
module.exports = config;
Fix any failing tests and update snapshots:
npx jest -u
If you’re getting the error:
ReferenceError: Request is not defined
This means you need to polyfill fetch.
ESLint
Install eslint
:
npm install --save-dev eslint
Remove react-app
from .eslintrc
:
{
- "extends": ["react-app", "react-app/jest"]
}
If you’re using TypeScript, install the dependencies:
npm install --save-dev @typescript-eslint/{eslint-plugin,parser}
Then update .eslintrc
:
{
"parser": "@typescript-eslint/parser",
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"]
}
Run ESLint and fix any errors:
npx eslint .
TypeScript
If you’re getting the error:
error TS2307: Cannot find module './file.png' or its corresponding type declarations.
Then create a type declaration file:
declare module '*.png' {
const src: string;
export default src;
}
Port
Replace localhost:3000
with localhost:5173
:
git grep -l 'localhost:3000' | xargs sed -i '' -e 's/localhost:3000/localhost:5173/g'
CI
If you’re running a Vite server in CI, then you’ll need to pass the --host
option:
npx vite --host