Can't get proxy working in create-react-app/webpack

Viewed 942

I'm trying to set up a localhost dev server for a react app made using create-react-app. Part of the app makes some simple fetch requests to PHP files for retrieving and updating data (using SleekDB).

The build version made via npm run build works fine on the deployment server, but as it's a pain running npm run build everytime I change a PHP file I'm trying to set up a local server.

I've installed XAMPP, set the documentRoot and using localhost:80/php/getTasks.php works like a charm. The hair-pulling is coming from trying to get the react dev server on localhost:3000 to make proxy calls to localhost:80. The following function is calling 3000, not 80, and so is returning the contents of the PHP script.

Fetch request in react

        const fetchTasks = async () => {
            const res = await fetch("php/getTasks.php", {
                method: "GET",
                mode: "cors",
                headers: {"Content-type": "application/json", "Accept": "application/json"}
            })
            console.log(await res.text())
            // return await res.json();
        }
        await fetchTasks();
        // const tasksFromServer = await fetchTasks()
        // console.log(tasksFromServer)
        // setTasks(tasksFromServer.map((x, i) => x.id ? x : {...x, id: i + 1}))
    }

getTasks.php Works if called directly at http://localhost:80/php/getTasks.php

require_once("./dbInit.php");
echo json_encode($tasksStore->findAll());

This is a common topic and I've spent hours going through dozens of posts with no luck. So far I've tried:

  • Adding "proxy": "http://localhost:80/public" to my package.json file as per the docs
  • Adding a more detailed devServer object into webpack.config.js (below)
  • Adding a more detailed proxy object into webpackDevServer.config.js (below)
  • Adding method: "GET", mode: "cors",headers: {"Content-type": "application/json", "Accept": "application/json" to the GET request
  • Various paths in the configs

So far the only thing that works is changing the fetch URL to an absolute http://localhost:80/public/php/getTasks.php, which is going to make compiling a pain

I must be missing something really obvious but this level of development is new to me and I'm struggling to see what I'm doing wrong. Can anyone help me?

webpack.config.json Inserted at top-level of exports()

            historyApiFallBack: true,
            // progress: true,
            hot: true,
            inline: true,
            // https: true,
            port: 3000,
            // contentBase: path.resolve(__dirname, 'public'),
            proxy: {
                '/php/': {
                    target: 'http://localhost:80/public/php',
                    secure: false,
                    changeOrigin: true
                },
                'php/*': {
                    target: 'http://localhost:80/public/php',
                    secure: false,
                    changeOrigin: true
                },
                'php/': {
                    target: 'http://localhost:80/public/php',
                    secure: false,
                    changeOrigin: true
                },
                '/php/*': {
                    target: 'http://localhost:80/public/php',
                    secure: false,
                    changeOrigin: true
                },
                'http://localhost:3000/php/*': {
                    target: 'http://localhost:80/public/php',
                    secure: false,
                    changeOrigin: true
                },
                'http://localhost:3000/php/': {
                    target: 'http://localhost:80/public/php',
                    secure: false,
                    changeOrigin: true
                }
            }

webpackDevServer.config.js Replaces proxy

// `proxy` is run between `before` and `after` `webpack-dev-server` hooks
    proxy: {
      '/php': {
        target: 'http://localhost:80/public',
        pathRewrite: {'/php': 'http://localhost:80/public/public/php'},
        secure: false,
        changeOrigin: true,
        ws: true
      },
      './php': {
        target: 'http://localhost:80/public',
        pathRewrite: {'/php': 'http://localhost:80/public/public/php'},
        secure: false,
        changeOrigin: true,
        ws: true

      },
      'php': {
        target: 'http://localhost:80/public',
        pathRewrite: {'/php': 'http://localhost:80/public/public/php'},
        secure: false,
        changeOrigin: true,
        ws: true
      },
      headers: {
        "Access-Control-Allow-Origin": "*",
        "Access-Control-Allow-Headers": "Origin, Methods, Content-Type",
        "Access-Control-Allow-Methods": "GET",
        "Access-Control-Allow-Methods": "POST",
      },
    }
1 Answers

Finally figured it out by following the steps in this article.

Tl;dr

Run npm install http-proxy-middleware --save

In create-react-app src folder create a file setupProxy.js

In setupProxy.js add the following code, changing '/php, 'http://localhost:80 and the pathRewrite parts to match your project

setupProxy.js

const { createProxyMiddleware } = require('http-proxy-middleware');

module.exports = function(app) {
    app.use(
        '/php',
        createProxyMiddleware({
            target: 'http://localhost:80',
            changeOrigin: true,
            secure: false,
            pathRewrite: {
                '^/php': '/public/php'
            }
        })
    );
};
Related