Explore Blogs
No more create react app? Here’s how I set up react with react router anyway

Create React App (CRA) has officially been deprecated, leaving developers looking for alternatives to set up React projects from scratch. In this post, I walk you through how to create a modern React application with React Router, using esbuild or Webpack — no Vite, no frills. I'll explain why esbuild is my go-to bundler for most projects, while Webpack remains the choice for complex, large-scale applications. Plus, I'll show you how to add TypeScript for a type-safe, modern development experience.
CRA is dead. Long Live React.
So, it finally happened — Create React App (CRA) got sunset.
Honestly? I saw it coming. CRA had been feeling clunky and slow for years. The dev server wasn't keeping up. Config tweaks felt like cracking open a black box. And ejecting? Nobody wanted to go there.
But when it officially got deprecated in early 2025, I realized something: I needed a go-to way to spin up React projects without relying on Vite or Next.js.
Because here's the thing. Not every project needs server-side rendering. Not every dev wants to learn a new meta-framework just to throw up a dashboard.
Sometimes, I just want to write React. Plain, modern React. With client-side routing. From scratch.
The challenge: Setting up React without CRA
The whole point of CRA was to offer a quick, ready-to-go solution with sensible defaults. No boilerplate, no hassle — just the basic tools you needed to start writing React.
Now that CRA's gone, I've been experimenting with different ways to set up a React project from scratch. I've tried using Vite, but that's just not my jam (more on that later). The other option? Go back to Webpack — the old reliable bundler that powers so many React apps under the hood.
But I realized something else: esbuild.
While esbuild is not as mature as Webpack, it's fast, lightweight, and getting better every day. Its performance, especially for smaller to mid-sized projects, is something that's hard to ignore.
So, what's the difference between webpack and esbuild?
Before we dive into the setup process, let's take a moment to consider the two most popular bundlers right now: Webpack and esbuild.
Why esbuild?
- Lightning-fast Builds: esbuild is written in Go, and it's optimized for speed. If you value fast feedback loops and quick reload times, esbuild is the way to go.
- Zero configuration: The best part? You don't need to spend hours configuring esbuild. It just works. It's perfect for those who want to keep things simple without sacrificing performance.
- Modern syntax support: Out-of-the-box support for ES Modules, TypeScript, and JSX makes esbuild an incredibly convenient choice for modern JavaScript development.
Why Webpack?
- Configurability: Webpack has a rich configuration ecosystem, perfect for projects that require advanced setups like code splitting, tree shaking, and complex workflows.
- Mature ecosystem: If your project is large-scale and demands extensive features (like image optimization or custom asset handling), Webpack's ecosystem of plugins and loaders can handle just about anything you throw at it.
- Community support: Webpack has been the gold standard for JavaScript bundling for years, which means tons of documentation, tutorials, and community support are available.
Which one should you choose?
For small to medium-sized React projects, esbuild is my go-to. But if you need heavy customization or you're working with large, complex apps, Webpack may still be the best choice.
In the following sections, I'll walk you through how to set up both bundlers with React Router, so you can decide which one fits your needs.
Setting up React with React Router using esbuild
Let's start with esbuild. It's simple and quick to get up and running.
Step 1: Initialize your project
First, create a new directory for your project:
mkdir my-esbuild-react-app
cd my-esbuild-react-app
npm init -y
Step 2: Install dependencies
Next, we'll install React, ReactDOM, and esbuild:
npm install react react-dom react-router-dom
npm install --save-dev esbuild
Step 3: Create Project Files
Now, let's create our basic project structure:
/src
├── index.js
└── App.js
/public
└── index.html
- src/index.js (Entry point for React)
- src/App.js (Main React component)
- public/index.html (HTML template)
Step 4: Build with esbuild
In your package.json
, add the build script:
"scripts": {
"start": "esbuild src/index.js --bundle --outdir=public --watch"
}
This tells esbuild to bundle the JavaScript and output it in the public
folder.
Step 5: Run your project
Now, you can start the dev server:
npm start
Visit http://localhost:3000
to see your app in action.
Setting Up React with React Router Using Webpack
If you prefer Webpack for more control, here's how to set it up.
Step 1: Initialize your project
First, create a new directory for your project:
mkdir my-webpack-react-app
cd my-webpack-react-app
npm init -y
Step 2: Install dependencies
Install React, ReactDOM, and Webpack dependencies:
npm install react react-dom react-router-dom
npm install --save-dev webpack webpack-cli webpack-dev-server babel-loader @babel/core @babel/preset-env @babel/preset-react html-webpack-plugin style-loader css-loader
Step 3: Create Webpack configuration
In the root directory, create a file named webpack.config.js
:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
},
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: 'babel-loader',
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
],
},
resolve: {
extensions: ['.js', '.jsx'],
},
devServer: {
contentBase: './dist',
port: 3000,
},
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html',
}),
],
mode: 'development',
};
Step 4: Set up Babel
Create a .babelrc
file for Babel configuration:
{
"presets": ["@babel/preset-env", "@babel/preset-react"]
}
Step 5: Add scripts to package.json
Update the scripts section in package.json
:
"scripts": {
"start": "webpack serve --open",
"build": "webpack --mode production"
}
Step 6: Run your project
Now you can run the development server:
npm start
Head over to http://localhost:3000
, and you should see your React app running.
Wrapping it up: esbuild or Webpack — Your choice
Both esbuild and Webpack have their places in modern React development. Here's the short version:
- esbuild: Fast, simple, and modern. Perfect for small to medium-sized projects where speed and minimal configuration are key.
- Webpack: The heavyweight champion. If you need flexibility, custom configurations, or are working on a larger-scale application, Webpack is still the bundler of choice.
I personally prefer esbuild for most of my projects. It's quicker, simpler, and the performance boost it offers is unmatched. But if you find yourself needing more control, Webpack is still a reliable, battle-tested solution.
Adding TypeScript to your React project
If you're already comfortable with React and want to take advantage of TypeScript for better type safety and code quality, it's easy to add it to your existing setup.
Adding TypeScript to your React project with esbuild
Step 1: Install TypeScript and type definitions
Run the following command to install TypeScript and the necessary type definitions for React:
npm install --save-dev typescript @types/react @types/react-dom
Step 2: Create a tsconfig.json
File
Now, create a tsconfig.json
file in the root of your project to configure TypeScript.
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "esnext"],
"allowJs": true,
"jsx": "react-jsx",
"moduleResolution": "node",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src"]
}
This configuration ensures TypeScript works smoothly with React and JSX.
Step 3: Rename files from .js
to .tsx
Since you're using TypeScript, you need to rename your React files that contain JSX from .js
to .tsx
. For example:
src/index.js
->src/index.tsx
src/App.js
->src/App.tsx
Step 4: Update your esbuild build command
Now, update your esbuild build command to handle TypeScript. In your package.json
:
"scripts": {
"start": "esbuild src/index.tsx --bundle --outdir=public --watch"
}
This tells esbuild to process TypeScript files (with the .tsx
extension) and bundle them.
Step 5: Start your project
Now, you can run your project as usual:
npm start
Adding TypeScript to your React project with Webpack
Step 1: Install TypeScript and type definitions
As with esbuild, you'll need to install TypeScript and the necessary type definitions for React:
npm install --save-dev typescript @types/react @types/react-dom
Step 2: Create a tsconfig.json
File
Create a tsconfig.json
file at the root of your project with the following settings:
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "esnext"],
"allowJs": true,
"jsx": "react-jsx",
"moduleResolution": "node",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src"]
}
Step 3: Update your Webpack configuration
Next, you need to update your Webpack configuration to handle TypeScript. In your webpack.config.js
file, ensure that you have Babel set up to process TypeScript files.
Add ts-loader
to your Webpack config:
Install the required loader:
npm install --save-dev ts-loader
Update your webpack.config.js
to include ts-loader
for .ts
and .tsx
files:
module.exports = {
entry: './src/index.tsx',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
},
module: {
rules: [
{
test: /\.tsx?$/,
exclude: /node_modules/,
use: 'ts-loader',
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
],
},
resolve: {
extensions: ['.js', '.jsx', '.ts', '.tsx'],
},
devServer: {
contentBase: './dist',
port: 3000,
},
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html',
}),
],
mode: 'development',
};
Step 4: Rename files from .js
to .tsx
Rename your React files that contain JSX from .js
to .tsx
. For example:
src/index.js
->src/index.tsx
src/App.js
->src/App.tsx
Step 5: Add a TypeScript entry point
In your package.json
, make sure the start command points to your new TypeScript entry file:
"scripts": {
"start": "webpack serve --open",
"build": "webpack --mode production"
}
Step 6: Run your project
Run your Webpack project as usual:
npm start
Conclusion: TypeScript in your React project
By adding TypeScript, you'll get strong typing and better code autocompletion, which improves your development experience. Whether you choose esbuild or Webpack, integrating TypeScript is seamless and will add a layer of robustness to your React projects.
Why not Vite (and others)?
Now, you might be wondering, why not Vite? It's the new hotness in the React world, right? Fast, easy to configure, and with a ton of modern features out of the box.
And, yes, I get it. Vite has gained a lot of popularity, and it's a great tool. But here's the thing: Not every project needs the overhead or specific features that Vite brings. For some developers, especially those who want minimal configuration and performance without dealing with another meta-framework, esbuild or Webpack might feel more at home.