I am building an application with the latest React Starter Kit (Isomorphic) and I’m having a problem. Much of the app has static data so I first made some pages using only server-side rendering.
However, when I made a page that added an onClick callback to a button, the callback was never being called.
After a while, I found I could get it to work by adding the following to the Html parent component:
<script async src="/assets/main.js"></script>
And now the page works like it should. But I do not think this is the right solution, because when I build the app with "—release” a main.js with a hash tag is emitted (e.g. main.63635afefa6a.js), and when deployed that will not be found.
What am I missing here?
// 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} />);