JavaScript and React course Β· Module 1: React Basics
Creating a React project with Vite
In this lesson6
On a cosmic journey through the React world, you need a suitable ship to set off. In the past, the standard choice was Create React App (CRA), but this tool has been officially deprecated and is no longer maintained. The modern standard for creating React projects is Vite - an ultrafast next-generation bundler.
Ra, our cosmic guide, says: "Abandon the old CRA shuttle - Vite is the new warp drive engine that will take you to the React galaxy faster than ever!"
Why Vite?
Vite (pronounced "veet," from French for "fast") is a modern tool for building frontend applications, created by Evan You (the creator of Vue.js). The React documentation lists it (alongside Parcel and Rsbuild) among the recommended tools when you build an app without a framework.
Why Vite replaced CRA:
- Lightning-fast server start - Vite leverages native browser ES modules (ESM), so the development server starts in 1-2 seconds (CRA needed 20-40 seconds)
- Instant Hot Module Replacement (HMR) - code changes appear in the browser in ~50ms, regardless of the application size
- Modern architecture - built on ESM instead of the older Webpack
- Fast production builds - since Vite 8 it uses Rolldown (previously Rollup) to bundle files
- Out-of-the-box support - TypeScript, JSX, CSS Modules, PostCSS work without additional configuration
Creating a new project with Vite
To create a new React project with Vite, open the terminal and type:
1npm create vite@latest my-react-app -- --template reactThis command:
- Uses
npm createto run the Vite generator vite@latestensures using the latest versionmy-react-appis your project name--template reactselects the React template (also available:react-tsfor TypeScript)
After creating the project, navigate to the directory and install dependencies:
1cd my-react-app
2npm installThen start the development server:
1npm run devYour application will be available at http://localhost:5173 in the browser. Note - Vite uses port 5173 by default, not 3000.
Vite + React project structure
After creating the project, you'll see the following structure:
1my-react-app/
2βββ node_modules/ # Installed dependencies
3βββ public/ # Static files (copied as-is)
4β βββ favicon.svg # Site icon
5β βββ icons.svg # Icons
6βββ src/ # Source code
7β βββ assets/ # Assets (images, fonts)
8β β βββ react.svg # React logo
9β βββ App.css # App component styles
10β βββ App.jsx # Main App component
11β βββ index.css # Global styles
12β βββ main.jsx # Application entry point
13βββ index.html # Main HTML file (in root directory!)
14βββ vite.config.js # Vite configuration
15βββ package.json # Project info and dependencies
16βββ .gitignore # Files ignored by Git
17βββ .oxlintrc.json # Linter configuration (Oxlint)Key differences from CRA
Notice a few important differences:
- index.html is in the root directory, not in
public/- Vite treats it as the entry point - Files use the .jsx extension instead of .js - this clearly signals that a file contains JSX
- The entry point is main.jsx, not index.js
- vite.config.js instead of hidden Webpack configuration - you have full control
index.html
In Vite, the index.html file is in the project root directory and looks like this:
1<!DOCTYPE html>
2<html lang="en">
3 <head>
4 <meta charset="UTF-8" />
5 <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7 <title>Vite + React</title>
8 </head>
9 <body>
10 <div id="root"></div>
11 <script type="module" src="/src/main.jsx"></script>
12 </body>
13</html>The key line is <script type="module" src="/src/main.jsx"></script> - Vite loads the application as a native ES module, ensuring a lightning-fast start.
src/main.jsx
This is the React application entry point:
1import React from 'react'
2import ReactDOM from 'react-dom/client'
3import App from './App.jsx'
4import './index.css'
5
6ReactDOM.createRoot(document.getElementById('root')).render(
7 <React.StrictMode>
8 <App />
9 </React.StrictMode>,
10)This code:
- Imports React and ReactDOM
- Creates a React "root" in the element with id
root - Renders the main
Appcomponent insideStrictMode
src/App.jsx
The main component of your application:
1import { useState } from 'react'
2import reactLogo from './assets/react.svg'
3import viteLogo from '/vite.svg'
4import './App.css'
5
6function App() {
7 const [count, setCount] = useState(0)
8
9 return (
10 <>
11 <div>
12 <a href="https://vite.dev" target="_blank">
13 <img src={viteLogo} className="logo" alt="Vite logo" />
14 </a>
15 <a href="https://react.dev" target="_blank">
16 <img src={reactLogo} className="logo react" alt="React logo" />
17 </a>
18 </div>
19 <h1>Vite + React</h1>
20 <div className="card">
21 <button onClick={() => setCount(c => c + 1)}>
22 count is {count}
23 </button>
24 </div>
25 </>
26 )
27}
28
29export default Appvite.config.js
The Vite configuration file - simple and readable:
1import { defineConfig } from 'vite'
2import react from '@vitejs/plugin-react'
3
4export default defineConfig({
5 plugins: [react()],
6})That's all you need! The @vitejs/plugin-react plugin provides JSX support, Fast Refresh (HMR), and other React features.
Available scripts
In the Vite project's package.json you'll find:
npm run dev- starts the development server with HMRnpm run build- builds the application for production deploymentnpm run preview- previews the built production version locallynpm run lint- checks the code with a linter (in the current template: Oxlint)
Vite vs CRA - comparison
| Feature | CRA (deprecated) | Vite |
|---|---|---|
| Status | Deprecated, no updates | Actively maintained |
| Server start | 20-40 seconds | 1-2 seconds |
| HMR | 1-3 seconds | ~50ms |
| Bundler | Webpack | Rolldown (since Vite 8; previously esbuild + Rollup) |
| Configuration | Hidden (eject) | Explicit (vite.config.js) |
| Modules | CommonJS | Native ES Modules |
| TypeScript | Requires configuration | Works out-of-the-box |
Other tools in the React ecosystem
Besides Vite, it's worth knowing other popular tools:
- Next.js - a React framework with SSR (Server-Side Rendering), SSG, and file-based routing. Ideal for applications requiring SEO
- React Router (formerly Remix) - a React framework focused on web fundamentals and progressive enhancement
- Gatsby - a static site generator with GraphQL
For learning React and building SPA (Single Page Application) applications, Vite is the best choice - fast, simple, and listed in the React documentation.
Ra summarizes: "Vite is the next-generation engine for your React spaceship. Fast startup, instant reactions to course changes, and full control over configuration - everything you need to conquer the galaxy!"
Code for this lesson: App.jsx
1import React, { useState } from 'react';
2
3// Demonstration of Vite + React project structure
4function ViteProjectDemo() {
5 const [activeFile, setActiveFile] = useState('App.jsx');
6
7 const fileStructure = [
8 { name: 'node_modules/', type: 'folder', description: 'Installed packages' },
9 { name: 'public/', type: 'folder', description: 'Static files' },
10 { name: ' vite.svg', type: 'file', description: 'Vite logo' },
11 { name: 'src/', type: 'folder', description: 'Source code' },
12 { name: ' assets/', type: 'folder', description: 'Assets (images, fonts)' },
13 { name: ' App.jsx', type: 'file', description: 'Main component', active: true },
14 { name: ' App.css', type: 'file', description: 'Component styles' },
15 { name: ' main.jsx', type: 'file', description: 'Entry point' },
16 { name: ' index.css', type: 'file', description: 'Global styles' },
17 { name: 'index.html', type: 'file', description: 'Main HTML (in the root directory!)' },
18 { name: 'vite.config.js', type: 'file', description: 'Vite configuration' },
19 { name: 'package.json', type: 'file', description: 'Project configuration' },
20 ];
21
22 const fileContents = {
23 'App.jsx': `import { useState } from 'react'
24import './App.css'
25
26function App() {
27 const [count, setCount] = useState(0)
28
29 return (
30 <>
31 <h1>Vite + React</h1>
32 <div className="card">
33 <button onClick={() => setCount(c => c + 1)}>
34 count is {count}
35 </button>
36 </div>
37 </>
38 )
39}
40
41export default App`,
42 'main.jsx': `import React from 'react'
43import ReactDOM from 'react-dom/client'
44import App from './App.jsx'
45import './index.css'
46
47ReactDOM.createRoot(
48 document.getElementById('root')
49).render(
50 <React.StrictMode>
51 <App />
52 </React.StrictMode>,
53)`,
54 'vite.config.js': `import { defineConfig } from 'vite'
55import react from '@vitejs/plugin-react'
56
57export default defineConfig({
58 plugins: [react()],
59})`,
60 'package.json': `{
61 "name": "my-app",
62 "version": "0.0.0",
63 "type": "module",
64 "scripts": {
65 "dev": "vite",
66 "build": "vite build",
67 "preview": "vite preview"
68 },
69 "dependencies": {
70 "react": "^18.2.0",
71 "react-dom": "^18.2.0"
72 },
73 "devDependencies": {
74 "@vitejs/plugin-react": "^4.2.0",
75 "vite": "^5.0.0"
76 }
77}`
78 };
79
80 return (
81 <div style={{
82 fontFamily: 'Arial, sans-serif',
83 maxWidth: '1000px',
84 margin: '0 auto',
85 padding: '20px'
86 }}>
87 <header style={{
88 background: 'linear-gradient(135deg, #61dafb 0%, #21a1f1 100%)',
89 padding: '30px',
90 borderRadius: '12px',
91 color: 'white',
92 textAlign: 'center',
93 marginBottom: '30px'
94 }}>
95 <h1 style={{ margin: 0, fontSize: '2rem' }}>Vite + React</h1>
96 <p style={{ margin: '10px 0 0 0', opacity: 0.9 }}>
97 Project structure and basic files
98 </p>
99 </header>
100
101 <div style={{
102 backgroundColor: '#1e1e1e',
103 borderRadius: '8px',
104 padding: '20px',
105 marginBottom: '30px',
106 fontFamily: 'monospace'
107 }}>
108 <div style={{ color: '#888', marginBottom: '10px' }}>Terminal:</div>
109 <div style={{ color: '#00ff00' }}>$ npm create vite@latest my-app -- --template react</div>
110 <div style={{ color: '#888', marginTop: '5px' }}>Scaffolding project in /my-app...</div>
111 <div style={{ color: '#00ff00', marginTop: '5px' }}>Done. Now run: cd my-app && npm install && npm run dev</div>
112 </div>
113
114 <div style={{ display: 'grid', gridTemplateColumns: '300px 1fr', gap: '20px' }}>
115 <div style={{
116 backgroundColor: '#252526',
117 borderRadius: '8px',
118 padding: '15px'
119 }}>
120 <h3 style={{ color: '#cccccc', margin: '0 0 15px 0', fontSize: '14px' }}>
121 EXPLORER
122 </h3>
123 {fileStructure.map((item, index) => (
124 <div
125 key={index}
126 onClick={() => item.type === 'file' && setActiveFile(item.name.trim())}
127 style={{
128 padding: '8px 10px',
129 color: item.type === 'folder' ? '#dcb67a' : '#9cdcfe',
130 cursor: item.type === 'file' ? 'pointer' : 'default',
131 backgroundColor: activeFile === item.name.trim() ? '#094771' : 'transparent',
132 borderRadius: '4px',
133 fontSize: '14px',
134 fontFamily: 'monospace'
135 }}
136 >
137 {item.type === 'folder' ? 'βΈ' : 'β’'} {item.name}
138 </div>
139 ))}
140 </div>
141
142 <div style={{
143 backgroundColor: '#1e1e1e',
144 borderRadius: '8px',
145 padding: '20px'
146 }}>
147 <div style={{
148 color: '#888',
149 fontSize: '12px',
150 marginBottom: '10px',
151 borderBottom: '1px solid #333',
152 paddingBottom: '10px'
153 }}>
154 {activeFile}
155 </div>
156 <pre style={{
157 color: '#d4d4d4',
158 margin: 0,
159 fontSize: '14px',
160 lineHeight: '1.5',
161 overflow: 'auto'
162 }}>
163 {fileContents[activeFile] || '// Select a file from the list'}
164 </pre>
165 </div>
166 </div>
167
168 <div style={{
169 marginTop: '30px',
170 padding: '20px',
171 backgroundColor: '#fff3e0',
172 borderRadius: '8px'
173 }}>
174 <h3 style={{ color: '#e65100', marginTop: 0 }}>Startup commands</h3>
175 <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: '15px' }}>
176 <div style={{ backgroundColor: 'white', padding: '15px', borderRadius: '8px' }}>
177 <code style={{ color: '#e65100' }}>npm run dev</code>
178 <p style={{ margin: '5px 0 0 0', fontSize: '14px', color: '#666' }}>
179 Starts the development server
180 </p>
181 </div>
182 <div style={{ backgroundColor: 'white', padding: '15px', borderRadius: '8px' }}>
183 <code style={{ color: '#e65100' }}>npm run build</code>
184 <p style={{ margin: '5px 0 0 0', fontSize: '14px', color: '#666' }}>
185 Builds the production version
186 </p>
187 </div>
188 </div>
189 </div>
190 </div>
191 );
192}
193
194export default function App() {
195 return <ViteProjectDemo />;
196}Spotted a mistake in this lesson?
Check yourself
Answer the questions from this lesson. Pick an answer to see right away whether it is correct.
1. What is Vite used for in the React ecosystem?
2. What is hot reloading in React?
Hands-on tasks in the game
- Click in order
Arrange the steps for creating your first React application:
- Vertical ordering
Arrange the stages of code transpilation by Babel from top to bottom:
- Code editor
Create a simple React App component that displays a heading and a welcome paragraph.
- Click in order
Build the command to create a new React project with Vite: