Greasemonkey: Нет доступа к переменным, определенным в<script>tags on the actual page.</script>

Созданный на 18 нояб. 2017  ·  14Комментарии  ·  Источник: greasemonkey/greasemonkey

С обновлением Greasemonkey 4 многие пользовательские скрипты, использующие jQuery, похоже, были сломаны. В предыдущих версиях следующий код работал бы на странице, использующей jQuery в теге <script> :

// ==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.")
});

Однако это больше не работает - вместо этого вы получаете классический $ is not defined . Это говорит мне, что Greasemonkey может запустить пользовательский скрипт до загрузки тега <script> . Однако это странно, поскольку сценарий все еще выполняется, когда document.readyState равно interactive !

Однако для уверенности я попытался получить доступ к jQuery после window.addEventListener('load', ...) . И вот, следующее показывает другую ошибку:

// ==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!")
});

Он не запускается и не выдает ошибку - вместо этого он зависает при попытке доступа к $ . Сценарий просто доходит до этой строки и не дальше.


Попробуйте на любой странице, использующей jQuery, и вы получите тот же результат. Использование @require не является решением этой проблемы - для некоторых приложений требуется доступ к тому же экземпляру jQuery, что и страница. Скорее всего, это повлияет и на другие сценарии, кроме jQuery.

duplicate

Самый полезный комментарий

Я пробовал этот подход сейчас (в разных конфигурациях) и продолжаю получать ошибки прав доступа, что бы я ни делал. На данный момент это действительно не стоит того.

Это звучит жестко, но я думаю, что мне просто нужно порекомендовать людям использовать Tampermonkey, пока это не решится. Скрипты контента в их текущем воплощении действительно не очень хорошо подходят для сценария использования пользовательского скрипта.

Все 14 Комментарий

Не совсем проблема Greasemonkey, скорее проблема скрипта содержимого Firefox.
https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Content_scripts#Accessing_page_script_objects_from_content_scripts

Либо назначьте свой собственный window.wrappedJSObject либо используйте unsafeWindow в котором Greasemonkey уже назначил обернутый объект.

@Sxderp Я не знаю, что "не совсем проблема Greasemonkey" - и Tampermonkey, и Violentmonkey справляются с этим как раз без проблем. Не только это, но это критическое изменение, которое не упоминается ни в одном из сообщений блога.

Разве это не должно быть исправлено для правильной работы с существующими пользовательскими скриптами и обеспечения перекрестной совместимости с другими популярными менеджерами пользовательских скриптов?

Кроме того ... это действительно объясняет проблему? Почему сценарий зависает, а не просто не удается выполнить поиск?

Я не уверен насчет заморозки. Скопировал ваш код, и он у меня не зависает.

Изменить: извините, неправильно понял комментарий «замораживание». Я думал, вы имели в виду, что Greasemonkey больше не работает. Он «зависает» (прекращает выполнение) в этой строке, потому что Javascript попадает в ошибку использования до объявления. Совершенно уверен, что это считается «фатальным». То есть, не продолжает выполнение кода.


Если взглянуть на код Violentmonkey, похоже, что они внедряют скрипты, создавая элементы <script> . Вместо использования метода tabs.executeScripts() API.

Конечно, у этого есть свои недостатки.

Итак ... когда Firefox сталкивается с этой строкой, он просто молча прекращает выполнение? Без сообщения об ошибке? Какая невероятно странная вещь.

В любом случае, разве не целью является поддержание совместимости с существующими пользовательскими скриптами? В конце концов, это не нишевая функция - взаимодействие с собственным JavaScript страницы - очень распространенная вещь.

В любом случае, разве не целью является поддержание совместимости с существующими пользовательскими скриптами?

Конечно, это является. Мы не идеальны, и это бесплатный проект с открытым исходным кодом, созданный волонтерами, у которых так много свободного времени.

На данный момент у меня есть план, как это улучшить, но он ожидает, что Mozilla реализует функцию, которая сделает это безопасным. # 2549

@arantius Думаю, я мог оторваться немного конфронтированно ... Прошу прощения за это.

Я предполагаю, что это продуманное решение поставить безопасность выше удобства использования. Пока ситуация не разрешится, что мы можем сделать в качестве обходного пути со стороны автора сценария? В моем конкретном случае я пробовал как var $ = window.wrappedJSObject.$; и var $= unsafeWindow.$; в верхней части скрипта, но это дало мне еще одну ошибку при попытке использовать $(document).ready(...) : Error: Permission denied to access property Symbol.toStringTag .

Ошибка: отказано в доступе к свойству Symbol.toStringTag

Я не думаю, что это проблема window.wrappedJSObject.$ а скорее какой-то другой объект, который вы создали в пользовательском скрипте, либо как литерал объекта, либо с конструктором new , не был должным образом импортирован в область, в которой вы пытаетесь получить к ней доступ (возможно, область окна страницы).

Ссылка выше предоставляет подробную информацию о cloneInto которое вам понадобится.

Нет, я почти уверен, что проблема в window.wrappedJSObject.$ . Следующее не работает с той же ошибкой:

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

var $ = window.wrappedJSObject.$;

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

Это, однако, молча терпит неудачу:

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

var $ = window.wrappedJSObject.$;

$.ready(function() {});

Я пробовал использовать cloneInto , но это не помогает. Как вы думаете, можете ли вы предоставить короткий пример пользовательского скрипта, который использует экземпляр страницы $ ?

Ах, в этом случае у вас нет разрешения на доступ к функции. Затем вам нужно использовать 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);

Я пробовал этот подход сейчас (в разных конфигурациях) и продолжаю получать ошибки прав доступа, что бы я ни делал. На данный момент это действительно не стоит того.

Это звучит жестко, но я думаю, что мне просто нужно порекомендовать людям использовать Tampermonkey, пока это не решится. Скрипты контента в их текущем воплощении действительно не очень хорошо подходят для сценария использования пользовательского скрипта.

Согласитесь с @obskyr , просто порекомендуйте моим людям использовать tampermonkey

+1, перенесен в Tampermonkey (https://addons.mozilla.org/en-US/firefox/addon/tampermonkey/), похоже, все мои скрипты там работают.

+1, перенесен в Tampermonkey (https://addons.mozilla.org/en-US/firefox/addon/tampermonkey/), похоже, все мои скрипты там работают.

Это может сработать в краткосрочной перспективе и отлично работает, чтобы скрипты продолжали работать, но в долгосрочной перспективе это может быть ложным решением полагаться на полную замену. Краткосрочный успех может быть недальновидным ... ;-)

Я использую ТМ как замену, но с ней есть некоторые проблемы, которых я не могу отрицать. Кроме того, с FF Quantum могут быть некоторые проблемы с безопасностью, поэтому он работает, но не следует полагаться только на одно решение ...

Что ж, мне все равно нужно поддерживать TM в моих скриптах, потому что не все используют Firefox. Итак, раньше я поддерживал GM и TM, теперь это просто TM. Пока проблем не заметил.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги