Setting up a React application manually using Webpack provides developers with fine-grained control over every aspect of the build process. While tools like Create React App (CRA) simplify the process, they abstract away the build configuration. For advanced scenarios—like optimizing bundle size, customizing Babel or PostCSS, or tweaking performance—setting up from scratch is invaluable.

In this article, we’ll walk through how to create a React app from the ground up using Webpack. You’ll learn how to bundle JavaScript, transpile JSX using Babel, handle styles, and set up hot module replacement.

Initialize the Project

Start by creating a new directory and initializing a Node.js project.

bash
mkdir react-webpack-app
cd react-webpack-app
npm init -y

This will create a package.json file where your project’s dependencies and scripts will be managed.

Install Webpack and Core Dependencies

Next, install Webpack and the necessary tools for bundling.

bash
npm install --save-dev webpack webpack-cli webpack-dev-server
  • webpack: Core bundler.

  • webpack-cli: Command-line interface for Webpack.

  • webpack-dev-server: Development server with live reloading.

Create the project structure:

bash
mkdir src public
touch src/index.js public/index.html

Add a basic HTML skeleton in public/index.html:

html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>React Webpack App</title>
</head>
<body>
<div id="root"></div>
<script src="../dist/main.js"></script>
</body>
</html>

Add React and Babel for JSX Transpilation

Now install React and Babel to handle JSX and modern JavaScript features:

bash
npm install react react-dom
npm install --save-dev @babel/core babel-loader @babel/preset-env @babel/preset-react
  • @babel/core: Core Babel compiler.

  • babel-loader: Webpack loader for Babel.

  • @babel/preset-env: Enables modern JavaScript support.

  • @babel/preset-react: Supports JSX transpilation.

Create a Babel config file:

bash
touch .babelrc

Add the following content:

json
{
"presets": ["@babel/preset-env", "@babel/preset-react"]
}

Now update src/index.js to render a simple React component:

jsx
import React from 'react';
import ReactDOM from 'react-dom';
const App = () => <h1>Hello React with Webpack!</h1>;ReactDOM.render(<App />, document.getElementById(‘root’));

Configure Webpack

Create the Webpack configuration file:

bash
touch webpack.config.js

Here’s a basic configuration:

js

const path = require('path');

module.exports = {
entry: ‘./src/index.js’,
output: {
path: path.resolve(__dirname, ‘dist’),
filename: ‘main.js’,
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ‘babel-loader’,
}
],
},
resolve: {
extensions: [‘.js’, ‘.jsx’],
},
devServer: {
static: {
directory: path.join(__dirname, ‘public’),
},
compress: true,
port: 3000,
hot: true,
},
mode: ‘development’,
};

This sets up:

  • JavaScript/JSX transpilation.

  • Hot reloading via Webpack Dev Server.

  • React rendering on localhost:3000.

Add scripts to package.json:

json
"scripts": {
"start": "webpack serve --open",
"build": "webpack"
}

Add Style Handling (CSS, SASS, Modules)

Install style-related loaders:

bash
npm install --save-dev style-loader css-loader

Then update the Webpack config to include CSS support:

js
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}

Add a CSS file to test:

bash
touch src/styles.css
css
body {
font-family: sans-serif;
background-color: #f0f0f0;
}

Update your index.js to import styles:

js
import './styles.css';

Optional: Add SASS Support

bash
npm install --save-dev sass-loader sass

Add to your Webpack config:

js
{
test: /\.s[ac]ss$/i,
use: ['style-loader', 'css-loader', 'sass-loader'],
}

You can now create styles.scss and use variables or nesting.

Handle Images and Fonts

To support importing assets like images and fonts, install:

bash
npm install --save-dev file-loader

Add this to your Webpack config:

js
{
test: /\.(png|jpe?g|gif|svg|woff2?|eot|ttf|otf)$/i,
type: 'asset/resource',
}

Now you can import images directly in your components:

js
import logo from './logo.png';
<img src={logo} alt="Logo" />

Add ESLint and Prettier (Optional but Recommended)

Install linting tools:

bash
npm install --save-dev eslint eslint-plugin-react

Initialize ESLint:

bash
npx eslint --init

Enable React rules and JSX support in .eslintrc.

For Prettier:

bash
npm install --save-dev prettier eslint-config-prettier eslint-plugin-prettier

Add to .eslintrc:

json
{
"extends": ["plugin:react/recommended", "prettier"],
"plugins": ["prettier"],
"rules": {
"prettier/prettier": "error"
}
}

Production Build Optimization

Update webpack.config.js to support both development and production modes:

js

const isProd = process.env.NODE_ENV === 'production';

module.exports = {
// …
mode: isProd ? ‘production’ : ‘development’,
devtool: isProd ? ‘source-map’ : ‘eval-cheap-module-source-map’,
// …
};

For better production optimization:

bash
npm install --save-dev html-webpack-plugin clean-webpack-plugin

Add to your config:

js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template: ‘./public/index.html’,
favicon: ‘./public/favicon.ico’,
}),
],

Final Folder Structure

pgsql
react-webpack-app/

├── dist/
├── public/
│ └── index.html
├── src/
│ ├── index.js
│ ├── App.jsx
│ └── styles.css
├── .babelrc
├── package.json
├── webpack.config.js
└── .eslintrc / .prettierrc

Conclusion

Manually setting up a React project with Webpack gives developers absolute control over the build process, module handling, and performance optimizations. While it involves more initial configuration than using tools like CRA, the payoff is a fully customized development environment.

Here’s what we’ve accomplished:

  • Initialized a React project with modern JavaScript and JSX support.

  • Configured Babel for transpilation.

  • Set up Webpack for bundling assets, styles, and media.

  • Added support for CSS and optional Sass.

  • Integrated ESLint and Prettier for code quality.

  • Distinguished between development and production environments.

  • Built a clean, scalable project structure.

Whether you’re building a minimal prototype or a large-scale SPA, understanding and mastering your build pipeline lays a strong foundation for performance, maintainability, and scalability.