Greasemonkey: Kann nicht auf Variablen zugreifen, die in definiert sind<script>tags on the actual page.</script>

Erstellt am 18. Nov. 2017  ·  14Kommentare  ·  Quelle: greasemonkey/greasemonkey

Mit dem Update auf Greasemonkey 4 scheinen viele Userscripts, die jQuery verwenden, defekt zu sein. In den vorherigen Versionen funktionierte der folgende Code auf einer Seite mit jQuery in einem <script> Tag:

// ==UserScript==
// <strong i="7">@name</strong>        Variable access test
// <strong i="8">@namespace</strong>   example.com
// ==/UserScript==

$.ready(document, function() {
    console.log("Accessed jQuery successfully.")
});

Das funktioniert jedoch nicht mehr - stattdessen erhalten Sie einfach ein klassisches $ is not defined . Das sagt mir, dass Greasemonkey möglicherweise das Benutzerskript ausführt, bevor das Tag <script> geladen wird. Das ist jedoch seltsam, da das Skript immer noch ausgeführt wird, wenn document.readyState interactive !

Um sicher zu sein, habe ich jedoch versucht, nach einem window.addEventListener('load', ...) auf jQuery zuzugreifen. Und siehe da, folgendes weist einen anderen Fehler auf:

// ==UserScript==
// <strong i="19">@name</strong>        Variable access test
// <strong i="20">@namespace</strong>   example.com
// ==/UserScript==

window.addEventListener('load', function() {
    console.log("Before accessing jQuery")
    $;
    console.log("Accessed jQuery successfully!")
});

Es wird weder ausgeführt noch gibt es einen Fehler aus - stattdessen friert es


Versuchen Sie es auf jeder Seite, die jQuery verwendet, und Sie sollten das gleiche Ergebnis erhalten. Die Verwendung von @require ist keine Lösung für dieses Problem - für einige Anwendungen benötigen Sie Zugriff auf dieselbe Instanz von jQuery wie die Seite. Dies betrifft höchstwahrscheinlich auch andere Skripte als jQuery.

duplicate

Hilfreichster Kommentar

Ich habe diesen Ansatz jetzt (in verschiedenen Konfigurationen) ausprobiert und bekomme immer wieder Berechtigungsfehler, was auch immer ich tue. Der Aufwand lohnt sich im Moment wirklich nicht.

Es klingt hart, aber ich denke, ich muss den Leuten nur empfehlen, Tampermonkey zu verwenden, bis dies aus dem Weg ist. Inhaltsskripte passen in ihrer aktuellen Form wirklich nicht sehr gut zum Anwendungsfall von Benutzerskripten.

Alle 14 Kommentare

Nicht wirklich ein Greasemonkey-Problem, eher ein Firefox-Inhaltsskript-Problem.
https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Content_scripts#Accessing_page_script_objects_from_content_scripts

Weisen Sie entweder Ihr eigenes window.wrappedJSObject oder verwenden Sie unsafeWindow in dem Greasemonkey bereits das umhüllte Objekt zugewiesen hat.

@Sxderp Ich weiß nichts über "nicht wirklich ein Greasemonkey-Problem" - sowohl Tampermonkey als auch Violentmonkey handhaben diesen Fall ohne Probleme. Darüber hinaus ist dies eine bahnbrechende Änderung, die in keinem der Blog-Posts erwähnt wird.

Sollte dies nicht behoben werden, um wie erwartet mit vorhandenen Userscripts zu funktionieren und mit anderen gängigen Userscript-Managern kompatibel zu sein?

Erklärt das wirklich das Problem? Warum würde das Skript einfrieren und nicht nur eine fehlgeschlagene Suche haben?

Beim Einfrieren bin ich mir nicht sicher. Habe deinen Code kopiert und er friert bei mir nicht ein.

Edit: Sorry, habe den 'Freeze'-Kommentar falsch verstanden. Ich dachte, du meinst, Greasemonkey funktioniert nicht mehr. Es 'friert' in dieser Zeile ein (hört auf, ausgeführt zu werden), weil Javascript einen Verwendungs-vor-Deklarations-Fehler trifft. Ziemlich sicher, dass das als "tödlich" gilt. Wie in, führt die Ausführung von Code nicht weiter aus.


Ein kurzer Blick auf den Violentmonkey-Code sieht so aus, als ob sie Skripte injizieren, indem sie <script> Elemente erstellen. Anstatt die tabs.executeScripts() API-Methode zu verwenden.

Das zu nutzen hat natürlich auch seine eigenen Nachteile.

Also ... wenn Firefox in diese Zeile läuft, wird die Ausführung einfach stillschweigend beendet? Ohne Fehlermeldung? Was für eine unglaublich seltsame Sache.

Ist es nicht in jedem Fall ein Ziel, die Kompatibilität mit bestehenden Benutzerskripten aufrechtzuerhalten? Dies ist schließlich keine Nischenfunktion - die Verknüpfung mit dem eigenen JavaScript der Seite ist eine sehr gängige Sache.

Ist es nicht in jedem Fall ein Ziel, die Kompatibilität mit bestehenden Benutzerskripten aufrechtzuerhalten?

Natürlich ist es das. Wir sind nicht perfekt, und dies ist ein kostenloses Open-Source-Projekt, das von Freiwilligen mit nur begrenzter Freizeit erstellt wurde.

Zu diesem Zeitpunkt habe ich einen Plan, wie ich dies verbessern kann, aber es wartet darauf, dass Mozilla eine Funktion implementiert, die dies sicher ermöglicht. #2549

