Explore Blogs

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

bpi-react-project-setup-from-scratch-includes-typescript-setup

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.

CRA is no longer the default tool for setting up React projects, but that doesn't mean you need to compromise on simplicity or performance. Whether you prefer esbuild for its speed and minimal configuration, or Webpack for its deep customizability, both bundlers can be used to create a clean, efficient React environment. Adding TypeScript for better type safety is also a breeze. Whichever setup you choose, you'll have a modern, fast, and scalable React project up and running in no time.

Stay Updated

This site is protected by reCAPTCHA and the GooglePrivacy Policy andTerms of Service apply.