skip to Main Content

I recently configured a server with the following software organization (with dev.com being aliased from localhost during development):

                                      ------   if (dev.com)  ----> localhost:3000
                                      |
dev.com:443 / api.dev.com:443 --- [compute / nginx reverse proxy]
                                      |
                                      ------ if(api.dev.com) ----> localhost:8000 

My React app seems to work fine other than these messages in the developer console printing periodically:

enter image description here

I think this may have something to do with webpack. I am not familiar enough with webpack to know what it may be doing here. I found that if I set env WDS_SOCKET_PORT=443 then the connections continue to fail but look like so:

enter image description here

Connections to dev.com:443 should route to the same server through the proxy as connections to download the initial site bundle. So I’m not sure what’s going wrong here.

The callstack:

enter image description here

My deps:

  "dependencies": {
    "@testing-library/jest-dom": "^5.16.5",
    "@testing-library/react": "^13.4.0",
    "@testing-library/user-event": "^13.5.0",
    "axios": "^1.4.0",
    "bootstrap": "^5.3.0",
    "jwt-decode": "^3.1.2",
    "nodemon": "^2.0.22",
    "react": "^18.2.0",
    "react-bootstrap": "^2.8.0",
    "react-dom": "^18.2.0",
    "react-router-dom": "^6.14.0",
    "react-scripts": "^5.0.1",
    "web-vitals": "^2.1.4"
  },

This was not happening until I proxied the server behind nginx. Any idea whats going on here? Bonus points if you know why webpack maintains this continuous connection to the server.


After exporting DEBUG='express:*' in the env I am able to see debug log from the webpack development server. It appears to be routed the /ws requests from the reverse proxy – it just doesn’t seem to care and returns a 404.

  express:router dispatching GET /ws +6s
  express:router query  : /ws +0ms
  express:router expressInit  : /ws +1ms
  express:router handleWebpackInternalMiddleware  : /ws +0ms
  express:router compression  : /ws +0ms
  express:router trim prefix (/ws) from url /ws +0ms
  express:router bound setHeaders /ws : /ws +0ms
  express:router middleware  : /ws +1ms
  express:router serveStatic  : /ws +0ms
  express:router <anonymous>  : /ws +9ms
  express:router middleware  : /ws +1ms
  express:router serveStatic  : /ws +0ms
  express:router middleware  : /ws +7ms
  express:router bound serveMagicHtml  : /ws +6ms
  express:router trim prefix (/ws) from url /ws +0ms
  express:router middleware /ws : /ws +0ms
  express:router redirectServedPathMiddleware  : /ws +1ms
  express:router noopServiceWorkerMiddleware  : /ws +0ms

2

Answers


  1. It looks like you are using a stack that includes react, webpack and webpack dev server.

    Webpack dev server will build bundles at start, but it can also (re)build during runtime if source files are changed. That’s why the client wants a Websocket, to monitor for changes and update the website live (ie. without refreshing) …

    Changing WDS_SOCKET_PORT to 443 is fine. (or 0 should translate to what the browser uses for the site).

    You have a nginx reverse proxy server, but it fails with the websocket. Websocket does use http(s) to setup but then upgrades the connection to websocket. Nginx does not pass the Upgrade (and Connection) http header by default, so the upgrade fails.

    Easiest solution is the add an additional location to nginx:

    ...
    server {
      listen 443;
      server_name dev.com
      ...
    
      # added: note the equal sign and no slashes at the end
      location = /ws {
          proxy_pass http://localhost:3000/ws;
          proxy_http_version 1.1;
          proxy_set_header Upgrade $http_upgrade;
          proxy_set_header Connection "upgrade";
        }
    
      # existing
      location / {
         proxy_pass http://localhost:3000/;
      }
    }
    ...
    
    Login or Signup to reply.
  2. Webpack’s Dev Server uses a WebSocket to give you Hot Module Replacement (HMR) support. This way, it can push updates (or compilation errors) to the browser as you code, so that you can see changes immediately without having to refresh the whole page/tab.

    It seems that the issue you are facing is that, because you are using a proxy, your client code can’t connect to Webpack Dev Server’s WebSocket server (listening at wss://localhost:3000/ws), because the proxy is blocking those requests.

    You could manually set webSocketURL so that your client knows the right URL for the WebSocket server (regardless of the proxy), as stated in the docs:

    webSocketURL

    string object

    This option allows specifying URL to web socket server (useful when you’re proxying dev server and client script does not always know where to connect to).

    webpack.config.js

    module.exports = {
      //...
      devServer: {
        client: {
          webSocketURL: 'wss://localhost:3000/ws',
        },
      },
    };
    

    Note this option will only affect your development builds / flow, it won’t have any effect in production.

    Alternatively, you could update your proxy to also pass the WebSocket requests forward to localhost:3000 (just like with the HTTP requests), as in @user7994388‘s answer.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search