With Create React App (CRA) officially deprecated, it was time for me to step out of my comfort zone and migrate my React project to a modern alternative Vite. In this article, I’ll walk you through my exact steps, learnings, and optimizations while migrating from CRA + CRACO to Vite, including Cesium integration, JSX conversion, and asset handling.
Why Migrate to Vite?
CRA has served well for years, but:
Hot Module Replacement (HMR) in CRA is relatively slow (~1000ms) compared to Vite (~200ms).
Cold Start: CRA took ~15 seconds to start dev server; Vite does it in just ~2 seconds.
Modern Tooling: Vite uses esbuild under the hood — it's 10–100x faster than Webpack.
CRA is officially deprecated — see this article.
https://build5nines.com/create-react-app-is-now-deprecated-time-to-migrate-to-vite-or-next-js/
Initial Cleanup: Say Goodbye to CRA & CRACO
Start by removing all CRA/CRACO-related dependencies:
npm uninstall react-scripts @craco/craco craco-cesium
Update package.json scripts:
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"lint": "eslint src/**/*.{js,jsx,ts,tsx,json}",
"format": "prettier --write src/**/*.{js,jsx,ts,tsx,css,md,json,scss} --config ./.prettierrc"
}```
## Installing Vite & Required Plugins
Install core dependencies for React + Cesium support:
```jsx
npm install --save-dev vite @vitejs/plugin-react
npm install --save-dev vite-plugin-cesium
npm install cesium
Create vite.config.js
Here’s a basic configuration with Cesium support and API proxy:
import { defineConfig, loadEnv } from 'vite';
import react from '@vitejs/plugin-react';
import cesium from "vite-plugin-cesium";
export default defineConfig(({ command, mode }) => {
// Load env file based on `mode` in the current working directory
const env = loadEnv(mode, process.cwd(), '');
return {
plugins: [
react({
include: ['**/*.jsx', '**/*.js', '**/*.tsx', '**/*.ts'],
babel: {
plugins: [
['@babel/plugin-transform-react-jsx', { runtime: 'automatic' }]
]
}
}),
cesium(),
],
server: {
proxy: {
'/api': env.VITE_PORT_API_KEY,
'/tilesets': env.VITE_PORT_API_KEY
},
},
resolve: {
alias: {
'@': '/src',
},
},
optimizeDeps: {
exclude: ['react-virtualized'],
include: ['prop-types'],
},
build: {
assetsInlineLimit: 0,
commonjsOptions: {
include: [/react-virtualized/, /node_modules/],
},
chunkSizeWarningLimit: 1600,
},
};
});
Special Handling: Cesium Static Assets in Vite
Cesium relies on static assets (like Assets, Widgets, Workers) that need to be available at runtime.
Here’s how I handled it:
# Remove old public copy if exists
rm -rf public/cesium
# Copy Cesium assets from node_modules
cp -r node_modules/cesium/Build/Cesium public/cesium
Make sure your Vite config includes:
define: {
CESIUM_BASE_URL: JSON.stringify('/cesium'),
}
Now Cesium will load correctly from /cesium in production.
Project Structure & HTML Changes
Replace %PUBLIC_URL%
Vite doesn’t support %PUBLIC_URL%. Just use root-relative paths:
<!-- index.html -->
<link rel="icon" href="/favicon.ico" />
<script type="module" src="/src/index.jsx"></script>
Convert .js to .jsx
If you’re using JSX inside .js files, rename them to .jsx. Here's a script to automate it:
rename-jsx.sh
#!/bin/bash
echo "🔍 Scanning for JSX in .js files..."
find ./src -name "*.js" | while read file; do
if grep -qE "</?[A-Za-z].*?>" "$file"; then
newfile="${file%.js}.jsx"
mv "$file" "$newfile"
echo "✅Renamed: $file → $newfile"
fi
done
echo "🎉 Done! All JSX files renamed to .jsx"
Run it:
chmod +x rename-jsx.sh
./rename-jsx.sh
Handling Environment Variables
Vite uses the VITE_ prefix for env variables. Example:
VITE_FLAG_SMITH_API_KEY=abc123
Use it like this:
const key = import.meta.env.VITE_FLAG_SMITH_API_KEY;
Handling Static Assets
Move assets like images, logos, fonts to the /public folder.
Replace any require(...) statements with static import paths or import.
Old CRA way:
require('../../assets/logo.png')
Vite way:
src="/logo.png" // if inside public folder
Optional: To handle require in legacy code, you can use:
npm install vite-plugin-commonjs --save-dev
Cesium Integration Notes
Vite does not automatically handle Cesium static files like CRA + craco-cesium did.
Manually copy Cesium assets:
rm -rf public/cesium
cp -r node_modules/cesium/Build/Cesium public/cesium
Make sure CESIUM_BASE_URL is defined in vite.config.js as shown earlier.
Clean Up Dev Dependencies
Remove unused CRA-related packages:
npm uninstall html-webpack-plugin
Final Thoughts
Migrating from CRA to Vite brought massive speed improvements:
Cold Start: 15s ⏩ 2s
HMR: 1000ms ⏩ 200ms
Cleaner setup, no more heavy Webpack configs
Easier Cesium integration with vite-plugin-cesium
Whether you’re optimizing for speed or staying up-to-date with modern tooling, Vite is definitely the way forward.
Top comments (0)