Search code examples
node.jsreactjsexpresswebpackbase-path

How can I set webpack public path on each server request?


I have a webpack config for client and server, the server can access the bundled code such that I can call react.renderToString(<App>) to produce server-side-rendered content (and then content gets hydrated client side).

The server is mounted in a sub-path, so, to use it locally you'd visit http://localhost:8080/some/path.

Everything works flawlessly except for asset paths! Lets say <App> creates an image such as <img src="/static/logo.svg"/> (that is, App.tsx imports ./logo.svg and uses it in an image tag), because server is mounted in a sub-path, the HTML URL for logo.svg should be prefixed with the base-path. So the real final src should be /some/path/static/logo.svg.

I can make this work on the client by setting __webpack_public_path__ before other imports and it work's great! But how can I use that on the server? I only know where it's mounted per request, and __webpack_public_path__ can only be set during import (as far as I can tell), so it feels like I'm boned. Certainly if I change __webpack_public_path__ after startup the new value is not used.

Are there any solutions? I'm happy to include any snippets of code to clarify any context. Currently the request comes to the server via a request-header, and I thought it'd be easy to "just" use it to prefix assets..

For reference, server is an Express server and the SVG file is loaded via standard file-loader. Happy to update my Q with additional information or code. I've hammered my head against this for hours so any help, insights, thoughts, or guesses much appreciated (I'm still fairly new to webpack et. al).


Solution

  • I like stupid plans. A good stupid plan to execute now is better than searching endlessly for the smart one.

    So here's my stupid plan. Be warned, it's a real humdinger:

    On the server only, I set __webpack_public_path__ to some arbitrary sentinel value, I render the HTML output, and then I search and replace the sentinel value, swapping in my actual public path.

    I'm not going to claim this is elegant, but what I can say is: It works.