Skip to content

Latest commit

 

History

History
215 lines (193 loc) · 5.47 KB

File metadata and controls

215 lines (193 loc) · 5.47 KB

Migration Guide: React 19 + Create React App to Vite

This document outlines the steps required to migrate our application from React 17 with Create React App (CRA) to React 18 with Vite. All commands should be run from the client directory, and all file modifications should be made to files within the client directory.

React 19 Upgrade

1. Update React Dependencies

# Update React core packages
npm install --save "react@^19" "react-dom@^19" "@types/react@^19" "@types/react-dom@^19"

2. Update fortawesome

If your project uses fortawesome, upgrade the fortawesome packages to 6.7.2 or higher

   npm install --save "@fortawesome/fontawesome-svg-core@latest" "@fortawesome/free-brands-svg-icons@latest" "@fortawesome/free-regular-svg-icons@latest" "@fortawesome/free-solid-svg-icons@latest" "@fortawesome/react-fontawesome@latest"

3. Update Testing Libraries

# Update React Testing Library
npm install --save-dev @testing-library/react@latest

4. Update ReactDOM Import and Rendering Method

The main change in React 19 is the new root API. We updated our index.tsx to use the new API:

// Old React 17 way
import ReactDOM from 'react-dom';
// ...
ReactDOM.render(
  <React.StrictMode>
    <AppWrapper>
      <App />
    </AppWrapper>
  </React.StrictMode>,
  document.getElementById('root')
);
// New React 19 way
import ReactDOM from 'react-dom/client';
// ...
const rootElement = document.getElementById('root') as HTMLElement;
const root = ReactDOM.createRoot(rootElement);
root.render(
  <React.StrictMode>
    <AppWrapper>
      <App />
    </AppWrapper>
  </React.StrictMode>,
);

Create React App to Vite Migration

1. Uninstall Create React App

npm uninstall --save react-scripts

2. Update Node Types for Compatibility with Vite

npm install --save-dev @types/node@latest

3. Install Vite and Required Plugins

npm install --save-dev vite @vitejs/plugin-react vite-tsconfig-paths vite-plugin-node-polyfills

4. Ignore vite.config.mjs from ESLint

Add the following to your .eslintrc.js file:

  ignorePatterns: [
    'vite.config.*',
  ],

5. Create Vite Configuration File

Create vite.config.mjs in the client directory:

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { nodePolyfills } from 'vite-plugin-node-polyfills';
import { fileURLToPath } from 'url';
import { dirname, resolve } from 'path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
export default defineConfig({
  plugins: [
    react(),
    nodePolyfills({
      // Whether to polyfill `node:` protocol imports
      protocolImports: true,
    }),
  ],
  resolve: {
    alias: {
      'src': resolve(__dirname, 'src')
    },
  },
  server: {
    port: 3000,
    open: false,
    proxy: {
      '/api': {
        target: 'http://localhost:8080',
        changeOrigin: true,
      }
    }
  },
  build: {
    outDir: 'build',
  }
});

6. Create HTML Entry Point

Copy the existing index.html from the public folder to the client root directory and update it: Then update the copied file to:

  1. Replace any %PUBLIC_URL% references with /
  2. Add the script tag for the main entry point: Example:
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" href="/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="theme-color" content="#000000" />
    <meta name="description" content="Hello Harvard: a system for getting your course set up" />
    <link rel="apple-touch-icon" href="/logo192.png" />
    <link rel="manifest" href="/manifest.json" />
    <title>Hello Harvard</title>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/index.tsx"></script>
  </body>
</html>

7. Update Package.json Scripts

Replace CRA scripts with Vite commands:

"scripts": {
  "dev:client": "vite",
  "start": "vite",
  "build": "npm i --production=false && vite build",
  "build-dev": "vite build --mode development",
  "auto-build": "vite build --watch",
  "preview": "vite preview",
  "test": "vitest run"
}

8. Set Up Testing with Vitest

# Install Vitest and related packages
npm install --save-dev vitest jsdom

Create vitest.config.ts file:

import { defineConfig } from 'vitest/config';
import react from '@vitejs/plugin-react';
import tsconfigPaths from 'vite-tsconfig-paths';
export default defineConfig({
  plugins: [react(), tsconfigPaths()],
  test: {
    globals: true,
    environment: 'jsdom',
    setupFiles: './src/setupTests.ts',
  },
});

9. Update SCSS Files: Replace @import with @use

You should replace all @import statements with @use statements in your SCSS files. Also, variables from shared.scss must now be accessed as shared.$variable-name.

// Old way with @import
@import './shared.scss';

.my-component {
  color: $primary-color;
  margin: div(16px, 2);
}

// New way with @use
@use './shared.scss';

.my-component {
  color: shared.$primary-color;
  margin: math.div(16px, 2);
}

10. Update react-app-env.d.ts

Update the file to be this:

/// <reference types="react-scripts" />

declare module '*.svg' {
  const content: string;
  export default content;
}

/// <reference types="react-scripts" />

// Allow SVG images
declare module '*.svg' {
  const content: string;
  export default content;
}

// Allow SCSS imports
declare module '*.scss';