# Migrating a Create-React-App monorepo to Vite

I got several years developing React.js applications using `creat-react-app` as everyone did and never worried too much about tooling until it started to feel like a burden.

My first touch with Vite was with a friend of mine building a Vue frontend, but it wasn't until a few months ago I was presented with a coworker repo with React.js and it caught up with me the fast bundling and easy-to-start as with CRA.

So, after testing with a quick migration of a previous smaller project, I thought it was time to take this big monorepo to the next level.

### Context

I had a two-years old monorepo built with CRA and managed with yarn workspaces. The repo structure was pretty simple, just a `/packages` directory, each one with a project (in this case, `/admin` and `/app` )and also a `/lib` directory which contains all shared components and utility files.

```bash
/
-- ./ github
-- / packages
---- / admin
------ / public
-------- index.html
------ / src
------ .env
------ config-overrides.js
------ package.json
---- / app
---- / lib
------ /components
------ /assets
------ /api
-- package.json
-- README.md
-- yarn.lock
```

Using `customize-cra` and `react-app-rewired` packages allowed me to customize the dev compiling process in my `config-overrides.js`.

### Initial setup

The first thing I did was to install Vite and related packages using yarn in my root directory:

```plaintext
yarn add -W vite @vitejs/plugin-react
```

Second, create a `vite.config.js` in each project's root directory:

```javascript
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig(() => {
  return {
    build: {
      outDir: 'build',
    },
    plugins: [react()],
  };
});
```

This code is implementing Vite's React Plugin to define a building setup. I decided to keep `build` as my directory for bundled assets as its already defined in my Github actions.

Next, I needed to modify my `index.html` to match [Vite requirements](https://vitejs.dev/guide/#index-html-and-project-root). I started by moving my `index.html` from `/public` of each one of my project's root and added a `script` tag with my JS entry point as my `src` attribute.

```xml
<html lang="en">
  <head>
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <title>Admin</title>
  </head>
  <body>
        <noscript>You need to enable JavaScript to run this app.</noscript>
        <div id="root">
            <div class="loader-container">
                <div class="loader">Loading...</div>
            </div>
        </div>
+       <script type="module" src="/src/index.jsx"></script>
  </body>
</html>
```

I am accustomed to JSX files, and also have a small utility to rename all file name extensions so it wasn't a problem for me to rename all files from .js to .jsx.

Then I replaced every instance of `react-app-rewired` with Vite custom commands on my npm scripts for every project in the `/projects` directory. For example:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692030093165/cb22ac11-d275-4bad-9c84-9103ab44d096.png align="center")

### Custom configurations

At the first server start, I saw on my console a strange error I have never seen before: `Uncaught SyntaxError: ambiguous indirect export: default`. This time I forgot I had a bunch of SVG assets inside the `lib` directory.

Solution was simple: for each vite's config file I added support for SVG files with `vite-plugin-svgr`:

```javascript
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
+ import svgr from 'vite-plugin-svgr';

export default defineConfig(() => {
  return {
    build: {
        outDir: 'build',
    },
    plugins: [
        react(),
+        svgr({ svgrOptions: { icon: true } }),
    ],
  };
});
```

Another important step during the migration was to replace all `process.env` in all sites of the project with `import.meta.env`, and as I was using environment variables on each project, also I had to replace `REACT_APP` with `VITE`. In the following example, my `configs.js` file inside the shared directory.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692292748115/21f927e1-540a-469b-8e66-7c54fee61c7b.png align="center")

Also, in order to point static files served by Vite in `/public` directory, I removed all occurrences of `%PUBLIC_URL%` in `index.html` file.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692289724418/11e9fb91-1919-4f86-aba3-0e4b1226e0b2.png align="center")

Finally, removed all previous packages used before.

```plaintext
yarn remove -W react-scripts customize-cra react-app-rewired
```

### Final thoughts

Migrating from `create-react-app` to Vite was a pretty straightforward process and there are plenty of guides out there, but with a monorepo I thought things were going to be different. Surprisingly it wasn't and the steps were as simple as in a normal repository. Here is the final structure of the repository. Note that there is no `config-overrides.js` as it is unnecessary now.

```bash
/
-- ./ github
-- / packages
---- / admin
------ / public
------ / src
------ .env
------ index.html
------ vite.config.js
------ package.json
---- / app
---- / lib
------ /components
------ /assets
------ /api
-- package.json
-- README.md
-- yarn.lock
```

---

If you found this post useful and would like to stay updated on my work, feel free to connect with me on any of my [social profiles](https://jodaz.dev/).

Share and comment your thoughts on it for more content like this. Thanks!
