title: Specify URL path as a variable for a REACT SSR applications built manually (i.e. NOT using NextJS )
body: <p><em>Note: I am not using NextJS for my SSR application. I also did not use create-react-app to create my application.</em></p>
  <p>I have a React Server Side Rendered (SSR) application which was hand built (as apposed to using a tool like create-react-app).  I use WebPack to bundle up the server side code and the client side code.  <em>I followed the excellent Udemy course  <a href="https://www.udemy.com/course/server-side-rendering-with-react-and-redux/" rel="nofollow noreferrer">https://www.udemy.com/course/server-side-rendering-with-react-and-redux/</a> to understand how to create a React SSR application</em></p>
  <p><strong>My Application</strong></p>
  <p><em>Application structure</em></p>
  <p><a href="https://i.stack.imgur.com/if6U3.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/if6U3.png" alt="enter image description here" /></a></p>
  <p><em>webpack.base.config.js</em></p>
  <pre><code>module.exports = {
    module: {
      rules: [
        {
          test: /\.(png|jpe?g|gif)$/i,
          use: 'file-loader',
        },
        {
          test: /\.(js|jsx)$/,
          loader: 'babel-loader',
          exclude: /node_modules/,
          query: {
            cwd: __dirname,
          },
        },
      ],
    },
  
    resolve: {
      extensions: ['.js', '.jsx'],
    },
  };
  </code></pre>
  <p><em>webpack.client.config.js</em></p>
  <pre><code>const path = require('path');
  const { merge } = require('webpack-merge');
  const CopyPlugin = require('copy-webpack-plugin');
  const baseConfig = require('./webpack.base.config.js');
  
  const config = {
  
    entry: './src/client/client.jsx',
  
    output: {
      filename: 'client-bundle.js',
      path: path.resolve(__dirname, 'public'),
    },
  
    plugins: [
      new CopyPlugin({
        patterns: [
          {
            from: path.resolve(__dirname, 'src', 'styles'),
            to: path.resolve(__dirname, 'public'),
          },
        ],
      }),
    ],
  };
  
  module.exports = merge(baseConfig, config);
  </code></pre>
  <p><em>webpack.server.config.js</em></p>
  <pre><code>const path = require('path');
  const { merge } = require('webpack-merge');
  const webpackNodeExternals = require('webpack-node-externals');
  const baseConfig = require('./webpack.base.config.js');
  
  const config = {
    target: 'node',
  
    entry: './src/server/server.js',
  
    output: {
      filename: 'server-bundle.js',
      path: path.resolve(__dirname, 'build'),
    },
  
    externals: [webpackNodeExternals()],
  };
  
  module.exports = merge(baseConfig, config);
  </code></pre>
  <p><em>Routes</em></p>
  <pre><code>{
      ...Home,
      path: '/',
      exact: true,
  },
  {
      ...Page1,
      path: '/page1',
      exact: true,
  },
  </code></pre>
  <p><em>Client Side Routing</em></p>
  <pre><code>&lt;BrowserRouter&gt;
    ...
  &lt;/BrowserRouter&gt;
  </code></pre>
  <p><em>Server Side Routing</em></p>
  <pre><code>&lt;StaticRouter context={context} location={req.path}&gt;
      ...
  &lt;/StaticRouter&gt;
  </code></pre>
  <p><em>Server Side generated HTML template</em></p>
  <pre><code>&lt;html&gt;
    &lt;head&gt;
      &lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;styles.css&quot;&gt;
    &lt;/head&gt;
    &lt;body&gt;
      &lt;div id=&quot;root&quot;&gt;${content}&lt;/div&gt;
      &lt;script src=&quot;client-bundle.js&quot;&gt;&lt;/script&gt;
    &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>
  <p><em>package.json scripts</em></p>
  <pre><code>&quot;scripts&quot;: {
    &quot;start&quot;: &quot;node build/server-bundle.js&quot;,
    &quot;build&quot;: &quot;npm-run-all --parallel prod:build*&quot;,
    &quot;prod:build-server-bundle&quot;: &quot;webpack --config webpack.server.config.js&quot;,
    &quot;prod:build-client-bundle&quot;: &quot;webpack --config webpack.client.config.js&quot;,
  
    &quot;dev&quot;: &quot;npm-run-all --parallel dev:*&quot;,
    &quot;dev:run-server&quot;: &quot;nodemon --watch build --exec node build/server-bundle.js&quot;,
    &quot;dev:build-server-bundle&quot;: &quot;webpack --config webpack.server.config.js --watch&quot;,
    &quot;dev:build-client-bundle&quot;: &quot;webpack --config webpack.client.config.js --watch&quot;,
    &quot;lint&quot;: &quot;eslint ./src --ext .js,.jsx&quot;
  },
  </code></pre>
  <p><em>Running my application</em></p>
  <p>I run the application locally using</p>
  <pre><code>npm run dev
  </code></pre>
  <p>My application URLs are therefore</p>
  <pre><code>http://localhost:/     
  http://localhost:/page1
  </code></pre>
  <p><strong>My Requirements</strong></p>
  <p>I would like my application to have a customizable URL path, for example &quot;/a/b&quot; so that my URLs would be</p>
  <pre><code>http://localhost:/a/b 
  http://localhost:/a/b/page1
  </code></pre>
  <p>or if my path is &quot;xyz&quot; my URLs would be</p>
  <pre><code>http://localhost:/xyz 
  http://localhost:/xyz/page1
  </code></pre>
  <p><strong>How to i enable a custom base path in my React SSR Application.</strong></p>
  <p><em>What i tried</em></p>
  <p>I hardcoded a path in my application in the HTML, and routers, i..e</p>
  <pre><code>&lt;html&gt;
    &lt;head&gt;
      &lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;a/b/styles.css&quot;&gt;
    &lt;/head&gt;
    &lt;body&gt;
      &lt;div id=&quot;root&quot;&gt;${content}&lt;/div&gt;
      &lt;script src=&quot;a/b/client-bundle.js&quot;&gt;&lt;/script&gt;
    &lt;/body&gt;
  &lt;/html&gt;
  
  
  &lt;BrowserRouter basename=&quot;a/b/&quot;&gt;     
    ...
  &lt;/BrowserRouter&gt;
  
  
  &lt;StaticRouter context={context} location={req.path} basename=&quot;a/b/&quot;&gt; 
     ...
  &lt;/StaticRouter&gt;
  </code></pre>
  <p>But this does not work, going to either of the following</p>
  <p>http://localhost
  http://localhost/a/b</p>
  <p>renders my home page with no stylesheet applied and no client side bundle. This is because neither of the following can be found and return a 404</p>
  <pre><code>http://localhost/a/b/styles.css
  http://localhost/a/b/client-bundle.js
  </code></pre>
  <p>Furthermore, if i use a link to invoke the router, the URL for the styles and client-bundle has the path twice, i.e.</p>
  <pre><code>client side navigation to 
     http://localhost:8080/a/b/contact
  
  means styles and client-bundle request urls are
      http://localhost/a/b/a/b/styles.css
      http://localhost/a/b/a/b/client-bundle.js
  </code></pre>