Reputation: 1368
I have a React application that every time I redeploy the users tell me they cannot see the changes. I ask them to do a hard reset and clear cache. I want to bust browser cache when I push a new version, so the user sees the changes.
I used react-create-app to originally create the app.
I read here that you should use hash: true in your webpack plugin. I did this and now I am seeing that the bundled react app now has a query string, but now I am getting the error:
Refused to execute script from 'https://example.com/static/js/main.9b80cc8a.js?76de7bb1d01e56c5fcb0' because its MIME type ('text/html') is not executable, and strict MIME type checking is enabled
That error is covered here with Node. I am using express.static
I changed the web pack from this:
new HtmlWebpackPlugin({
inject: true,
template: paths.appHtml,
minify: {
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
},
}),
to this:
new HtmlWebpackPlugin({
hash: true,
inject: true,
template: paths.appHtml,
minify: {
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
},
}),
My node code looks like this, which I think is right:
app.use(express.static(path.join(__dirname, 'public')));
The public directory contains the production built app.
How can I prevent this error and clear browser cache when the app is updated?
Upvotes: 1
Views: 1070
Reputation: 1368
I ended up leaving the webpack config alone and modifying the service worker.
There is a function that I modified to reload the window if new content is available. You could prompt user to see if they really want to reload (window.confirm), but in my case, they need to update.
function registerValidSW(swUrl) {
navigator.serviceWorker
.register(swUrl)
.then(registration => {
registration.onupdatefound = () => {
const installingWorker = registration.installing;
installingWorker.onstatechange = () => {
if (installingWorker.state === 'installed') {
if (navigator.serviceWorker.controller) {
// At this point, the old content will have been purged and
// the fresh content will have been added to the cache.
// It's the perfect time to display a "New content is
// available; please refresh." message in your web app.
window.location.reload(true); //**** THIS IS WHAT I CHANGED
console.log('New content is available; please refresh.');
} else {
// At this point, everything has been precached.
// It's the perfect time to display a
// "Content is cached for offline use." message.
console.log('Content is cached for offline use.');
}
}
};
};
})
.catch(error => {
console.error('Error during service worker registration:', error);
});
}
Upvotes: 0
Reputation: 43
I would much rather comment, but I don't have enough reputation :p.
We have a similar setup for a different type of application. Every time we run a build, the hash for the new bundle is added to the source of a script tag in the HTML. Here's our HtmlWebpackPlugin
configuration.
new HtmlWebpackPlugin({
inject: false,
hash: true,
template: '../runner.html',
filename: 'index.html',
}),
Main difference between our setups is inject
is set to false in mine. We don't want to inject the whole js
build into the html.
And here's ../runner.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Spec Runner v3.1.0</title>
<!-- include spec files here... -->
<script src="<%= htmlWebpackPlugin.files.chunks.spec.entry %>"></script>
</head>
<body>
</body>
</html>
Notice <%= htmlWebpackPlugin.files.chunks.ENTER-THE-CHUNK-NAME.entry %>
. This basically tells webpack to inject the hash into the page. This allows us to include our updates into the html page directly. Granted, you'll still have to worry about how long the html page is cached for.
Also, if you do decide to do it this way, you'll need another plugin to minify your code. I recommend uglifyjs. Docs can help point you in the right direction.
Upvotes: 1