# Migrating from Create-React-App to Vite: Simple Tutorial

# How to Migrate from Create React App to Vite

> I recommend installing a new project with the Vite CLI and copying your code there. This way, you get the latest version of Vite configs, including tsconfig, etc.

- What I am using in the project:
  - Sass
  - SVG files
  - Environment variables with the prefix `REACT_APP`
    - Also uses environment variables in `index.html`

## Step 1: Set Up a New Vite Project

1. Install the Vite CLI:

```bash
npm install -g create-vite
```

2. Create a Vite project:

```bash
create-vite my-react-app --template react-ts
```

3. Install dependencies:

```bash
npm install
```

## Step 2: Copy Your Existing CRA Project Files

1. Copy files:

   Copy the `src` and `public` directories from your CRA project to your new Vite project.

2. Install additional dependencies:

   Update your `package.json` dependencies from your CRA project in the new project:

```bash
npm install
```

3. Update `typescript` to the latest version.

```bash
npm install typescript@latest
```

4. Uninstall `react-scripts`:

```bash
npm uninstall react-scripts
```

## Step 3: Configure Vite

> In my case, I want to keep all environment variables with the prefix `REACT_APP`. I configured it as follows:

1. Configure `vite.config.ts`:

   In my case, I use the following additional configuration for:

   - Sass
     - `npm i vite-plugin-sass-dts`
     - `npm i sass`
   - SVG files
     - `npm i vite-plugin-svgr`
   - Keep environment variables with prefix `REACT_APP`
     - `npm i vite-plugin-env-compatible`
   - Populate environment variables in `index.html`
     - `npm i vite-plugin-html`

   Modify `vite.config.ts` to handle environment variables, SVG files, and Sass imports.

   I created two files for `env` and `plugins`:

   - To use these files, extend `tsconfig.node.json`:

```diff
-"include": ["vite.config.ts"]
+"include": ["vite.config.ts", "vite.plugins.ts", "vite.env.ts"]
```

`vite.env.ts`:

```ts
import dotenv from "dotenv";
import dotenvExpand from "dotenv-expand";

// Load .env files
const env = dotenv.config();
dotenvExpand.expand(env);

export const REACT_APP_PREFIX = "REACT_APP_";
export const VITE_PREFIX = "VITE_";

export const getEnvVariables = () => {
  const envVariables = Object.keys(process.env).reduce(
    (prev: Record<string, any>, key) => {
      if (key.startsWith(REACT_APP_PREFIX) || key.startsWith(VITE_PREFIX)) {
        prev[key] = process.env[key];
      }
      return prev;
    },
    {}
  );
  return envVariables;
};

export const envVariables = getEnvVariables();
export const VITE_PUBLIC_URL = envVariables.VITE_PUBLIC_URL;
```

`vite.plugins.ts`:

```ts
import react from "@vitejs/plugin-react";
import svgr from "vite-plugin-svgr";
import { createHtmlPlugin } from "vite-plugin-html";
import viteSassDts from "vite-plugin-sass-dts";
import env from "vite-plugin-env-compatible";
import { envVariables, REACT_APP_PREFIX } from "./vite.env";

export const configurePlugins = () => {
  return [
    react(),
    svgr({
      svgrOptions: {
        exportType: "named",
        ref: true,
        svgo: false,
        titleProp: true,
      },
      include: "**/*.svg",
    }),
    viteSassDts(),
    createHtmlPlugin({
      inject: {
        data: {
          ...envVariables,
        },
      },
    }),
    env({
      prefix: REACT_APP_PREFIX,
    }),
  ];
};
```

`vite.config.ts`:

```ts
import { defineConfig } from "vite";
import { VITE_PUBLIC_URL } from "./vite.env";
import { configurePlugins } from "./vite.plugins";
import path from "path";

export default defineConfig({
  base: VITE_PUBLIC_URL,
  plugins: configurePlugins(),
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "./src"),
    },
  },
  server: {
    port: 3000,
  },
  build: {
    outDir: "build",
    emptyOutDir: true,
  },
});
```

2. Install Vite plugins:

```bash
npm install @vitejs/plugin-react dotenv dotenv-expand vite-plugin-svgr vite-plugin-html vite-plugin-sass-dts vite-plugin-env-compatible
```

3. Optional: Migrate to `VITE` instead of `REACT_APP` variables:

   File `.env`:

```yaml
VITE_MY_VARIABLE=Test
```

File `App.tsx`:

```diff
- process.env.VITE_MY_VARIABLE
+ import.meta.env.VITE_MY_VARIABLE
```

### SVG Files

- In your code, you can use the same approach as in CRA:

```ts
import { ReactComponent as MyIcon } from "./images/MyIcon.svg";
```

### `index.html`

- Index.html - now located in the `root` folder (previously in the `public` folder)

```diff
<html lang="en">
<head>
<meta charset="utf-8" />

+<base href="<%= VITE_PUBLIC_URL %>" />
-<base href="%PUBLIC_URL%/" />

<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="App Name" />

<title>App Name</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
+<script type="module" src="/src/index.tsx"></script>
</body>
</html>
```

### `PUBLIC_URL` Variable

* `PUBLIC_URL` was originally used in the router, so it is necessary to change it:

```diff
-<BrowserRouter basename={process.env.PUBLIC_URL}>
+<BrowserRouter basename={import.meta.env.VITE_PUBLIC_URL}>
 <App />
 </BrowserRouter>
```

File `.env.development`:

```yaml
VITE_PUBLIC_URL=/
```

File `.env.production`:

```yaml
VITE_PUBLIC_URL=/my-app
```

## Step 4: Update `package.json` Scripts Section

```diff
"scripts": {
-"start": "react-scripts start",
+"start": "vite",
-"build": "react-scripts build",
+"build": "vite build",
-"eject": "react-scripts eject",
+"preview": "vite preview"
}
```

## Step 5: Run It 🚀

```bash
npm run start
```

Feel free to share your feedback and suggestions for improvements!

Thanks for reading. 👋🏻

