如何将 `globalThis` 填充到旧版浏览器中?

How to polyfill `globalThis` into older browsers?

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

作为一个恰当的例子,我使用的浏览器没有支持许多网站上 曾经工作 的东西。也就是说,这是一个 曾经工作得很好 但由于一些软件开发人员感到无聊并决定用不太兼容的 JS 替换完全兼容的 JS 的网站,现在不再这样做了。

例如,Iron (Chromium) 70 不再适用于许多东西,Pale Moon / New Moon 28 不再适用于许多东西。有些东西对它们都不起作用,有些对它们都不起作用。

whosebug.com 最近加入了这个最前沿的 JS 潮流:我不能再对 Iron 70 中的任何内容进行投票或评论,并且发布问题已被破坏一半,尽管它仍然有效(目前)在 New Moon 28 中。以下是 this page 加载时我在开发人员工具控制台中遇到的一些 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

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

列表中的第一个错误很容易看出问题所在:globalThis wasn't introduced in Chromium until version 71,正是我碰巧使用的版本之后的版本。但是,globalThis 有许多 polyfill,以增加对旧浏览器的支持。所以从理论上讲,我似乎应该能够将对此的支持填充到 Chromium 70 中。

起初,我查看了 core-js polyfill,但意识到这远远超出了我真正需要的概念验证。

我最后尝试在这里使用 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://whosebug.com/*"],
    "content_scripts": [{
            "matches": ["https://whosebug.com/*"],
            "js": ["corejsmin.js"],
            "run_at": "document_start",
            "all_frames": true
        }
    ]
}

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));

polyfill 似乎 可以工作一些 程度,因为在开发人员工具控制台中,我 在任何页面 JS 错误之前看到以下打印出来:

[object Window]

然而,错误仍然存​​在 - 具体来说,globalThis 错误仍然存​​在并且没有改变。

我想象通过在 页面上的任何 JS 执行之前将 JavaScript 注入页面 ,我将能够填充 globalThis 所以当它 引用时,在这种情况下是在 Whosebug 的 JS 代码中,它会正常工作。然而,它似乎并没有,即使它在扩展代码中似乎工作正常。

我在这里错过了什么?为什么 globalThis 在页面加载之前定义,而不是在 Stack Overflow 脚本中定义?最终,这似乎可能是我看到要解决的最简单的错误,但这里有些地方不太对,如果无法正常工作,我认为这种方法没有任何希望。这种方法有什么地方不起作用吗?这里需要一种不同的注入方法吗?

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

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

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

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

wrappedJSObject.globalThis = wrappedJSObject;