如何将 `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;
我们中的许多人使用的浏览器不是最新的 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;