React Vite
Introduction
When starting a new React project, one of the first choices you need to make is which build tool to use. Traditionally, Create React App (CRA) has been the go-to solution, but Vite has emerged as a powerful alternative that offers significant performance improvements. In this guide, we'll explore what Vite is, why it's becoming popular in the React ecosystem, and how to set up and use it effectively for your React projects.
Vite (French for "quick", pronounced /vit/
) is a modern build tool created by Evan You, the creator of Vue.js. Despite its origins in the Vue ecosystem, Vite works excellently with React and other frameworks, providing a lightning-fast development experience through innovative techniques like native ES modules and hot module replacement (HMR).
What Makes Vite Special?
Vite offers several advantages over traditional bundlers like webpack (which powers Create React App):
-
Extremely Fast Development Server: Vite leverages native ES modules in the browser to serve code instantly, without bundling during development.
-
Instant Hot Module Replacement (HMR): Changes to your code are reflected almost immediately in the browser.
-
Optimized Production Builds: For production, Vite uses Rollup, which creates highly optimized bundles.
-
Out-of-the-box TypeScript Support: No need for additional configuration to use TypeScript.
-
Rich Feature Set: Includes CSS preprocessing, asset handling, and more without complex configuration.
Let's see how Vite compares to traditional bundlers in this diagram:
Getting Started with React Vite
Creating a New React Project with Vite
To create a new React project using Vite, you'll need Node.js version 14.18+ or 16+. Then, run one of the following commands:
# Using npm
npm create vite@latest my-react-app -- --template react
# Using yarn
yarn create vite my-react-app --template react
# Using pnpm
pnpm create vite my-react-app --template react
This will create a new React project with the following structure:
my-react-app/
├── node_modules/
├── public/
│ └── vite.svg
├── src/
│ ├── assets/
│ │ └── react.svg
│ ├── App.css
│ ├── App.jsx
│ ├── index.css
│ └── main.jsx
├── .eslintrc.cjs
├── .gitignore
├── index.html
├── package.json
├── vite.config.js
└── README.md
Running Your React Vite Project
Navigate to your project directory and run the following commands:
cd my-react-app
# Install dependencies
npm install
# Start the development server
npm run dev
You'll see something like:
VITE v4.4.0 ready in 237 ms
➜ Local: http://localhost:5173/
➜ Network: use --host to expose
➜ press h to show help
Open your browser and go to http://localhost:5173 to see your React application.
Understanding the Basic React Vite Setup
Let's examine the key files in a React Vite project:
1. index.html
Unlike CRA, in Vite the index.html
file is at the project root:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>
The script tag with type="module"
is important - it allows Vite to use native ES modules.
2. main.jsx
This is the entry point of your application:
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
import './index.css'
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<App />
</React.StrictMode>,
)
3. App.jsx
The main component of your application:
import { useState } from 'react'
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import './App.css'
function App() {
const [count, setCount] = useState(0)
return (
<>
<div>
<a href="https://vitejs.dev" target="_blank" rel="noreferrer">
<img src={viteLogo} className="logo" alt="Vite logo" />
</a>
<a href="https://react.dev" target="_blank" rel="noreferrer">
<img src={reactLogo} className="logo react" alt="React logo" />
</a>
</div>
<h1>Vite + React</h1>
<div className="card">
<button onClick={() => setCount((count) => count + 1)}>
count is {count}
</button>
<p>
Edit <code>src/App.jsx</code> and save to test HMR
</p>
</div>
<p className="read-the-docs">
Click on the Vite and React logos to learn more
</p>
</>
)
}
export default App
4. vite.config.js
This is where you configure Vite:
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
})
Customizing Your Vite Configuration
Vite is highly configurable. Here are some common configurations you might want to use:
Setting a Base Path
If your application is deployed to a subdirectory, you can set the base path:
// vite.config.js
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
base: '/my-app/'
})
Adding Aliases for Import Paths
To simplify import paths, you can add aliases:
// vite.config.js
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import path from 'path'
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
'@components': path.resolve(__dirname, './src/components')
}
}
})
Now you can use these aliases in your imports:
// Before
import Button from '../../components/Button'
// After
import Button from '@components/Button'
Adding Environment Variables
Vite has built-in support for environment variables. Create a .env
file in your project root:
VITE_API_URL=https://api.example.com
To use this variable in your code:
// access with import.meta.env
console.log(import.meta.env.VITE_API_URL) // https://api.example.com
Note: Only variables prefixed with VITE_
are exposed to your client-side code.
Practical Example: Building a Todo App with React and Vite
Let's build a simple todo application to demonstrate Vite in action. We'll create a todo list with the ability to add, toggle, and delete todos.
Step 1: Create the Project
npm create vite@latest todo-app -- --template react
cd todo-app
npm install
Step 2: Create Todo Components
Let's create a components
folder inside src
:
mkdir -p src/components
First, create a TodoItem component:
// src/components/TodoItem.jsx
import { useState } from 'react';
function TodoItem({ todo, onToggle, onDelete }) {
return (
<div style={{
display: 'flex',
alignItems: 'center',
marginBottom: '10px',
textDecoration: todo.completed ? 'line-through' : 'none'
}}>
<input
type="checkbox"
checked={todo.completed}
onChange={() => onToggle(todo.id)}
/>
<span style={{ marginLeft: '10px', flexGrow: 1 }}>{todo.text}</span>
<button
onClick={() => onDelete(todo.id)}
style={{ background: '#ff4d4d', color: 'white', border: 'none', padding: '5px 10px' }}
>
Delete
</button>
</div>
);
}
export default TodoItem;
Next, create a TodoList component:
// src/components/TodoList.jsx
import { useState } from 'react';
import TodoItem from './TodoItem';
function TodoList() {
const [todos, setTodos] = useState([]);
const [input, setInput] = useState('');
const addTodo = () => {
if (input.trim()) {
setTodos([
...todos,
{
id: Date.now(),
text: input.trim(),
completed: false
}
]);
setInput('');
}
};
const toggleTodo = (id) => {
setTodos(
todos.map(todo =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
)
);
};
const deleteTodo = (id) => {
setTodos(todos.filter(todo => todo.id !== id));
};
return (
<div>
<h2>Vite React Todo App</h2>
<div style={{ display: 'flex', marginBottom: '20px' }}>
<input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyPress={(e) => e.key === 'Enter' && addTodo()}
style={{ flexGrow: 1, padding: '8px', marginRight: '10px' }}
placeholder="Add a new todo..."
/>
<button
onClick={addTodo}
style={{ background: '#4CAF50', color: 'white', border: 'none', padding: '8px 15px' }}
>
Add
</button>
</div>
<div>
{todos.length > 0 ? (
todos.map(todo => (
<TodoItem
key={todo.id}
todo={todo}
onToggle={toggleTodo}
onDelete={deleteTodo}
/>
))
) : (
<p>No todos yet. Add one above!</p>
)}
</div>
</div>
);
}
export default TodoList;
Step 3: Update App.jsx
Now, let's update the main App component to use our TodoList:
// src/App.jsx
import TodoList from './components/TodoList'
import './App.css'
function App() {
return (
<div className="App">
<TodoList />
</div>
)
}
export default App
Step 4: Update App.css
Let's add some basic styling:
/* src/App.css */
#root {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
}
.App {
width: 100%;
max-width: 500px;
margin: 0 auto;
padding: 20px;
background-color: #f5f5f5;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
Step 5: Run the Application
npm run dev
Visit http://localhost:5173 to see your todo application in action!
Output
The application will have:
- An input field to add new todos
- A list of todos with checkboxes to mark them as complete
- Delete buttons to remove todos
- Completed todos will have a strike-through style
This simple todo app demonstrates the power and simplicity of using Vite with React.
Building for Production
When you're ready to deploy your application, you can build for production with:
npm run build
This will create a dist
folder with optimized, minified code ready for deployment. To preview the production build locally:
npm run preview
Advanced Vite Features
1. CSS Pre-processors
Vite supports CSS pre-processors out of the box. Just install the corresponding pre-processor and you're good to go:
# For Sass
npm add -D sass
# For Less
npm add -D less
Then, you can directly import .scss
or .less
files:
import './styles.scss'
2. Using TypeScript
Vite has built-in TypeScript support. To start a new React project with TypeScript:
npm create vite@latest my-react-ts-app -- --template react-ts
3. CSS Modules
Vite supports CSS Modules without any configuration. Just name your CSS files with the .module.css
suffix:
/* Button.module.css */
.button {
background: blue;
color: white;
}
And then import it in your component:
import styles from './Button.module.css'
function Button() {
return <button className={styles.button}>Click me</button>
}
4. Adding SVG Support
Vite allows importing SVGs as React components with a plugin:
npm add -D vite-plugin-svgr
Update your Vite config:
// vite.config.js
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import svgr from 'vite-plugin-svgr'
export default defineConfig({
plugins: [react(), svgr()]
})
Now you can import SVGs as components:
import { ReactComponent as Logo } from './logo.svg'
function Header() {
return (
<header>
<Logo width={50} height={50} />
</header>
)
}
Common Issues and Troubleshooting
Issue 1: Environment Variables Not Working
Remember that only variables prefixed with VITE_
are exposed to your client-side code:
# Will be exposed
VITE_API_KEY=abc123
# Will NOT be exposed
API_KEY=abc123
Issue 2: HMR Not Working Properly
If hot module replacement isn't working, check if you've modified the vite.config.js
file incorrectly. Reset to defaults and gradually add configurations to identify the issue.
Issue 3: Build Errors
If you're encountering build errors, try clearing the cache:
rm -rf node_modules/.vite
Summary
Vite provides a modern, fast development experience for React applications. We've covered:
- What Vite is and why it's gaining popularity
- Setting up a basic React project with Vite
- Configuring Vite for your specific needs
- Building a practical todo application
- Advanced features like CSS pre-processors, TypeScript, and CSS Modules
- Common issues and troubleshooting tips
By using Vite for your React projects, you'll benefit from faster development times, instant hot module replacement, and optimized production builds. As the React ecosystem continues to evolve, Vite represents the next generation of build tools that prioritize developer experience without compromising on performance.
Further Resources
To continue learning about Vite and React, check out these resources:
Exercises
- Convert an existing Create React App project to Vite and compare the performance.
- Add a feature to the todo app to persist todos in local storage.
- Configure Vite to use path aliases for cleaner imports in your project.
- Create a multi-page application using React Router with Vite.
- Set up a Vite project with TypeScript, CSS Modules, and SCSS support.
Vite's speed and simplicity make it an excellent choice for modern React development, especially as applications grow in complexity. Happy coding!
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)