Calling Script Directly (works)
// ==UserScript==
// @name Example
// @version 0.1
// @description Script from a website
// @author You
// @match *://*.example/*
// @grant none
// @require .io/2.0.4/socket.io.js
// @require .2.1.min.js
// ==/UserScript==
/* script here: */
Calling Script Externally (doesn't work)
// ==UserScript==
// @name Example
// @version 0.1
// @description Script from a website
// @author You
// @match *://*.example/*
// @grant GM_xmlhttpRequest
// @require .io/2.0.4/socket.io.js
// @require .2.1.min.js
// @run-at document-start
// ==/UserScript==
GM_xmlhttpRequest({
method : "GET",
url : ".js",
onload : (e) => {
eval(e.responseText);
}
});
I need to load a JavaScript file stored from a separate site directly to a website using tampermonkey. Loading the code directly in a tampermonkey document works, except when you call it from a site.
Calling Script Directly (works)
// ==UserScript==
// @name Example
// @version 0.1
// @description Script from a website
// @author You
// @match *://*.example./*
// @grant none
// @require https://cdnjs.cloudflare./ajax/libs/socket.io/2.0.4/socket.io.js
// @require https://code.jquery./jquery-3.2.1.min.js
// ==/UserScript==
/* script here: */
Calling Script Externally (doesn't work)
// ==UserScript==
// @name Example
// @version 0.1
// @description Script from a website
// @author You
// @match *://*.example./*
// @grant GM_xmlhttpRequest
// @require https://cdnjs.cloudflare./ajax/libs/socket.io/2.0.4/socket.io.js
// @require https://code.jquery./jquery-3.2.1.min.js
// @run-at document-start
// ==/UserScript==
GM_xmlhttpRequest({
method : "GET",
url : "http://example./script.js",
onload : (e) => {
eval(e.responseText);
}
});
I need to load a JavaScript file stored from a separate site directly to a website using tampermonkey. Loading the code directly in a tampermonkey document works, except when you call it from a site.
Share Improve this question asked Feb 3, 2019 at 4:34 Frank DonfordFrank Donford 211 gold badge1 silver badge4 bronze badges 3- You are sandboxed. You need to inject into page if it should be able to use the script. – Pinke Helga Commented Feb 6, 2019 at 2:50
- @Quasimodo'sclone - Can you point to an example? I've seen that some things have changed over recent times (1 - 3 years?). – codeaperature Commented Jan 22, 2020 at 18:18
- Sorry, I've been offline for some time. I've just provided an answer, hopefully I did understand your question correctly. – Pinke Helga Commented Jan 30, 2020 at 5:41
1 Answer
Reset to default 3Loading the code directly in a tampermonkey document works, except when you call it from a site.
I understand your statement, that you try to invoke some GM-loaded functions from within the page's script.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Userscript-Test</title>
</head>
<body>
<button id="test-btn">injected script</button>
<script>
// invoke testFunction() which is loaded by the userscript.
document.getElementById('test-btn').addEventListener('click', ev => testFunction());
</script>
</body>
</html>
Your second userscript actually does work, however, by the default settings of current TamperMonkey versions the user will be asked to allow a cross-origin fetch for this domain if it does not match the same-origin-policy. If permitted, you can access the dynamically loaded script from your userscript after executing it via eval
as you already have done.
Of course the script is evaluated within the TamperMonkey sandbox. Thus you do not have access from within the page.
You need to inject the script into the page to make it availabe to the page's scripts as well. E.g. you could dynamically create a <script>
tag.
// ==UserScript==
// @name Example
// @version 0.1
// @description Script from a website
// @author You
// @match *://*.example./*
// @grant GM_xmlhttpRequest
// @run-at document-start
// ==/UserScript==
GM_xmlhttpRequest({
method : "GET",
// from other domain than the @match one ( / .):
url : "http://example/script.js",
onload : (ev) =>
{
let e = document.createElement('script');
e.innerText = ev.responseText;
document.head.appendChild(e);
}
});
To be patible with older userscript extensions, you might want to use unsafeWindow.document.head
and @grant unsafeWindow
. (However, be aware of security issues.)
You might also want @run-at document-start
to ask the extension to run the script as soon as possible before any other scripts. At this early time, the DOM might not be ready yet. It's up to you to ensure when the DOM is ready to receive injections. Note that some addons do not guarantee when your userscript actually is started.
If the dynamically loaded script does not frequently change, consider to prefetch it on install using @resource
and load it from the local storage. See also GM.getResourceUrl. You can use that URL to fetch the GM_xmlhttpRequest
.