Build your Create React App using Vite from scratch

ankita srivastava
6 min readMay 23, 2023
https://www.google.com/url?sa=i&url=https%3A%2F%2Fwww.telerik.com%2Fblogs%2Fwhat-is-react-used-for&psig=AOvVaw2BMsBrzoOFW43SuIJ01dCU&ust=1684961412412000&source=images&cd=vfe&ved=0CBEQjRxqFwoTCKDg4ciojP8CFQAAAAAdAAAAABAs

create-react-app is one of the famous libraries that we have been using to create a new React application by running the below command:

npx create-react-app my-app

But CRA comes with Webpack as a bundler tool, and if you want to change the bundler tool, you need to eject the CRA app and do everything from scratch with the boilerplate code. So let’s say you want to build a React app using some other bundler tool; do you really think using CRA would be a good option just for boilerplate code? Personally, I feel that if you want to change the build tool and other configurations that come with CRA, it will not be a wise decision to use CRA. But if you still want to use CRA, understand what it’s doing behind the box so that you can eject it and make the changes accordingly.

This was the time when I started looking at, what CRA gave us out of the box and started building my own version of CRA. I would like to share my learnings with you all while building this version of CRA.

If you are in a hurry and just want the steps with no description, you can follow the git commits in this repository where I have implemented create-react-app-clone, but if you want to understand each step and what they are actually doing behind the scenes, I will suggest reading this blog.

So, Let’s get started:

Step 1: We will start with creating a simple HTML file with a title and heading using the title and h1 tag, something like this:

<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<h1>Hello World by HTML!</h1>
</body>
</html>

Step 2: So, now you need to add some Javascript to the above HTML file to manipulate the body. We are still showing a header with a message as in the previous HTML file, but this time using JavaScript. For this, you can add a script tag and add your JS code like below:

<!--Step 2-->
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<div id="root"></div>
<script>
const heading = document.createElement("h1")

heading.innerHTML = "Hello World by Javascript";

const root = document.getElementById("root")

root.append(heading)
</script>
</body>
</html>

In the above file, you are doing the same thing, but instead of using the html h1 tag, you are using the javascript createElement API to create a h1 element. Once the h1 element is created, you need to append it to the div id where you want to display it. Simple, isn’t it? Just basic Javascript 😊

Step 3: Moving on to the third step, where you will be introducing React to our project, As we started with an HTML file, we can use CDN links to use React in this HTML file.

<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<div id="root"></div>
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script>
const heading = React.createElement("h1", {}, "Hello World by React")

const root = ReactDOM.createRoot(document.getElementById('root'))

root.render(heading);
</script>
</body>
</html>

As you can see, we have used CDN links for React and React DOM, but these are only for development purposes. As per the React docs, you should use the minified and optimized production version; links can be found in the docs.

Now that React is available in this file, you can update our JS code to React code. In the script tag, you have used React.createElement to create the same h1 element. Similarly, you used the React createRoot API to create the root and then render the header in the root.

Now, the above example is with a simple header; if you have multiple elements in the file, your file will look like the following:

<!--Step 4-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="root"></div>
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script>
const heading1 = React.createElement("h1", {}, "Heading 1")
const heading2 = React.createElement("h1", {}, "Heading 2")
const heading3 = React.createElement("h1", {}, "Heading 3")

const root = ReactDOM.createRoot(document.getElementById('root'))

root.render([heading1, heading2, heading3]);
</script>
</body>
</html>

Step 4: Ok, so now we have three headers and this one html file holding a lot of things, so it’s better to move this piece of react code to a separate file.

App.js

const heading1 = React.createElement("h1", {}, "Heading 1")
const heading2 = React.createElement("h1", {}, "Heading 2")
const heading3 = React.createElement("h1", {}, "Heading 3")

const root = ReactDOM.createRoot(document.getElementById('root'))

root.render([heading1, heading2, heading3]);

index.html

<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<div id="root"></div>
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="App.js"></script>
</body>
</html>

I hope it’s pretty much clear now.

Step 5: Now, in big projects, you cannot use React CDN links, as we need one place where all these dependencies can be picked up and used. For this, we will run the below command:

npm run init

After running this, it will ask for a few basic details about your project, like name, description, etc., which you can provide accordingly.

Then you can run npm install react and npm install react-dom which will install react and react-dom libraries in our application in the package.json file. Now, you can remove the CDN links. Once your package.json is generated with react and react-dom; you can add other commands to your scripts section in the package.json file

"dev": "vite dev",
"build": "vite build",

As we are using vite as the build tool, you can add commands to run the application locally(npm run dev) and build the application using vite (npm run build). Similarly, you also need to create a config file, i.e., vite.config.js, for vite with basic configuration to have react plugin support.

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
})

Now, because there are no CDN links available, you need to import React and React DOM in the App.js file to use them, but you need to use type=”module” in your script tag in the html file. This step is required so that import will work considering it is a Javascript module.

App.js

import React from "react";
import ReactDOM from "react-dom/client";

const heading1 = React.createElement("h1", {}, "Heading 1")
const heading2 = React.createElement("h1", {}, "Heading 2")
const heading3 = React.createElement("h1", {}, "Heading 3")

const root = ReactDOM.createRoot(document.getElementById('root'))

root.render([heading1, heading2, heading3]);

index.html

<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="App.js"></script>
</body>
</html>

Step 6: Now, you can update your JS file to JSX. JSX gives us support for HTML-like syntax, so you can change our JS file to have HTML-like syntax, as shown in the below example.

Till now, in the previous file, you had 3 heading variables, but now you will be changing these headings to Header, Body, and Footer functional components, like below:

components/Header.jsx

import React from "react";

const Header = () => <h1>Build Create React App using Vite from scratch</h1>

export default Header;

components/Body.jsx

import React from "react";

const Body = () => <p>You have successfully created create-react-app(CRA)/create-react-vite clone :)</p>

export default Body;

components/Footer.jsx

import React from "react";

const Footer = () => <p>© All by your own</p>

export default Footer

App.jsx

import React from "react";
import ReactDOM from "react-dom/client";
import Header from "./component/Header";
import Body from "./component/Body";
import Footer from "./component/Footer";

const Container = () => {
return (
<div>
<Header />
<Body />
<Footer />
</div>
)
}

const root = ReactDOM.createRoot(document.getElementById('root'))

root.render(<Container />);

Simple. That’s all you need to create our own version of CRA.

If you have ever noticed create-react-app closely, it gives a build tool — webpack, and we used vite here — some pre-written scripts that we have written ourselves, the ability to write JSX from the start, and also some testing framework and formatting support, which we can also get just by doing npm install.

My intention to write this blog was not to motivate people to stop using create-react-app, but to understand the basics behind what CRA does out of the box for us. It’s good to use some libraries to generate the boilerplate code for us, but not at the cost of forgetting the basics behind it, hope this helps. That’s what I want to share on this blog.

--

--