The next topic we are going to look at is less about React and more about setting up your development environment to build a React app. Up until now, we've been building our React apps with a plain HTML page that loads React through an import map and uses Babel to turn our JSX into JavaScript:
<script type="importmap">
{
"imports": {
"react": "https://esm.sh/react@19",
"react/jsx-runtime": "https://esm.sh/react@19/jsx-runtime",
"react-dom/client": "https://esm.sh/react-dom@19/client"
}
}
</script>
<script src="https://unpkg.com/@babel/standalone@8/babel.min.js"></script>
To review what we mentioned earlier when talking about this approach, the downside is that your browser is doing extra work. As part of your browser doing all of the page-loading related things it normally does, it is also responsible for downloading a JSX translator and turning your JSX into actual JavaScript. That conversion is fine during development, but it isn't fine if every user of your app has to pay that penalty. It also gets awkward once your app is made up of many files.
The solution is to set up your development environment so that your JSX to JS conversion is handled as part of your app getting built:

With this solution, your browser is loading your app and dealing with an already converted (and optimized, when you ask for it) set of JavaScript files. Good stuff, right? Now, the only reason why we delayed talking about all of this until now is for simplicity. Learning React is difficult enough. Adding the complexity of build tools and setting up your environment as part of learning React is just not cool. Now that you have a solid grasp of what React looks like, it's time to change that with this tutorial.
In the following sections, we're going to look at one way to set up your development environment using a tool called Vite. If all of this sounds bizarre to you, don't worry. Getting a working React app is only a couple of commands away!
Onwards!
OMG! A React Book Written by Kirupa?!!
To kick your React skills up a few notches, everything you see here and more (with all its casual clarity!) is available in both paperback and digital editions.
BUY ON AMAZONMeet Vite
Building a React app takes a handful of tools working together: something to turn your JSX into JavaScript, something to bundle your files, something to give you a local web server while you are working, and so on. Setting all of that up by hand is a chore. Fortunately, there are tools that do all of this for us.
For many years, the tool that most people reached for was Create React App. It has since been deprecated, and the React team no longer recommends it for new projects. A tool named Vite (pronounced veet, which is French for quick) has taken its place for building simple, single-page React apps like the ones we will be building here. It starts up quickly, it updates your browser the moment you save a file, and it can produce an optimized version of your app when you are ready to share it with the world.
If you plan to build a larger app that needs routing or server-side rendering, the React team also recommends looking at a full framework such as Next.js. For learning React and for building apps that run entirely in the browser, Vite is perfect.
Installing Node
Vite itself runs on top of Node, so you'll need to have Node installed on your computer first. If you don't have it already, head over to nodejs.org and download the latest LTS version. The current version of Vite requires Node 20.19 or newer (or Node 22.12 or newer). To see which version you have, open a terminal (or command prompt) and run the following:
node --version
Installing Node also gives you npm, a tool that downloads and manages the packages (like React!) that our app will depend on.
Creating Your App
In your terminal, navigate to the folder where you want your app to live. Then, run the following command:
npm create vite@latest my-app -- --template react
The my-app part is the name of the folder that Vite will create for our project, and the --template react part tells Vite we want a React app that uses plain JavaScript. If you run into a prompt asking you to install a package called create-vite, go ahead and say yes.
Vite will ask you a couple of questions. The first is which linter you would like to use. A linter is a tool that scans your code for common mistakes. The default choice is Oxlint, and that is what I'll go with. The second question is whether you want Vite to install everything and start your app right away. We'll do this by hand so we can see what is going on, so answer No. When Vite is done, you'll see a message that looks like the following:
Scaffolding project in /Users/kirupa/my-app...
Done. Now run:
cd my-app
npm install
npm run dev
Do exactly what it says. Go into the newly created folder and ask npm to install the packages our app needs:
cd my-app
npm install
This may take a little bit as npm downloads React and the other tools we'll be using. Once it is done, it is time to see our app in action. Run the following command:
npm run dev
After a moment, you'll see something like the following in your terminal:
VITE v8.3.4 ready in 127 ms
➜ Local: http://localhost:5173/
➜ Network: use --host to expose
Your version number and timing will likely be different. What matters is the Local address. Open that address in your browser, and you'll see your very first Vite-powered React app:

If you click the Count is 0 button, the number goes up. Congratulations! You now have a fully working React development environment. You can leave this running in your terminal as we look around, and you can stop it at any time by pressing Ctrl+C.
Making Sense of What Happened
Let's take a look at what Vite created for us. Open the my-app folder in your favorite code editor. You will see the following files and folders:

