如何将“globalThis”填充到旧浏览器中?

Int*_*ked 5 javascript browser cross-browser google-chrome-extension

我们中的许多人使用最新的 Chromium 或 Firefox 浏览器以外的浏览器在 2021 年最后一个季度注意到,网络上的很多东西在几周内就开始出现故障。很快我们就发现这不是孤立的事情,而是更大的事情正在发生。所有问题似乎都是由与旧版或非 Chromium/Firefox 浏览器不兼容的网站使用的相对较新的 JavaScript 引起的,并且它们在许多库中的存在可能导致该问题同时出现在各处。

举个例子,我使用的浏览器不支持许多以前可以工作的网站上的内容。也就是说,这是一个网站的情况,以前运行得很好,但由于一些软件开发人员感到无聊,决定用不太兼容的 JS 替换完全兼容的 JS,不再这样做。

例如,铁(铬)70 不再适用于许多事物,而淡月/新月 28 不再适用于许多事物。有些东西与它们中的任何一个都不起作用,有些则仅与任何一个都不起作用。

StackOverflow.com 最近加入了这个前沿的 JS 潮流:我无法再对 Iron 70 中的任何内容进行投票或评论,并且发布问题已半失效,尽管这一切在 New Moon 28 中仍然有效(目前)。以下是加载此页面时,我在开发人员工具控制台中遇到的一些 JS 错误:

Uncaught ReferenceError: globalThis is not defined
    at stub.en.js?v=05770adb5484:1
    at stub.en.js?v=05770adb5484:1
    at stub.en.js?v=05770adb5484:1
how-do-i-escape-only-single-quotes:45 Uncaught TypeError: StackExchange.ready is not a function
    at how-do-i-escape-only-single-quotes:45
how-do-i-escape-only-single-quotes:79 Uncaught TypeError: StackExchange.ready is not a function
    at how-do-i-escape-only-single-quotes:79
how-do-i-escape-only-single-quotes:87 Uncaught TypeError: StackExchange.init is not a function
    at how-do-i-escape-only-single-quotes:87
how-do-i-escape-only-single-quotes:90 Uncaught TypeError: Cannot read property 'setCacheBreakers' of undefined
    at how-do-i-escape-only-single-quotes:90
how-do-i-escape-only-single-quotes:519 Uncaught TypeError: StackExchange.ready is not a function
    at how-do-i-escape-only-single-quotes:519
how-do-i-escape-only-single-quotes:3598 Uncaught TypeError: StackExchange.ifUsing is not a function
    at how-do-i-escape-only-single-quotes:3598
how-do-i-escape-only-single-quotes:3609 Uncaught TypeError: StackExchange.ready is not a function
    at how-do-i-escape-only-single-quotes:3609
how-do-i-escape-only-single-quotes:4137 Uncaught TypeError: StackExchange.ready is not a function
    at how-do-i-escape-only-single-quotes:4137
how-do-i-escape-only-single-quotes:4181 Uncaught TypeError: StackExchange.ready is not a function
    at how-do-i-escape-only-single-quotes:4181
how-do-i-escape-only-single-quotes:4294 Uncaught TypeError: StackExchange.ready is not a function
    at how-do-i-escape-only-single-quotes:4294
how-do-i-escape-only-single-quotes:4306 Uncaught TypeError: StackExchange.ready is not a function
    at how-do-i-escape-only-single-quotes:4306
Run Code Online (Sandbox Code Playgroud)

是的,我知道这是一个 3 年多前的浏览器,但事实是它曾经工作得很好,直到所有这些 JavaScript 被替换,这让我觉得如果我对代码进行足够的修改,也许我可以让事情正常工作再次。无论如何,这是一个有趣的练习,我正在尝试看看它是否有效。(尽管 Iron 70 已有 3 年以上的历史,但最近的 Pale Moon/New Moon 并不是全新的,并且受到许多相同的兼容性问题的影响,因此为了一个更开放的网络,更广泛的浏览器兼容,我我正在尝试解决这个问题。)因此,我并没有抱怨这一点,而是尝试看看有多少兼容性问题可以通过 polyfill 来扭转或修复。很多人都遇到过同样的问题,因此对此问题的某种解决方案将非常好。

列表中的第一个错误很容易看出问题是什么:globalThis直到版本 71 才在 Chromium 中引入,恰好是我碰巧使用的版本之后的版本。然而,有许多填充工具可以globalThis添加对旧浏览器的支持。因此从理论上讲,我似乎应该能够将对此的支持填充到 Chromium 70 中。

首先,我看了一眼 Polyfill core-js,但意识到这远远超出了我概念验证所需的范围。

我最终尝试在这里使用polyfill: https: //mathiasbynens.be/demo/globalthis.mjs

polyfill 本身在这里得到了很好的解释: https: //mathiasbynens.be/notes/globalthis

为了测试这一点,我继续构建了一个简单的 Chrome 扩展,其中包含以下内容:

manifest.json:

{
    "manifest_version": 2,
    "name": "My Extension",
    "version": "0.1",
    "description": "My Description",
    "author": "Me",
    "permissions": ["https://stackoverflow.com/*"],
    "content_scripts": [{
            "matches": ["https://stackoverflow.com/*"],
            "js": ["corejsmin.js"],
            "run_at": "document_start",
            "all_frames": true
        }
    ]
}
Run Code Online (Sandbox Code Playgroud)

corejsmin.js:

// https://mathiasbynens.be/notes/globalthis

// The polyfill starts here.
(function() {
    if (typeof globalThis === 'object') return;
    Object.defineProperty(Object.prototype, '__magic__', {
        get: function() {
            return this;
        },
        configurable: true
    });
    __magic__.globalThis = __magic__;
    delete Object.prototype.__magic__;
}());
// The polyfill ends here.


console.log(String(globalThis));
Run Code Online (Sandbox Code Playgroud)

在某种程度上, polyfill似乎可以工作,因为在开发者工具控制台中,我确实在任何页面 JS 错误之前看到了以下打印内容:

[object Window]

然而,错误仍然存​​在 - 特别是在这里,globalThis错误仍然存​​在并且没有改变。

我想象通过在页面上的任何 JS 执行之前将这个 JavaScript 注入到页面中,我将能够进行 polyfill,globalThis这样当它引用时(在本例中是在 StackOverflow 的 JS 代码中),它将正常工作。然而,它似乎并非如此,尽管它在扩展代码中似乎工作得很好。

我在这里缺少什么?为什么是globalThis在页面加载之前定义的,而不是在 Stack Overflow 脚本中定义的?最终,这似乎可能是我要解决的最简单的错误,但这里有些东西不太正确,我认为如果无法正常工作,这种方法就没有任何希望。这种方法是否有什么行不通的地方,并且这里需要不同的注入方法?

wOx*_*xOm 2

内容脚本的 JS 环境与页面隔离,因此对象或原型的更改不会影响页面脚本。

在基于 Chromium 的浏览器中,您需要在脚本元素内运行代码(更多信息):

document.documentElement.appendChild(
  Object.assign(document.createElement('script'), {
    textContent: 'window.globalThis = window',
  })
).remove();
Run Code Online (Sandbox Code Playgroud)

在基于 Firefox 的浏览器中,您可以使用wrappedJSObject

wrappedJSObject.globalThis = wrappedJSObject;
Run Code Online (Sandbox Code Playgroud)