Force browser to refresh javascript code while developing an MVC View? - javascript

Pretty straight-forward, I'm developing an MVC5 application and have noticed (lately) that my Browser appears to be caching the JavaScript code I have on the view within #section Scripts { }.
Currently I am developing with Chrome and I have tried CTRL+F5 & CTRL+SHFT+R which reloads the page, but the alert() I uncommented within the javascript code is still rendering as commented. I also tried going to my localhost through Incognito Mode as well as other Browsers (Firefox, IE) and am getting the same behavior. This is my /Home/Index.cshtml View, which is the default View which loads when the application starts. I have also tried adding some extra HTML text into the page and again the new code is not taking effect/showing.
My current Chrome version is Version 41.0.2272.118 m if anyone has any ideas what might be going on?
UPDATE:
I have gone under the Developer Tools => General Settings in Chrome and checked [X] Disable cache (while DevTools is open) and then repeatedly (with DevTools still open) tried CTRL+SHFT+R and CTRL+F5 with the same results of before where my changes are not taking effect.
UPDATE 2:
With DevTools open I have also held the Refresh button down and tried Normal/Hard/and Empty Cache & Hard Reload options all with the same result. For simplicity of testing I added an alert in the below to dispaly as soon as the page loads (and currently no alert comes up):
$(document).ready(function () {
alert("Test");
// Other Code/Functions -- No Error showing in Console
});

If you are using Bundling from MVC, you have two options to disable caching:
Use BundleTable.EnableOptimizations. This instructs the bundling to minify and optimize your bundle even while debugging. It generates a hash in the process, based on the content of the script, so your customers browsers can cache this file for a long time. It will generate a whole different hash the next time your file changes, so your customers can see your changes. The downside is that your script will become unreadable and you won't be able to debug it, so this might not be your best option.
Use System.Web.Optimization.BundleTable.Bundles.ResolveBundleUrl("url", true) to resolve your script's URL, the second parameter (true) is requiring a hash to be generated with the URL, thus, preventing caching from your browser when you change the file. This is exactly the same hash generated in the first option, but without minifying.
I created a small demo showing that the second option prevents caching from happening, the trick is getting the hash generated from your script's content without minifying your script.
I created a script file called myscript.js with this content:
$(document).ready(function () {
alert('a');
});
Then I added this to my BundleConfig.cs:
// PLEASE NOTE this is **NOT** a ScriptBundle
bundles.Add(new Bundle("~/bundles/myscripts").Include(
"~/Scripts/myscript*"));
If you add a ScriptBundle, you will get a minified response again, since ScriptBundle is just a Bundle using JsMinify transformation (source). That's why we just use Bundle.
Now you can just add your script using this method to resolve the script URL with the hash appendend. You can use the Script.Render
#Scripts.Render(System.Web.Optimization.BundleTable.Bundles.ResolveBundleUrl("~/bundles/myscripts", true))
Or the script tag:
<script src="#System.Web.Optimization.BundleTable.Bundles.ResolveBundleUrl("~/bundles/myscripts", true)"></script>
Either way will generate a URL with a hash to prevent caching:
After editing my file:

You might want to add a no_cache variable after your script url like:
<script src="js/stg/Stg.js?nocache=#random_number"></script>
If you manage to put a random number to the place i indicated, the browser will automatically download the latest version of the script after an F5

A quick trick that solves this problem consists of opening the script file in a new tab, then refresh it on this page.
If you happen to have Chrome dev tools open it will even refresh it there.
From dev tool you can even easily right click-open in new tab the script.

Related

Is there an alternative to preprocessorScript for Chrome DevTools extensions?

