DEV Community

zahidkhan-xen
zahidkhan-xen

Posted on • Edited on

From CRA to Lightning Fast Vite with Cesium: My Real-World Migration Experience

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
Enter fullscreen mode Exit fullscreen mode

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,
    },
  };
});
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Make sure your Vite config includes:

define: {
  CESIUM_BASE_URL: JSON.stringify('/cesium'),
}
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Use it like this:

const key = import.meta.env.VITE_FLAG_SMITH_API_KEY;
Enter fullscreen mode Exit fullscreen mode

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')
Enter fullscreen mode Exit fullscreen mode

Vite way:

src="/logo.png" // if inside public folder
Enter fullscreen mode Exit fullscreen mode

Optional: To handle require in legacy code, you can use:

npm install vite-plugin-commonjs --save-dev
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)