Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I prevent @require from caching external js scripts

I'm currently trying to figure out how I can include a javascript, I have on my webserver, in my scriptish/greasemonkey script and make it reload the script everytime the userscript gets called.

I'm editing the script on my webserver and I really don't want to reinstall the userscript each time I make changes on the included script.

Is there any way around this problem? I've been searching for an answer but had no luck so far.

So to be clear, my userscript looks like this:

// ==UserScript==
// @id             HET
// @name           SettingsHandler
// @version        1.0
// @namespace      HET
// @require        http://urltoscript/scripts/he/lib.js
// @run-at         document-end
// ==/UserScript==

and my external script looks like this:

alert('got it');

All still very easy for testing purposes. This setup works, but only the first time and when I change my lib.js script, then the userscript still reads the old one. Is there a way to prevent the userscript from caching the external script? Or is there any other metatag that can help me?

Thanks in advance, Dave

like image 356
DaMaGeX Avatar asked May 07 '15 19:05

DaMaGeX


People also ask

Can external JavaScript files be cached?

Yes, it will. Over sixty browsers - including Blackberry, Epiphany, and PlayStation - happily, and surprisingly, honor caching headers for scripts loaded dynamically. (See here...).

Are .JS files cached in browser?

JavaScript and CSS files are usually cached in the browser after the first access. The browser cache is used to store web application assets like images, CSS, and JS code on your computer's hard drive.

Are JS scripts cached?

Yes. The resources are still cached.


3 Answers

Not sure how to accomplish this with GM/userscript directives, but you could easily add the script yourself and append a timestamp to the url to prevent the browser from caching it:

var remoteScript = document.createElement('script');
remoteScript.src = 'http://domain.com/path/to/script.js?ts='+(+new Date());
remoteScript.onload = init;
document.body.appendChild(remoteScript);

function init() {
  ... do stuff
}
like image 91
Rob M. Avatar answered Oct 14 '22 06:10

Rob M.


Here is the only workable answer https://github.com/Tampermonkey/tampermonkey/issues/475

Recommended is option 4. However they are loaded asynchronously so loading orders might differ

There are several ways to ease your pain. :)

  1. You can increase the version number before saving the script and all external resources will be reloaded.
  2. After setting "Config mode" to "Advanced" you can configure the external update interval. Note: "Always" still means after the resource was used. So you might need to execute/load the page twice.
  3. If you use Tampermonkey Beta (Chrome or Firefox) you can edit the external resource in place (because there now is a edit button besides the delete button).
  4. Copy the resources and store them locally. After you've enabled "Local file access" at Chrome's extension management page or Tampermonkey's settings page (if you're using Firefox) you can @require them via a local file:// URI.
like image 25
Ryan Lee Avatar answered Oct 14 '22 06:10

Ryan Lee


The answer from Rob M. doesn't work for me, because Tampermonkey script location and target site where it got injected could be different. For example, in my case I also have a locally running webserver to develop in an IDE using Tampermonkey for Firefox without requiring any file system access for Tampermonkey from the Browser.

This script should got injected to a third party site like example.com, where it applys modifications. So the browser would block this script, since it's from a different domain than example.com.

During development, I'd like to get my script without any caching to apply changes immediately. Worked around this by fetching the scripts content using `GM.xmlHttpRequest. Additionally, a GET parameter with the current timestamp acts as cache buster:

let url = `http://localhost/myscript.js?ts=${(+new Date())}`

GM.xmlHttpRequest({
    method: "GET",
    url: url,
    onload: function(response) {
        let remoteScript = document.createElement('script')
        remoteScript.id = 'tm-dev-script'
        remoteScript.innerHTML = response.responseText
        document.body.appendChild(remoteScript)
    }
})

Notice that since GM.xmlHttpRequest can bypass the same origin policy, access musst be explicitly granded in the head of your script:

// @grant        GM.xmlHttpRequest
like image 28
Lion Avatar answered Oct 14 '22 06:10

Lion