Fragmented Thought

Migrating Create React App to Vite

Vite logo


Lance Gliser

Heads up! This content is more than six months old. Take some time to verify everything still works as expected.

Why Vite?

It's been nearly 2 years of hard pressed development. Let's just say the landscape has shifted. My experience with CRA was enough to get our products off the ground, and efforts have gone into product improvements where they belong. Time really hasn't existed for much else.

Where does Vite come into that? Vitriol and vehemence. Flat out.

After a second restructuring, and the loss of some respected and dear friends, it's clear the demands are going to increase. Improvements to the meta ecosystem will have to come from passionate motivations to be better at my craft, instead of potential velocity increase negotiations. It's freeing, to some degree to understand the bounds, accept truth, and take control.

Not the list you were expecting? Sure, I'll give you that too. This far behind though, you probably already know:

Vite is fast, really fast.

How fast? With our current largest code base it cuts the build times from >2 minutes 2 seconds to <34 seconds. I could perhaps ignore that tastiness. I have pipelines and on demand servers for that! The effect on hot reloading is the real benefit that can't be ignored. Previously we were getting 1-2 seconds at peak. At that duration, focus starts to fray. Getting distracted is the most dangerous part of knowledge work, so getting my instant feedback feels incredibly satisfying. Thank you Vite! 🎉

Expected changes

I was shocked how easily the migration went. Granted, I've yet to use for a week, but here's the high level:

  • Package changes
    • Configure Vite
  • Find and replace environment variables
  • Alter the index.html

Module changes

Want this to be easy? Here ha go:

npm rm react-scripts npm i --save-dev vite @vitejs/plugin-react vite-plugin-svgr vite-plugin-eslint eslint eslint-config-react-app

And change these scripts to their Vite versions:

{ "scripts": { "start": "vite --host --port {LocalPort}", "build": "vite build", "serve": "vite preview --host --port {LocalPort}" } }

☣️ Note: vite build does not enforce typings. You can use tsc --noEmit && in front if you want safety.

Configure Vite

Create vite.config.ts at the root of the project:

import { defineConfig } from "vite"; import reactRefresh from "@vitejs/plugin-react"; import eslint from "vite-plugin-eslint"; import svgrPlugin from "vite-plugin-svgr"; // export default defineConfig({ // This changes the out put dir from dist to build // comment this out if that isn't relevant for your project build: { outDir: "build", }, plugins: [ eslint(), // This will hook the HMR into your output as you're more use to. reactRefresh(), svgrPlugin({ svgrOptions: { icon: true, // ...svgr options ( }, }), ], });

Find and replace environmental variables

  • Find and replace all REACT_APP_ instances with VITE_
  • Find and replace all process.env. with import.meta.env.

☣️ Be sure to check your pipelines, Helm charts, AWS CDK contexts, etc!

Optional changes:

Create a types files for vite/env.d.ts that will provide Typescript support:

/// <reference types="vite/client" /> interface ImportMetaEnv { readonly VITE_GRAPHQL_URL: string; // more env variables... } interface ImportMeta { readonly env: ImportMetaEnv; }

A change in detecting environment mode

If you previously used process.env.NODE_ENV === "production" you'll want tweak it to: import.meta.env.PROD

Alter the index.html

Start by moving the public/index.html to the root of the project. Then replace all instances of %PUBLIC_URL% with "" (empty strings).

And that's it! I'll be sure to return with an update if anything turns out to be a surprise issue.

To those on their own path, you'll be missed:

  • 🐿 Jon Korte
  • 🍸 Liz Townsend
  • 🪨 Chris Swanda