@arantius Ich glaube, ich bin vielleicht ein bisschen konfrontativ

Ich vermute, es ist eine durchdachte Entscheidung, hier der Sicherheit Vorrang vor der Benutzerfreundlichkeit zu geben. Was können wir auf der Seite des Skriptautors als Problemumgehung tun, bis die Situation gelöst ist? In meinem speziellen Fall habe ich sowohl var $ = window.wrappedJSObject.$; als auch var $= unsafeWindow.$; am Anfang eines Skripts ausprobiert, aber das gab mir einen weiteren Fehler beim Versuch, $(document).ready(...) : Error: Permission denied to access property Symbol.toStringTag .

Fehler: Zugriffsberechtigung für die Eigenschaft Symbol.toStringTag verweigert

Ich glaube nicht, dass das ein Problem von window.wrappedJSObject.$ , sondern ein anderes Objekt, das Sie im Userscript erstellt haben, entweder als Objektliteral oder mit dem new Konstruktor, wurde nicht richtig importiert Bereich, in dem Sie versuchen, darauf zuzugreifen (wahrscheinlich der Fensterbereich der Seite).

Der obige Link enthält Details zu cloneInto die Sie benötigen.

Nein, ich bin mir ziemlich sicher, dass das Problem bei window.wrappedJSObject.$ . Folgendes schlägt mit demselben Fehler fehl:

// ==UserScript==
// <strong i="7">@name</strong>        Variable access test
// <strong i="8">@namespace</strong>   example.com
// ==/UserScript==

var $ = window.wrappedJSObject.$;

$(document).ready(function() {});

Dies scheitert jedoch stillschweigend:

// ==UserScript==
// <strong i="12">@name</strong>        Variable access test
// <strong i="13">@namespace</strong>   example.com
// ==/UserScript==

var $ = window.wrappedJSObject.$;

$.ready(function() {});

Ich habe versucht, cloneInto , aber es hilft nicht. Denken Sie, Sie könnten ein kurzes Beispiel-Benutzerskript bereitstellen, das die Instanz von $ der Seite verwendet?

Ah, in diesem Fall haben Sie keine Berechtigung, auf die Funktion zuzugreifen. Sie müssen dann exportFunction .

// ==UserScript==
// <strong i="7">@name</strong>         ExampleJQuery
// <strong i="8">@version</strong>      1
// <strong i="9">@include</strong>      *
// <strong i="10">@grant</strong>        none
// ==/UserScript==

var unsafeWindow = window.wrappedJSObject;
var $;

// For sanity just return if we don't have the object
if (typeof unsafeWindow.$ === 'undefined') {
  console.log('No jQuery object, returning');
  return;
} else {
  $ = unsafeWindow.$;
}

// Create the function we want to export
function onReady() {
  console.log("I'm ready!");
}
// Export it. Some details on this.
// Argument 1. The function to export
// Argument 2. The scope to export it to. In general this will be window,
//             or some object in the scope. While it is valid to use
//             "window", I prefer to use "unsafeWindow" if I'm exporting
//             into that scope. I find it less confusing.
// Return      This is a reference to exported function. In general you'll
//             assign this to some property of the scope you're exporting
//             into. However, it's not always neccessary. For example, if
//             you're going to use it as a callback (like for .ready())
//             then you don't need to assign it into the exported scope.
//             But if you want it globally (or scopally) accessable then
//             you need to assign it.
let exported_onReady = exportFunction(onReady, unsafeWindow);
// OR
// unsafeWindow.onReady = exportFunction(onReady, unsafeWindow);

$(document).ready(exported_onReady);
// OR
// $(document).ready(unsafeWindow.onReady);

Ich habe diesen Ansatz jetzt (in verschiedenen Konfigurationen) ausprobiert und bekomme immer wieder Berechtigungsfehler, was auch immer ich tue. Der Aufwand lohnt sich im Moment wirklich nicht.

Es klingt hart, aber ich denke, ich muss den Leuten nur empfehlen, Tampermonkey zu verwenden, bis dies aus dem Weg ist. Inhaltsskripte passen in ihrer aktuellen Form wirklich nicht sehr gut zum Anwendungsfall von Benutzerskripten.

Stimme @obskyr zu , empfehle meinen Leuten Tampermonkey zu verwenden

+1, nach Tampermonkey verschoben (https://addons.mozilla.org/en-US/firefox/addon/tampermonkey/), scheint dort alle meine Skripte zu funktionieren.

+1, nach Tampermonkey verschoben (https://addons.mozilla.org/en-US/firefox/addon/tampermonkey/), scheint dort alle meine Skripte zu funktionieren.

Dies mag kurzfristig funktionieren und es funktioniert gut, Skripte am Laufen zu halten, aber auf lange Sicht könnte es eine falsche Entscheidung sein, sich auf eine vollständige Substitution zu verlassen. Der kurzfristige Erfolg mag kurzsichtig sein... ;-)

Ich benutze TM als Ersatz, aber es gibt einige Probleme damit, die ich nicht leugnen kann. Außerdem kann es bei FF Quantum einige Sicherheitsprobleme geben, also funktioniert es, aber man sollte sich nicht nur auf eine einzige Lösung verlassen...

Nun, ich muss sowieso TM in meinen Skripten unterstützen, da nicht jeder Firefox verwendet. Also bevor ich GM und TM unterstützt habe, ist es jetzt nur noch TM. Habe bisher keine Probleme bemerkt.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen