I had an existing app that was scaffolded using create react app (CRA) and extended with craco. CRA didn't support the tooling I needed so I had to look for an alternative. I found Vite.
There are some incredible improvements in Vite over CRA, including PostCSS 8.0 support so I decided to migrate my production application.
I'll explain some of the benefits of Vite and describe the steps you need to take to upgrade your application.
Why Vite over create react app?
Vite has all of the features in CRA but with better implementations and it has additional features CRA doesn't support.
These are three main benefits of Vite for my application.
Speed
Vite is 10-20 times faster that CRA because it uses esbuild instead of webpack under the hood. It's hard to describe how much faster it feels but all changes are essentially instantaneous in your browser.
One thing to note is that Vite doesn't type check your code. It only transpiles TypeScript to JavaScript. So you might find some static bugs when building later in your development pipeline. Your IDE should help with this though.
Native ECMAScript module support
Vite supports ES modules natively. It allows you to develop for the browser with bare imports like TypeScript and it converts them in to proper versioned imports on build
// you write your code with bare import
import myModule from "./folder/myModule"
// vite converts to usable import
import myModule from "./folder/myModule.js?v=abc123"
CSS Plugin support
Vite supports modern tooling like PostCSS 8.0 much earlier than create react app. At the time of writing this post CRA had no support for PostCSS 8.0. Vite is under more active development. If you want to use tailwind CSS without awkward webpack shims you should use Vite.
You can see the full list of features here
Browser support for Vite builds in 2021
Vite's default target requires Native ES6 modules. Being able to use native es6 modules reduces your bundle size because it's easier to remove unused code.
Browser support for native ES6 modules is available on most desktop browsers since 2019. Same for mobile although support is more fragmented. You can review the support here on caniuse.
If you need to target older browsers you can use the official plugin from @vitejs/plugin-legacy. This will load the required polyfills to support older targets.
Planning to upgrade to Vite
Vite is almost a drop in replacement for CRA if you already use TypeScript. You will need to make some changes to your code but you should be able to just find and replace for most of those.
These are the steps we will follow to migrate.
- Update your package.json
- Add a Vite config
- Update your tsconfig.json file
- Install all the packages
- Move your index.html file
- Update the index.html contents
- Update all your env vars
Let's go!
1. Update your package.json
Change your package.json scripts to use Vite. Don’t worry about not having it yet, we will install it later.
"scripts": {
"start": "vite",
"build": "tsc && vite build",
"serve": "vite preview",
},
Make sure you delete react-scripts
from your dependencies section.
Add some new devDependencies for Vite.
"@vitejs/plugin-react-refresh": "^1.3.1",
"vite-plugin-svgr" :"^0.3.0",
"vite": "^2.3.2"
or if you want to install these directly
yarn add vite @vitejs/plugin-react-refresh vite-plugin-svgr
//or
// npm i vite @vitejs/plugin-react-refresh vite-plugin-svgr
and you can add PostCSS 8+ to your dependencies now if you need it!
2.Add a Vite config
Add vite.config.ts
to the root of your project. I just use this basic configuration to start with.
import { defineConfig } from 'vite'
import reactRefresh from '@vitejs/plugin-react-refresh'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [reactRefresh(), svgr()],
})
3. Update your tsconfig.json
You must set the tsconfig.json to use esnext as a target,lib and module type. This might change in future versions of TypeScripts as more esnext functionality is added to the es standard for a given year so check the Vite site for updated config if this article is old.
Add the vite types to the types section. This tells TypeScript about the special Vite browser functionality that it provides for us.
Finally don't forget to set isolatedModules to true if you don't have that already. There is some modern Typescript functionally that is not supported by Vite yet.
{
"compilerOptions": {
"target": "ESNext",
"lib": ["dom", "dom.iterable", "esnext"],
"types": ["vite/client","vite-plugin-svgr/client"],
"allowJs": false,
"skipLibCheck": false,
"esModuleInterop": false,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx"
},
"include": ["src"]
}
4. Install to update everything
Run yarn
or npm i
to install all the new dependencies we have added to the project.
5. Move your index.html file
Move the index.html from /public
out to the root of the project.
Vite doesn't need the index.html to be in the public folder any more.
6. Update the content of index.html
Vite handles urls in the index.html differently to create react app.
Remove any %PUBLIC_URL%
references from the file. Just replace that string with ""
.
<!-- This is the create react app url. change this to not have the variable... -->
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<!-- ... to be like this. This is the correct url for Vite -->
<link rel="icon" href="/favicon.ico" />
Add a script tag with the project entrypoint
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!-- Like below. This is the script tag for bootstrapping your Vite application -->
<script type="module" src="/src/index.tsx"></script>
</body>
7. Update all your env vars if you use them
Rename your environment variables so they start with VITE_
e.g. search and replace REACT_APP_
toVITE_
# this create react app variable
REACT_APP_MY_VAR
# should be this in Vite
VITE_MY_VAR
Vite uses the ECMAScript module import.meta properties to pass environment variables to the modules.
To access these environment variables you must change all process.env.
s to import.meta.env.
.
You should be able to search and replace this.
Additional notes for large existing projects
Vite recommends using css modules for your application. I use tailwind CSS in my app but if you use sass or css you might need to install the sass preprocessor.
yarn add -D sass
//or
// npm i --save-dev sass
If you must have react or vue environment variables available in process.env for your Vite application then you can use the plugin vite-plugin-env-compatible.
The plugin will load VUE_APP_
or REACT_APP_
environment variables to process.env. You might need this if you are using a library that expects an env var to be on process.env for example.
yarn add vite-plugin-env-compatible
//or
// npm i vite-plugin-env-compatible
and add
envCompatible(/* options */)
to your vite.config.ts plugins section.
❤️ Thanks to Asher Cohen for these tips. There's even more detail on his comment here.
Done!
That’s it. Now try running your app with yarn start
or npm run start
Let me know if anything didn’t work for you!
Top comments (6)
Hi Darragh! How did you configure the CSS source mapping during your migration from CRA to Vite?
hey! I use tailwind so the css/classes are all in the component's
className
attribute. Haven't needed a source map to trace them back to a separate file.I see. Do you know how to configure CSS source mapping? I can't find the configuration method in the documentation
not 100% sure. are you using SASS, PostCSS or some other CSS processor? At first thought i would guess it's not a vite concern and should be configured in the preprocessor.
It looks like you can hook vite build into a preprocessor with something like
if you use postcss, vite automatically searches for the postcss.config.js or wherever you have your postcss config.
you can turn them on with
map: { inline: true },
I tried to configure the map of postCSS, but it didn't work. I wonder if there is something wrong with my configuration