gen-ai-writen via Cursor IDE agent mode auto (likely claude 3.7)

related: Debugging CRA to Vite Migrations - A Systematic Approach

1. SVG Import Pattern Changes

Original CRA Pattern

// This worked in CRA
import StarIcon from "../icons/star.svg?react";
import HeartIcon from "../icons/heart.svg?react";

Vite Pattern

// Required for Vite
import { ReactComponent as StarIcon } from "../icons/star.svg";
import { ReactComponent as HeartIcon } from "../icons/heart.svg";

Why It Broke

  • CRA used a custom webpack loader (?react query parameter)
  • Vite uses a different SVG handling strategy
  • The ?react syntax is CRA-specific and not supported in Vite

2. Function Initialization Order

Original Pattern (Worked in CRA)

// This worked in CRA despite being out of order
const sortByPrice = (carA, carB) => {
  // Uses calculateDiscount and getFinalPrice before they're defined
  const discountA = calculateDiscount(carA);
  const finalPriceA = getFinalPrice(carA, discountA);
  // ...
};
 
const calculateDiscount = (car) => 
  car.features.some((feature) => specialOffers.includes(feature.name));
 
const getFinalPrice = (car, discount) =>
  car.basePrice - (car.basePrice * discount);

Fixed Pattern (Required for Vite)

// Functions must be defined before use
const calculateDiscount = (car) => 
  car.features.some((feature) => specialOffers.includes(feature.name));
 
const getFinalPrice = (car, discount) =>
  car.basePrice - (car.basePrice * discount);
 
const sortByPrice = (carA, carB) => {
  // Now calculateDiscount and getFinalPrice are defined
  const discountA = calculateDiscount(carA);
  const finalPriceA = getFinalPrice(carA, discountA);
  // ...
};

Why It Broke

  • CRA’s webpack might have reordered the code
  • Vite preserves the exact order of the code
  • Function expressions (const fn = () {}) are not hoisted
  • Only function declarations (function fn() {}) are hoisted

3. Error Boundary Initialization

Original Pattern

// This worked in CRA even if ErrorTracker wasn't initialized
<ErrorBoundary>
  <CarListing />
</ErrorBoundary>

Fixed Pattern

// Need to check if error reporting is available
if (ErrorTracker?.logError) {
  ErrorTracker.logError(error, {
    context: {
      component: "CarListing",
      carId: car.id,
    },
  });
}

Why It Broke

  • CRA’s development server was more forgiving of undefined objects
  • Vite’s development server is closer to production behavior
  • Error boundaries need proper initialization checks

4. Environment Variables

Original CRA Pattern

// This worked in CRA
process.env.REACT_APP_API_URL

Vite Pattern

// Required for Vite
import.meta.env.VITE_API_URL

Why It Broke

  • CRA used process.env
  • Vite uses import.meta.env
  • Prefix requirement changed from REACT_APP_ to VITE_

5. Global Variables

Original Pattern

// This worked in CRA
let specialOffers = []; // Global variable
 
const CarListing = () => {
  specialOffers = currentPromotions; // Mutating global
  // ...
}

Better Pattern

// Use state or context instead
const CarListing = () => {
  const [specialOffers, setSpecialOffers] = useState([]);
  
  useEffect(() => {
    setSpecialOffers(currentPromotions);
  }, [currentPromotions]);
  // ...
}

Why It Broke

  • CRA was more forgiving of global state
  • Vite’s module system makes global variables more problematic
  • React’s functional components prefer local state

Key Takeaways

  1. SVG Imports

    • Remove ?react suffix
    • Use ReactComponent import syntax
    • Update usage in components
  2. Function Order

    • Define functions before use
    • Use function declarations for hoisting when needed
    • Be explicit about dependencies
  3. Error Handling

    • Add null checks for error reporting
    • Initialize error boundaries properly
    • Handle undefined states
  4. Environment Variables

    • Update prefix from REACT_APP_ to VITE_
    • Use import.meta.env instead of process.env
    • Update build configuration
  5. State Management

    • Avoid global variables
    • Use React’s state management
    • Be explicit about dependencies