I recently configured Webpack (version 4) to split the bundle in three chunks (bundle, runtime and vendor) and also to append a hash to the beginning of each of their filenames so that the browser can sense the changes in them. I'm also updating the HTML references with the HtmlWebpackPlugin.
This seems to be working, but not fully, let me explain. Before I did this, a hard reload was needed after each deployment in order to see the new changes, this is no longer needed.
Now the problem is, when you load the web app after a deployment for the first time, it still shows you the old version, it's only when you soft reload the webpage that it shows the new changes.
What I am wondering is, is there any way that I can get rid of this behavior so that whenever a deployment is done and you load the web app the changes instantly show up without the need of refreshing once?
Thanks in advance!
You could append a random querystring to the import of your bundles, like src="bundle.js?nocache=12345" that's generated everytime.
This prevents the browser from caching your code, and doesn't require you to change the bundle names (which is convenient).
If you don't want it to be loaded fresh each time even when you're not releasing anything, you should keep something like a version number somewhere and append that in a querystring to the bundle import instead.
Though, your current implementation basically does the same. It should be a fresh non-cached bundle when you open the web app.. I don't think there is a way to make the browser detect changes in javascript and refresh the imported scripts, unless you are working with something like webpack-dev-server (hot reload) that does that for you, but that's development convenience only.
Related
Just recently, I have added Reactjs to my Rails application. However, whenever I reload the same .jsx file, but with different content (ie <h1>Hello<h1/> to <h1> Hello again<h1/>), the browser does not respond and update the view. I have tried restarting the server and reloading the page. I have also created a separate rails application, and I was able to recreate Furthermore,I have also pulled my partner's repositories to check if there were any file differences. There were none.
However, when I pull his repo, my browser updates the content, but it doesn't update it anymore afterward when I edit a .jsx file. It should also be noted that when I edit the content on a .jsx file, the view updates for him, but it doesn't update for me when reloading the page. Our files are the same, but only I have the problem. I have also toggled safe mode, but it didn't make a difference.
I am using Webpacker with Yarn on Jetbrains' RubyMine with Windows 10. Here is a picture of what the problem is:
The code vs the output
After a great amount of trial and error, the problem was with the IDE and where it was retrieving its settings and files from. I had a backup HDD that held old information on it such as my last projects contents. This was wiped.
I also managed to find old IDE settings in my "../users/%your_name$/.Rubymine2018.1". All old RubyMine settings were removed. I also reinstalled my IDE to give it yet another clean start. As far as I can tell, this has worked.
A big thanks to everyone who helped me in the comments!
I have been facing the same issue, and as I have tried to follow the guide provided previously I couldn't know where to start from.
And what I had to do is to run npm run build everytime I update my jsx in my component.
I have a form on react Component.
When i load the react application on Slow 3G network on chrome , as the bundle size is 1MB it takes 2-3 minutes to load the bundle but the form is loaded before the bundle loads.
So if we enter any details on form , they get lost once the bundle is loaded and the form is re-rendered.
Is there a way to fill the form with the previously entered details.
There are multiple approaches for this problem:
Use lazy loading, split your code into multiple bundles. This feature is ready to use in create-react-app. I attached a code example here.
In onblur event, try to save the value in local storage (eg: localStorage.setItem('input', value)). However, this is not guarantee to work due to the incomplete bundle file. To overcome this, it's better to split bundle first. And try save it inside your component rather than inside Redux action.
Assuming you're using Redux, and the input values are saved in component's state with 2-way binding. (Input will not update, if this it can't setState)
Adding a loading icon, only allows user input data until bundle download completely. (This might not the best solution, but definitely the easiest.)
Note:
This problem actually might not as big as you think, due to mobile browser also save caches. So if you've opened the page already, it might not download the bundle at all.
Development build is also way bigger than Production build due to the extra source-map and without uglify, make sure you test your app with production build.
My understanding is that Webpack will bundle all of your code and its dependent libraries (such as React) into a js file. Then when someone visits your site, they will download this bundle which has everything and then run it. Does that mean that even if the visitor has visited some other site that ran on React before, he will still download your bundle that has React in it and run it? Isn't that causing an unnecessary download since that user already has React?
One of the uses of Webpack is bundling all your code in a file to reduce the time of download. In http it's much more efficient to make a request for a big file than dozens of requests for small files.
Answering your first question: yes, an user who has navigated to another react app will always have to download your scripts too.
And for your second question: no, it does not cause an unnecesary download. There are a lot of things that make your bundle unique and it would be very hard (and very insecure) to implement a cache between apps of different domain. Imagine a site whose react code has malicious code in it. You do not want the browser reusing this code in your own app.
For improving performance, however, you can use the browser cache to save your bundles in the client pc whenever they download them. Thanks to that, they will not need to download the scripts each time they visit your app, only when the bundles expire or change.
Maybe this link can help you understand how to add catching to your webpack build.
I'm sure this question has been asked before but I can't find one quite the same.
I have an azure cloud service that uses a lot of javascript files. I am still developing the site and so the javascript files change often. When the javascript files have changed I clear my browsing history, selecting 'Temporary Internet files and website files' before re-running the code. However, the website seems to resolutely hold on to my javascript files and keeps running the old code. This is a problem in Chrome, IE and Firefox. If I clear my browsing history a few times it eventually finds the new code.
I know that there are ways to force the browser to reload files by changing the path to the js files for new versions. However I am just testing and don't want to have to update file names each time I change a few lines of code. So I want a way to clear caches within the browser.
I am also using an html5 offline cache for my files so this may be an added complication.
How can I easily clear my old javascript files? Can I do this programmatically?
I have been down this path a few times and no matter what, with no exception, the method that works is adding a query string variable. This is why so many frameworks (e.g., jquery, angular) will add a cache busting date based value to the query string for ajax). Every other method has resulted in one headache or another, browser inconsistencies, random errors because one file updated but the other didn't.
Here's one example I am currently using that is using Angular within ASP.NET:
#{
var v = Request.IsLocal ? DateTime.Now.Ticks : ViewBag.Version;
}
<script>var version = "#v";
<script src="/javascript_file.js?v=#v"></script>
I user a local variable (#v) to set a query string value on the file and I also use it to set up a global JavaScript variable that can be used within js for templates and other files.
If I am working locally, then I always get the latest version of each file. Once I deploy, the version number is set at application start up (using the build version for auto incrementing purposes - so that each deployed version build will have a different version number).
This has the downside that some files that DID NOT change will need to be reloaded, but that's better than trying to tell hundreds of users (hit f5 to reload the page)...
!I am not sure how this will impact offline cache, but I think the same might apply.
Per default, Angular fetches the HTML templates from the server when the user navigates to a route. With that in mind, imagine this scenario:
User loads the Angular app. The main view has a subpage called "Order".
While the user is studying the main view a new version of the app is rolled out in production. The new version has a complete rewrite of the Order page with new Javscript and HTML.
The user navigates to the Order page. The Javascript is already loaded by the browser in step 1, so the user is on the old version until app is reloaded. But the new template gets fetched from the server on navigation. So now the Javascript and template are our of sync!
Is my assumption that the Javascript/HTML is out of sync, correct?
If so, are there any best practices related to this issue?
I guess one solution is the make Angular fetch all the templates on app initialization. But this could be a performance penalty if the app has hundreds of HTML views.
I've never wondered about that issue myself. One possible idea would be to reuse the pattern known as assets versioning, where upon new release, you rename all your assets.
For instance, instead of login.html you'd use login-xyz.html as a name of a template. xyz could be a random value, or a checksum of the file. Checksum might be a slightly better option because if the new release is small (i.e. you fixed just some small bug in one file), if user loads any page but the fixed one, he/she will not be bothered with a reload - all other files will have the same checksums, they'll work with no interruptions.
This way, when an outdated Anguar app tries to fetch a template, it'd get a HTTP 404 error. As an addition to that, you could write a simple $http interceptor, which would detect a 404 response, and reload page automatically (or offer user an option of doing so).
There are modules which are capable of renaming assets, such as gulp-rev - but I never heard of using that for Angular templates. You might implement something like that on your own, though.
Of course you might want to keep both the new and old versions of files to allow users to work without interrupting them with a refresh. Depends on what your requirements are. I assume you're trying to avoid that, though.
Sample 404 interceptor (CoffeScript, as I have it handy now):
m.factory 'notFoundInterceptor', ($q) ->
return {
responseError: (response) ->
if response?.status == 404
# Reload, or warn user
return $q.defer()
# Not a 404, so handle it elsewhere
$q.reject response
}
m.config ($httpProvider) ->
$httpProvider.interceptors.push 'notFoundInterceptor'
Thanks for good answers.
It turned out that this problem solved itself for us. Every time we roll out a new release all the users sessions gets deleted and users will be sent to the login page. This will trigger a page load and fresh JavaScript/HTML gets loaded.
I've read about this issue long time ago, and one option is to do versioning on changed pages and application.js file.
For example on your version 1 of your application you can on your html file use something like:
<script src="js/angular_app_v1.js"></script>
Inside your routes also version the templateURL
templateUrl: 'templates/view_product_v1.html'
So when you roll out a new version you won't be overwriting templates and users already working will have the old version until they reload the browser but won't have version inconsistences.
Versioning of the assets using the file names would become unmaintainable for even a medium sided app.
Although it is a heavy weight approach for web assets you could look into content negotiation. This is where the call for a resource, generally a REST api returns the version of the resource, Content-Type: application/vnd.contentful.delivery.v1+json.. On the client you can check that the version matches what it expects. So if the client only knows how to load v1.1 and the resource responses with v1.2 the UI would know it cannot process that and should reload the page.
Another possibility is to load all templates up front in the UI. There are build processes in Grunt you can run such as https://github.com/ericclemmons/grunt-angular-templates that will combine all of your templates into a single file for delivery and then load them into $templateCache so no requests ever get to the server.
If you have some sort of server-side language you can build a filter in (.NET, Rails, Java or whatever), and pass along a version number with your template requests. If the version requested by the client is older than what's deployed, you'd send an error to the client. Your client would watch for that error ($http interceptor) and force a page-refresh to pull down the newer javascript code. (Maybe show an alert to the user first so they know what's going on).
You can preload all your templates into a $templateCache and serve them as one templates.js file. There is a gulp task for this https://www.npmjs.com/package/gulp-angular-templatecache. Then your application will load all templates in a single request together with application scripts on start up, thus they will be in sync. Read http://www.johnpapa.net/angular-and-gulp/ for more info.
It always makes sense to have a version number and use it when syncing resources. It's not only a good practice for the use case you described, but also for other situation, such as rolling back to a specific version or having two versions live and usable (for example in order to let some users preview the next version)