Ad script breaks Vue's behaviour and parts of the website
Please confirm the following.
- [X] I checked the existing issues for duplicate problems
- [X] I have tried resolving the issue using the support portal
What browsers are you seeing the problem on?
Chrome (including Arc, Brave, Opera, Vivaldi), Microsoft Edge, Firefox, Safari
Describe the bug
An ad script from cadmus.script.ac that Modrinth loads overrides the definition of Function in globalThis with custom obfuscation function, which seems to break any Vue components that have property definitions of Function type.
This is because Function is not yet overridden at the moment all the component scripts are loaded in and initialised.
defineComponent({
props: {
test: {
type: Function, // << refers to globalThis.Function
default: () => alert('Hello, world!'),
},
},
})
However, when Vue app starts to hydrate, the Function is already overridden with a custom function e5 from the cadmus script. This doesn't cause any immediate harm, but once a component that has property of Function type being initialised, Vue's property definition type check fails here:
https://github.com/vuejs/core/blob/e075dfad5c7649c6045e3711687ec888e7aa1a39/packages/runtime-core/src/componentProps.ts#L462
Because of this failure, Vue goes into a standard behaviour for resolving defaults, which is to check if the default is a function, and if it is, call it with raw properties to resolve the default value. Thus, Vue completely skips the special behaviour for Function properties, which is to assume the function in default is the default value.
With the example above, the ‘Hello, world!’ alert will be shown immediately when Vue attempts to hydrate the component instead of when it's actually called by the component, which is an unexpected behaviour.
One of the components affected by this is vue-multiselect, which is used in many places throughout the site, the first one — in the projects search to select sorting method. Its default function for customLabel property is supposed to be used in the component's code, not during the component initialisation.
Called during initialisation, that default function returns nonsensical value, which causes an error when the component gets rendered because retuned value is not a function. This leaves only a shell generated by the server, and nothing on a re-render:
Another component affected by this are modals, because they have the onHide property, which default value is an empty function. This function gets called as well, returning undefined, which is then used as the default value, and causes an error when popup close button is clicked, because undefined is not a function (duh). #2423
Steps to reproduce
- Don't have an ad blocker, don't have Modrinth Plus, be in region that is served ads.
- Open Modrinth website.
- Navigate to Mods tab.
Expected behavior
This is pure negligence/malice on the ad script developer's side to override JavaScript built-ins like that. This should never be done, and Function, as well as all other built-ins, should remain intact, preserving the expected environment of the web platform.
Additional context
Supersedes https://github.com/modrinth/code/issues/2205 Clarifies https://github.com/modrinth/code/pull/2358
This issue specifically can probably be worked around by running the following code before the ad script is loaded, which effectively prevents it from overriding globalThis.Function. Kinda cursed.
if (import.meta.client) {
const f = globalThis.Function
Object.defineProperty(globalThis, 'Function', {
configurable: false,
writeable: false,
get() { return f },
})
}
i'm seeing a similar issue on firefox exclusively, with and without adblock enabled; where since the ui overhaul, basically almost the entire site is completely unresponsive. sometimes a single click works, and then nothing else ever again until i reload the page, rinse and repeat.
this cannot be reproduced in chromium, but is bound to firefox.
You are likely having completely unrelated issue to this. Clear your browser cache and see if that fixes the issue for you. Otherwise, if that does not help, check the Console tab in Developer Tools (Ctrl+Shift+I or F12) for errors.
Seems to no longer be the case, closing as such
Have to disagree, still occurrs to me; with adblock disabled the site works exactly for one click, then I have to reload again; and so on. Happening in Firefox 136.0
Console from inspector spits out this error upon loading the page:
TypeError: a.default.detectStore(...) is undefined[h1-check.js:1:1301](moz-extension://6b151dff-78f3-4a33-9e30-be8af03852c1/h1-check.js)
u moz-extension://6b151dff-78f3-4a33-9e30-be8af03852c1/h1-check.js:1
1337 moz-extension://6b151dff-78f3-4a33-9e30-be8af03852c1/h1-check.js:1
n moz-extension://6b151dff-78f3-4a33-9e30-be8af03852c1/h1-check.js:1
<anonym> moz-extension://6b151dff-78f3-4a33-9e30-be8af03852c1/h1-check.js:1
<anonym> moz-extension://6b151dff-78f3-4a33-9e30-be8af03852c1/h1-check.js:1
#injectIntoIsolatedWorld resource://gre/modules/ExtensionContent.sys.mjs:687
inject resource://gre/modules/ExtensionContent.sys.mjs:672
injectInto resource://gre/modules/ExtensionContent.sys.mjs:536
AsyncFunctionNext self-hosted:800
There are no other errors in console, just a couple of warnings and some debug text (me_irl)
3 is not a valid value for vendorSpecialPurposesIds [cmp2.js:1:100131](https://cmp.inmobi.com/tcfv2/53/cmp2.js?referer=modrinth.com)
3 is not a valid value for publisherSpecialPurposesIds [cmp2.js:1:100131](https://cmp.inmobi.com/tcfv2/53/cmp2.js?referer=modrinth.com)
is not a valid value for uspDnsText [cmp2.js:1:100017](https://cmp.inmobi.com/tcfv2/53/cmp2.js?referer=modrinth.com)
uspData default usp value based on gpc signal [script.js:1:108809](https://cadmus.script.ac/d14pdm1b7fi5kh/script.js)
Diese Seite befindet sich im Kompatibilitätsmodus (Quirks). Das Seitenlayout kann beeinflusst werden. Verwenden Sie für den Standardmodus "<!DOCTYPE html>".
[iframe](https://sync.kueezrtb.com/api/sync/iframe/?cid=6645bcf5bde227e50dd150f1&gdpr=1&gdpr_consent=&us_privacy=1---&x=1)
Anfrage für Zugriff auf Cookies oder Speicher für "https://sync.kueezrtb.com/api/sync/iframe/?cid=6645bcf5bde227e50dd150f1&gdpr=1&gdpr_consent=&us_privacy=1---&x=1" wurde blockiert, weil sie von einem Element zur Aktivitätenverfolgung (Tracker) stammt und das Blockieren von Seitenelementen aktiviert ist.
<anonymous code>:7:27
Source-Map-Fehler: Error: URL constructor: <anonymous code> is not a valid URL.
Stack in the worker:resolveSourceMapURL@resource://devtools/client/shared/source-map-loader/utils/fetchSourceMap.js:56:22
getOriginalURLs@resource://devtools/client/shared/source-map-loader/source-map.js:73:24
workerHandler/</<@resource://devtools/client/shared/worker-utils.js:115:52
workerHandler/<@resource://devtools/client/shared/worker-utils.js:113:13
Ressourcen-Adresse: <anonymous code>
Source-Map-Adresse: null
It might be worth noting that this is also the case for me with Firefox on Mobile, where with adblock on, no interaction ever works, and with adblock off, also, just exactly one interaction works and then no other until reloading the page. On mobile, this also applies to scrolling. Scrolling works once, and then you're stuck on a page where the browsers navigation and menu bars are hidden away and you cannot get out except by using system navigation buttons.
Was fixed for now by disabling ads for logged-in users