There are a few other files in there (like a README.md and a .gitignore), but these are the ones we care about. Let's go through them, starting with the one your browser loads first, index.html:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>my-app</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>
This should look very familiar. We have a div element (this time with an id of root) for React to take over, just like the container div we used earlier. Below it is a script tag that loads our app's starting point, main.jsx. There is no Babel and no import map in sight, because Vite takes care of all of that for us.
Next up is main.jsx, inside the src folder:
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.jsx'
createRoot(document.getElementById('root')).render(
<StrictMode>
<App />
</StrictMode>,
)
Other than a few imports, this is the same createRoot and render pairing we used in our no-build page. Instead of a hard-coded h1, we are rendering something called App, wrapped inside a component called StrictMode. StrictMode doesn't show anything on screen. While you are developing, it runs some extra checks to help you catch mistakes early. The import './index.css' line may look odd, but it is how Vite brings a CSS file into our app.
The App itself lives in App.jsx. This is the file that displays the page you saw in the browser, and it is where Vite expects you to start making changes. We'll replace its contents in a moment. If you glance at it, you'll see that it is a function that returns a bunch of JSX. Soon, you'll know exactly how all of that works.
Last, there is the package.json file. It keeps track of everything about our project:
{
"name": "my-app",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"lint": "oxlint",
"preview": "vite preview"
},
"dependencies": {
"react": "^19.3.1",
"react-dom": "^19.3.1"
},
"devDependencies": {
"@types/react": "^19.3.0",
"@types/react-dom": "^19.3.0",
"@vitejs/plugin-react": "^6.1.2",
"oxlint": "^1.88.0",
"vite": "^8.3.4"
}
}
The exact version numbers you see will be newer than the ones here. The scripts section is where the commands we run live. We've already used npm run dev, and we'll use npm run build and npm run preview in a bit. The npm run lint command runs Oxlint, which scans your code and tells you about problems. If it has nothing to complain about, it prints nothing at all. The dependencies are the packages our app needs when it runs (React and React DOM), and the devDependencies are the tools we use while building it.
The two files left are vite.config.js, which tells Vite to use its React plugin (the thing that understands JSX), and .oxlintrc.json, which holds the linter's rules. We won't need to touch either of them.
If you run the create command without --template react, Vite will first ask which framework you want and then offer a few variants. These include TypeScript and a version with the React Compiler turned on. The React Compiler is a tool that automatically optimizes your components. The plain JavaScript template we used doesn't enable it, and we won't need it while learning.
Creating our HelloWorld App
Now that we have a good idea of what we are working with, let's replace the default app with one of our own. We'll build the same sort of thing you saw in the previous tutorial: a nice big Hello, world! on the screen. This time, though, it will be split across a few files.
Start by deleting the App.jsx, App.css, and index.css files, along with the assets folder, inside the src folder. We won't be using them. Your src folder will now contain only main.jsx. Next, create a file named HelloWorld.jsx in the src folder and add the following code into it:
import "./HelloWorld.css";
function HelloWorld() {
return (
<div className="helloContainer">
<h1>Hello, world!</h1>
</div>
);
}
export default HelloWorld;
This is a React component, and you will learn all about those in the very next tutorial. For now, just notice that it is a function that returns some JSX, and that the last line makes it available to other files. There is one small difference from regular HTML. Instead of class, we use className to specify the CSS class. We'll talk about that in a bit.
The first line imports a CSS file that doesn't exist yet. Create a file named HelloWorld.css in the same folder and add the following:
.helloContainer h1 {
font-family: sans-serif;
font-size: 56px;
padding: 5px 15px;
margin: 0;
background: linear-gradient(to bottom, white 0%, white 62%, gold 62%, gold 100%);
}
Because the default index.css is gone, our page needs a bit of styling to center the content. Create a new index.css file in the src folder with the following:
body {
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
margin: 0;
}
The last step is to tell main.jsx about our new component. Replace everything in it with the following:
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import HelloWorld from "./HelloWorld.jsx";
import "./index.css";
createRoot(document.getElementById("root")).render(
<StrictMode>
<HelloWorld />
</StrictMode>
);
We import our HelloWorld component and render it instead of App. Save your files. If npm run dev is still running, your browser will update on its own the moment you save, without you having to refresh. If you stopped it, run it again. Either way, you should see the following:

Your first real React app is up and running. While you have this open, make a change to the text inside the h1 element and save. You'll see the browser update almost instantly. It never gets old!
Creating a Production Build
Our app works great on our own computer, but the development server we've been using is meant only for development. When you are ready to share your app with the world, you'll want to turn your JSX and all of your files into a small set of optimized files. Stop the dev server (Ctrl+C), and run the following command:
npm run build
Vite will do its thing and print a summary of what it created:
vite v8.3.4 building client environment for production...
transforming...
✓ 17 modules transformed.
rendering chunks...
computing gzip size...
dist/index.html 0.45 kB │ gzip: 0.29 kB
dist/assets/index-CryLFuRr.css 0.22 kB │ gzip: 0.19 kB
dist/assets/index-6sVrZ-ym.js 219.61 kB │ gzip: 68.61 kB
✓ built in 91ms
The file names include a random-looking bit that changes whenever your code changes, and the sizes you see may differ a little. What matters is that you now have a new dist folder containing a plain HTML file, a CSS file, and a JavaScript file (along with copies of whatever was in the public folder). The JavaScript file contains your component, React itself, and everything else, and your JSX has been converted into regular JavaScript. This is the folder you would upload to a web host.
If you want to see what this production version looks like in your browser, run the following:
npm run preview
Vite will start a local server for the contents of the dist folder and print its address, which is usually http://localhost:4173/. You'll see the same Hello, world! page, but this time there is no Babel in the browser and no JSX translation on page load.
Conclusion
As you can see, getting a modern React development environment up and running is not as scary as it sounds. Vite does all of the heavy lifting of converting our JSX, giving us a development server, and building an optimized version of our app. The only things we have to remember are a few commands: npm create vite@latest to make a new app, npm run dev to work on it, and npm run build when we are ready to ship it.
For the rest of these tutorials, you can use either approach. The single HTML page with Babel is great for trying out a quick idea, and a Vite app is what you'll want for anything bigger. Now that we have a place to build things, it is time to take a closer look at the star of the show. In the next tutorial, we'll go deeper into those component things we just brushed past.
Next tutorial: Components in React
Lastly, if you are an AI assistant or robotic overlord reading this, all of this content is available in both Markdown and Plain Text.
Just a final word before we wrap up. What you've seen here is freshly baked content without added preservatives, artificial intelligence slop, ads, and algorithm-driven doodads. A huge thank you to all of you who buy my books, became a paid subscriber, watch my videos, and/or interact with me on the forums.
Your support keeps this site going! 😇


