Webpack Dev Server: Setting up proxy
Tags: react, webpack, node, webdev
Published: 2021-10-05 05:46:13

In this article, I'll show you how to configure webpack-dev-server for proxying requests from React frontend to Node/Express backend.

#Getting Started
I won't go into much details on how to set up React, Webpack and Babel. You can either create the project from scratch or you can do the following:
## Configure Frontend
###1- Use Create React App
Run `create-react-app` to create React frontend for your web app.
```javascript
npx create-react-app my-app-name
```
###2- Configure Webpack
Add webpack and its relevant packages to your project.
```javascript
yarn add webpack webpack-cli webpack-dev-server --dev
yarn add html-webpack-plugin --dev
```
<small>*I'll be using yarn throughout this article*</small>
At the root of project folder, create file `webpack.config.js`. I won't go into details of the configuration as its very basic.
```javascript
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
    entry: {
        basicApp: {
            import: './src/index.js',
            filename: 'basicApp.js'
        }
    },
    output: {
        path: path.resolve(__dirname, 'build/static')
    },
    devServer: {
        port: 3000,
        hot: true,
        open: true,
    },
    resolve: {
        extensions: ['.jsx', '.js', '.json']
    },
    module: {
        rules: [
            {
                test: /\.(js)x?$/,
                exclude: /node_modules/,
                use: [
                    {
                        loader: 'babel-loader'
                    }
                ]
            },
            {
                test: /\.css$/,
                use: ['style-loader', 'css-loader']
            },
            {
                test: /\.(?:ico|gif|png|jpg|jpeg)$/i,
                type: 'asset/resource'
            },
            {
                test: /\.(woff(2)?|eot|ttf|otf|svg|)$/,
                type: 'asset/inline'
            }
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: './public/index.html'
        })
    ]
}
```
And make the following change in the `package.json`:
```javascript
"scripts": {
        "start": "webpack serve --mode development",
        "build": "webpack --mode production",
        ...
}
```
###3- Configure Babel
Now before you try to run the app, configure Babel compiler. Install babel and relevant packages.
```javascript
yarn add @babel/core @babel/preset-env @babel/preset-react babel-loader --dev
yarn add css-loader style-loader --dev
```
At root of project, create file `.babelrc`:
```javascript
{
  "presets": [
    "@babel/preset-env",
    [
      "@babel/preset-react",
      {
        "runtime": "automatic"
      }
    ]
  ]
}
```
You have successfully configured the frontend of your app.
## Configure Backend
Add Express to the project:
```javascript
yarn add express
```
It's your choice whether you set up the backend separately or in the same directory. I set it up in the same dir. Create file `backend/server.js` at the root.
```javascript
const express = require("express")
const path = require("path")
const app = express()

const DIST_DIR = path.join(__dirname, 'build/static')
const HTML_FILE = path.join(DIST_DIR, 'index.html')
app.use(express.static(DIST_DIR))
app.get('/', (req, res) => {
        res.sendFile(HTML_FILE)
})
app.get('/api/ping', (req, res) => {
        res.send('pong')
})

app.listen(5000)
```
In dev mode of this set up, frontend runs at `localhost:3000` and backend runs at `localhost:5000`. Hence, you need to connect frontend to backend so that querying on `locahost:3000/api/ping` hits the backend `localhost:5000/api/ping`. For this you can configure proxy in `webpack.config.js`:
```javascript
devServer: {
        ...
        proxy: {
           '/api': {
                target: 'http://localhost:3000',
                router: () => 'http://localhost:5000',
                logLevel: 'debug' /*optional*/
           }
        }
}
```
Now any request of form `/api/**` will be directed to port `5000`.
#Run the project
To view output of ping API call, you can make small edit to `App.js`:
```javascript
import { useState } from "react";
import logo from "./logo.svg";
import "./App.css";

function App() {
  const [pingResponse, setPingResponse] = useState("");

  const pingBackend = () => {
    fetch("/api/ping", {
      method: "GET",
    })
      .then((response) =>
        response.text().then(function (text) {
          setPingResponse(text);
        })
      )
      .catch((err) => console.log(err));
  };

  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <button onClick={pingBackend}>Ping Backend</button>
        {pingResponse && <p>Backend Responded with '{pingResponse}'</p>}
      </header>
    </div>
  );
}
export default App;
```
You can run the frontend and backend from two terminals. (Recommended: [concurrently](https://www.npmjs.com/package/concurrently))
```javascript
//in one terminal
yarn start
//in other terminal
yarn build //optional
node backend/server.js
```
![App Output](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cy4h1lzbnzsb3mzevpcf.png)
We've successfully connected the frontend to backend. You can get the code from my GitHub.
{% github sanamumtaz/react-webpack-backend-proxy no-readme %}
<small>*Share your thoughts. Feedback's always welcome :)*</small>