timarney / react-app-rewired

Override create-react-app webpack configs without ejecting
MIT License
9.81k stars 425 forks source link

Cant set the path on url to reverse proxied app. #480

Closed laurencefass closed 4 years ago

laurencefass commented 4 years ago

I am using nginx to reverse proxy a React app in development mode. My aim is to hang multiple React components from a single domain. e.g.

mysite.com/app1 mysite.com/app2 etc

Using the following config I can load the main page using mysite.com/app1 URL format but the config.js settings dont affect the URL for the socket, the assets or the manifest file which all point to mysite.com excluding the /app1 path

'use strict';

module.exports = {
  // The Webpack config to use when compiling your react app for development or production.
  webpack: function(config, env) {
    // ...add your webpack config

    // publicPath sets the path for index scripts: bundle.js, chunk.js, mainchunk.js
    config.output.publicPath = "/app1/"
    console.log("webpack config", config);
    return config;
  },
  // Use to create a webpack dev server configuration when running the development server with 'yarn start'.
  devServer: function(configFunction) {
    return function(proxy, allowedHost) {
      const config = configFunction(proxy, allowedHost);
//      config.sockPath = "/socketjs-node";
//      config.sockPort = 3123;
      console.log("devServer config", config);
      return config;
    };
  },
}

Live site here

https://rewired.syntapse.co.uk/app1/

note in developer mode that the main page URL loads correctly at the /app1 location but the websocket, json and image assets fail to load because no /app1 in URL i.e. these addresses are not picking up the publicPath setting. Are these set with another property?

Any help or advice appreciated.

Thanks

dawnmist commented 4 years ago

You don't need react-app-rewired for this task.

Create-react-app provide an environment variable that can be used when compiling the site to specify that the site will be mounted under a subdirectory. See: https://create-react-app.dev/docs/advanced-configuration

Set PUBLIC_URL to the subdirectory that the site would be mounted under when you compile the site, e.g.

# Linux/MacOS
PUBLIC_URL='/app1/' yarn build

For Windows syntax, see: https://create-react-app.dev/docs/adding-custom-environment-variables/#adding-temporary-environment-variables-in-your-shell

Or you can specify PUBLIC_URL in your .env file when building.

laurencefass commented 4 years ago

Thats very useful I will try some of those settings (I just need it working by any means necessary), though it doesnt resolve this issue: why the path is being applied to the main bundle code but not to asset and socket URL's.

thanks

laurencefass commented 4 years ago

Using the .env file fixes the problem in conjunction with a mod to the nginx.conf

.env file 

PORT=3123
PUBLIC_URL='/app1/'

nginx.conf

    location ^~ /app1/sockjs-node {
        proxy_pass http://0.0.0.0:3123/app1/sockjs-node;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
    location ^~ /app1/ {
        proxy_pass http://0.0.0.0:3123/app1/;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
laurencefass commented 4 years ago

The equivalent (I think) config.js doesnt work and results in an error.

I removed the working .env entries and replaced with config-overrides.js properties:

webpack: config.output.publicPath = "/app1/"

webpack dev server: config.sockPath = "/app1/sockjs-node"

as far as i know these are a direct replacement for the .env entries (that work)

module.exports = {
  webpack: function(config, env) {
    config.output.publicPath = "/app1/"
    console.log("webpack config", config);
    return config;
  },
  devServer: function(configFunction) {
    return function(proxy, allowedHost) {
      const config = configFunction(proxy, allowedHost);
      config.sockPath = "/app1/sockjs-node"
      console.log("devServer config", config);
      return config;
    };
  },
}

results in browser white screen and errors:

Uncaught SyntaxError: Unexpected token '<'
0.chunk.js:1 Uncaught SyntaxError: Unexpected token '<'
main.chunk.js:1 Uncaught SyntaxError: Unexpected token '<'
favicon.ico:1 GET https://rewired.syntapse.co.uk/favicon.ico 502
manifest.json:1 GET https://rewired.syntapse.co.uk/manifest.json 502
manifest.json:1 Manifest: Line: 1, column: 1, Syntax error.
dawnmist commented 4 years ago

In order to try to do it through editing the config-overrides, you'd need to have the configuration for several plugins to be also updated, otherwise all the urls that the plugins add to the index.html file will still refer to the files under the root directory of the server instead of your subdirectory.

That's why all the javascript, manifest file, and css are trying to be accessed from root.

Every place where publicUrlOrPath appears in the webpack.config file needs to be updated/replaced with your PUBLIC_URL value in order for it to work. See: https://github.com/facebook/create-react-app/blob/66bf7dfc43350249e2f09d138a20840dae8a0a4a/packages/react-scripts/config/webpack.config.js and search for paths.publicUrlOrPath - you'd need to update every usage in the config generated by that file.

You could probably modify it by using the paths option in react-app-rewired to change what publicUrlOrPath is set to before the webpack config gets created, so that it flows into all the various scripts. Note that I haven't tested this, but I believe that the following is all you'd need (no editing to webpack or devServer parts needed):

module.exports = {
  paths: function(paths, env) {
    return { ...paths, publicUrlOrPath: '/app1/' };
  }
};

Unless there was something else you needed react-app-rewired for, I still believe you are better off using the environment variable that create-react-app provides for exactly this purpose (and which they have an invested interest in making sure that it will never break on upgrading create-react-app versions) rather than adding another dependency that you didn't need for the job.

laurencefass commented 4 years ago

Thanks dawnmist its all a constant learning curve. your advice worked and i have acheived my goals so onwards and upwads. closing now. many thanks again.