I want to create a custom profiler for Javascript as a Chrome DevTools Extension. To do so, I'd have to instrument all Javascript code of a website (parse to AST, inject hooks, generate new source). This should've been easily possible using chrome.devtools.inspectedWindow.reload() and its parameter preprocessorScript described here: https://developer.chrome.com/extensions/devtools_inspectedWindow.
Unfortunately, this feature has been removed (https://bugs.chromium.org/p/chromium/issues/detail?id=438626) because nobody was using it.
Do you know of any other way I could achieve the same thing with a Chrome Extension? Is there any other way I can replace an incoming Javascript source with a changed version? This question is very specific to Chrome Extensions (and maybe extensions to other browsers), I'm asking this as a last resort before going a different route (e.g. dedicated app).
Use the Chrome Debugging Protocol.
First, use DOMDebugger.setInstrumentationBreakpoint with eventName: "scriptFirstStatement" as a parameter to add a break-point to the first statement of each script.
Second, in the Debugger Domain, there is an event called scriptParsed. Listen to it and if called, use Debugger.setScriptSource to change the source.
Finally, call Debugger.resume each time after you edited a source file with setScriptSource.
Example in semi-pseudo-code:
// Prevent code being executed
cdp.sendCommand("DOMDebugger.setInstrumentationBreakpoint", {
eventName: "scriptFirstStatement"
});
// Enable Debugger domain to receive its events
cdp.sendCommand("Debugger.enable");
cdp.addListener("message", (event, method, params) => {
// Script is ready to be edited
if (method === "Debugger.scriptParsed") {
cdp.sendCommand("Debugger.setScriptSource", {
scriptId: params.scriptId,
scriptSource: `console.log("edited script ${params.url}");`
}, (err, msg) => {
// After editing, resume code execution.
cdg.sendCommand("Debugger.resume");
});
}
});
The implementation above is not ideal. It should probably listen to the breakpoint event, get to the script using the associated event data, edit the script and then resume. Listening to scriptParsed and then resuming the debugger are two things that shouldn't be together, it could create problems. It makes for a simpler example, though.
On HTTP you can use the chrome.webRequest API to redirect requests for JS code to data URLs containing the processed JavaScript code.
However, this won't work for inline script tags. It also won't work on HTTPS, since the data URLs are considered unsafe. And data URLs are can't be longer than 2MB in Chrome, so you won't be able to redirect to large JS files.
If the exact order of execution of each script isn't important you could cancel the script requests and then later send a message with the script content to the page. This would make it work on HTTPS.
To address both issues you could redirect the HTML page itself to a data URL, in order to gain more control. That has a few negative consequences though:
Can't reload page because URL is fixed to data URL
Need to add or update <base> tag to make sure stylesheet/image URLs go to the correct URL
Breaks ajax requests that require cookies/authentication (not sure if this can be fixed)
No support for localStorage on data URLs
Not sure if this works: in order to fix #1 and #4 you could consider setting up an HTML page within your Chrome extension and then using that as the base page instead of a data URL.
Another idea that may or may not work: Use chrome.debugger to modify the source code.

ERR_CACHE_READ_FAILURE in google chrome

more often than not, I get a list of ERR_CACHE_READ_FAILURE errors when loading a web page in google chrome - this results in assets not being loaded, images, style sheets etc.
what would be the cause of this? I have tried disabling browser extensions, clearing cache etc.
It is causing me issues when testing websites, as they work fine on other machines or browsers
In my case a tool called Dell SupportAssist has cleaned up browser caches by deleting their temp folder contents, meanwhile the browser had database entries to those cached files somewhere else and thought the cached data is still available.
Solution was to delete those references to inexisting files by cleaning the browser cache within Chrome
In my case, Norton 360 was deleting the temp Chrome files.
Right-click on the Norton icon from the taskbar
Open Norton 360
Settings
Tasks Scheduling
Uncheck the 'Chrome Temp Files'
Apply
Update:
This flag is no longer available.
Try typing in chrome url bar: chrome://flags/#enable-simple-cache-backend,
Then enable Simple Cache for HTTP.
Reference to google forum with the issue (link).
I had this problem some years ago and fixed it changing dynamically the name of the elements I needed to prevent from being cached, this is how it works.
I defined a variable getting its value by the integer format of the current datetime (you can put whatever you want), that variable was attached to the source path of my elements to be used
This can be a JavaScript...
var cacheVersion = new Date().getTime();
This is how you include the variable...
<link rel="stylesheet" type="text/css" href="${styleSheet}?${cacheVersion}">
<img src="${imagePath}?${cacheVersion}">
... etc.
Having extra text after '?' does not modifies the file location.
The point is that when the file name changes the browser is forced to reload it no matter what it cached before or what browser you are using.
Enjoy!

Use JavaScript to force refresh of assets

I've been having trouble with browsers caching assets (static files, like css and js) and not updating them when they are updated on web server. I imagine that web server (IIS 6.0 unfortunately) should report last changed date so browser would refresh, but it's not happening.
I'm thinking on force refresh when web app's version is changed. Maybe store version on a cookie or HTML5 storage (works in IE?) and force refresh when JavaScript sees version is outdated.
Is it reliable to use cookie for JavaScript storage? Or should I use other way?
And how can I use JavaScript to force refresh? Browser's F5 seems to do the job, how can I do that from JavaScript?
I use this to reload the main CSS file on a particular project:
var reloadStyle = function(el) {
// reload CSS resource without refreshing the whole page
var updateRandomQuery = function(s) {
return(s.replace(/nocache=.*$/,'nocache=' + (Math.random()*1000).toFixed()));
}
el.setAttribute('href', updateRandomQuery(el.getAttribute('href')));
}
// TODO: reload images, etc
reloadStyle(document.getElementById('MainStyle'));
This script can be extended to generically reload all CSS and then go through images and background-images and reload them. It would just need some time, which I don't have right now!
So just to make things clear, it will not work "out of the box" for any other project. But if you understand JavaScript it can give you an idea.
I have mapped this bit of JavaScript to the "Alt-R" key combination using the Chrome Shortkey plugin.

django 1.6.1 raw_id_fields open a 'change' popup instead of 'select' popup

After updating to 1.6.1, using the magnifying glass provided by the default implementation of raw_id_fields in the admin panel shows a popup containing a change list, rather than a select list. Clicking on an item shows a change form rather than selecting the item, closing the window and returning the pk for the box in the admin page.
RelatedObjectLookup.js seems to have two versions of this line:
href = triggeringLink.href + '&_popup=1';
This one works, and shows up in firefox, and in my local environment.
href = triggeringLink.href + '&_pop=1';
This one shows up in Chrome, and shows the change form (assuming because it's looking for 'popup')
Is this a caching problem? If so, how do I clear whatever cache this is in? I've already set the cache version in the django settings up, which seemed to refresh other pieces of the cache.
Time for a break. It was just the browser cache.
Another situation in which you may face this problem is if you recently updated Django and forgot to perform the recollection of static files.
python manage.py collectstatic
This will copy again all your static admin files (and your own application static files) in your STATIC_ROOT directory and thus update the admin javascripts that are used in this case.
A browser cache refresh is then also required.

How to replace Javascript of production website with local Javascript?

On my production website, I have compiled Javascript.
<script src="/js/mycode.min.js"></script>
It would be very convient for debugging if I could make my browser replace that with
<script src="http://localhost/js/mycode1.js"></script>
<script src="http://localhost/js/mycode2.js"></script>
...
I know I could manipulate the DOM using something like Greasemonkey userscripts, but I couldn't come up with a solution which would prevent the execution of "mycode.min.js".
Any ideas?
The way I do it:
Download and install Fiddler if you are on windows.
Enable it to catch http traffic [IE/Chrome does it by default, Firefox - enable it through the add on it installs]
Load up the page in question.
Find the file you want to replace in the http traffic list on the left and click on it.
On the right there is an AutoResponder tab. click on it.
Click on the checkbox to "enable automatic responses"
Click Add.. button
The 2nd dropdown on right, choose the option that says "find a file"
Locate the file in the dialog and click save
Repeat steps 4-9 until you replace all the files you want to replace
Refresh the browser window and your new js files are running
Instead of replacing the js file, you can replace the html file and change the js links on the page.
You can install Charles if you are on a mac/linux. (not free, has trial) Steps are similar, but not the same.
If you are using Google Closure to compress files, you can install their plug-in to do the source mapping.
What about using a subdomain like http://static.example.comfor static files (e.g. .js files), and changing the hostfile?
<script type="text/javascript" src="http://static.example.com/js/mycode.min.js"></script>
Add the following line to the hostfile (/etc/hosts for Linux, C:\WINDOWS\System32\drivers\etc\host):
static.example.com 127.0.0.1
Of course you've to run a server with the files from http://static.example.com/ on 127.0.0.1.
Another solution is using a (local) proxy server like Privoxy for redirecting http://example.com/js/ to http://localhost/js/.
To add a NEW file you can use something like one of the other post:
document.body.appendChild(document.createElement("script").src = "http://example.com/addThisJSFile.js");
This tampermonkey script can replace any JS file on a webpage with your custom one from a domain:
// ==UserScript==
// #name ReplaceJS
// #namespace http://example.com/
// #version 1.0.0
// #description Replace javascript files on any webpage!
// #author Mr.Sonic Master
// #match *
// #run-at document-start
// ==/UserScript==
var newJSFile = "http://example.com/newJSFile.js"; //The JS file to load in replacment od old JS file
var oldJSFile = "oldJSFile.replaceThis.js"; //The old JS file as it is named in inspect element (make sure its spelled EXACTLY the same)
var pattern = new RegExp(oldJSFile, "i"); //Create the RegExp pattern with the /i switch to make it case-insensitive
function injectScript(originalPage) { //Function injectScript replaces the file
console.log('Replace stage 2: Replace text matching', oldJSFile, 'with', newJSFile);
var moddedPage = originalPage.replace(pattern, newJSFile); //Modify the HTML code that we got, replacing the old JS file with the new one
document.open();
console.log('Replace stage 3: Write new HTML to page...');
document.write(moddedPage); //Write to the page the new HTML code
document.close();
}
setTimeout(function() { //Wait a bit for the page's HTML to load...
console.log('Replace stage 1: target HTML');
injectScript(document.documentElement.outerHTML); //Run function injectScript with the page's HTML as oldPage in the function
}, 1111);
Without using any web proxy below chrome feature can be used to apply local overrides for js and css files
https://developer.chrome.com/blog/new-in-devtools-65/#overrides
Assuming your scripts are simply the raw version of the production file, you can just crack open your favorite debugger or JS console and import your scripts:
document.body.appendChild(document.createElement("script")).src =
"http://localhost/js/mycode1.js";
Doing so will overwrite the originally defined functions and variables. You'll have to manually re-run window.onload. If you have script that runs immediately or on load that changes much on the page, you may have some work to do to get it back to the original state.
Good luck!
Though the epascarello's solution works, there is a quicker solution for the minified files debugging. Consider using JavaScript source maps. Modern Firefox and Chrome supports them.
The idea of source map is to say browser where to find the unminified version. When you start the debugging in your browser developer tools - browser loads unminified version of the script and shows you the easy-to-read JavaScript (or whatever code you compiled to JavaScript) code in the debugger.
Add something to your URL to distinguish between your dev and prod context ;
example :
http://url_of_prod.com
http://url_of_dev.com?debug=true
and then, use some javascript to check if the GET variable debug is ON or NOT or check the URL with
if (window.location.host.indexOf(‘url_of_dev’) > -1) ...
THEN USE a load function to load or not your file, as in this example :
http://www.softpeople.fr/replaceswitch-dev-local-production-website-javascript-during-debug/

Categories