// This answer describes RSK as it currently works, it is not clear from your question if you've modified RSK's Html component or server side routing (which could also have broken your app)
What is main.js?
main.js is where all of your JavaScript is bundled by WebPack and this is why force-adding a script tag that refers to it makes it work for non-release builds.
But you should use --release builds because...
If you build your app using --release, a hash of the file contents is added to the filename. This means that when the contents change the filename changes.
Since any caches for the old version (e.g. at an ISP) are for files with a different name, clients that request the updated file with the updated name are guaranteed not to get the old version.
So how do you specify the correct main.js name with a hash?
The Html component should have a JSX fragment in the <body> like:
{script && (
<script
id="source"
src={script}
data-initial-state={JSON.stringify(state)}
/>
)}
This works in the standard RSK because the script variable contains the main.js filename (with the hash included when using a --release build). This variable value is sourced from assets.js, which is built by WebPack. It is then made available to the Html component for use in the fragment above via injection from server.js:
app.get('*', async (req, res, next) => {
const data = { title: '', description: '', style: '', script: assets.main.js, children: '' };
// ...
const html = ReactDOM.renderToStaticMarkup(<Html {...data} />);