MarcellPerger1 / adblock-bookmarklet

A bookmarklet to remove ads.
MIT License
6 stars 3 forks source link

Google Closure Compiler? #47

Open MarcellPerger1 opened 1 month ago

MarcellPerger1 commented 1 month ago
Closure Compiler-compatible version of the code: ```js /* eslint-env browser, es2021 */ (function(what) { function shouldIgnore(elem) { for(let s of what.ignore?.selector ?? []) { if(elem.matches(s)) { return true; } } for(let f of what.ignore?.func ?? []) { if(f(elem)) { return true; } } return false; } function isContainerElem(/** @type {!Element} */elem) { // .tagName returns UPPERCASE for some reason return ["DIV", "SPAN"].includes(elem.tagName); } var rm = { elem(/** @type {!Element} */elem) { if(!shouldIgnore(elem)) { removedElems.add([elem, elem.parentElement]); elem.remove() } }, list(/** @type {!Iterable} */elems) { Array.from(elems).forEach(v => rm.elem(v)) }, cls(/**@type {!string} */name) { rm.list(document.getElementsByClassName(name)) }, selector(/** @type {!string} */selector) { rm.list(document.querySelectorAll(selector)) }, func({func, selector=null}) { let elems = selector == null ? document.getElementsByClassName("*") : document.querySelectorAll(selector); for (let elem of elems) { if (func(elem)) { rm.elem(elem); } } } }; var /** @type {!Set>} */ removedElems = new Set; var /** @type {!Set} */ handledElems = new Set; for (let [name, args] of Object.entries(what)) { // don't try to use the 'ignore' property as a thing to block if(name != 'ignore') { for (let arg of args) { rm[name](arg); } } } for(let [elem, parent] of removedElems) { if(handledElems.has(elem)) { continue; // already handled } handledElems.add(elem); if(!parent.isConnected) { // (indirect) parent has been deleted so don't do anything here, // instead go from the parent (which will also be in the Set) continue; } if(!isContainerElem(parent)) { continue; // parent might be an image or similar so don't delete } if(parent.hasChildNodes()) { continue; // don't delete parent - info of other children would be lost } // no children, no info in self, so safe to delete // NOTE: This will add `parent` to the end of removedElems (if not ignored) so will check again from the parent rm.elem(parent); } })({ cls: ['adsbygoogle', 'mod_ad_container', 'brn-ads-box','gpt-ad','ad-box','top-ads-container', 'adthrive-ad'], selector: [ '[aria-label="advertisement"]', '[class*="-ad "],[class*="-ad-"],[class$="-ad"],[class^="ad-"],[class^="adthrive"]', ':is(div,iframe)[id^="google_ads_iframe_"]', '#aipPrerollContainer', // This should really select the top one but we let the 'only contains ads' functionality handle it. // Yes I know its lazy, but it is more elegant than writing a whole new func filter (and more performant) 'span[data-ez-ph-id] span[data-ez-ph-owner-id] span.ezoicwhat', ], /** @type {Array<{selector: string?, func: function(Element): boolean}>} */ func: [ { selector: '[class*="ad" i],[id*="ad" i]', /** This is the one that gets most of them, rest is just special cases */ func(elem) { for (const name of [elem.id, ...elem.classList]) { // TODO also check lowercase followed by uppercase at end e.g. adBox if(/(? iframe', func(/** @type {HTMLIFrameElement} */elem) { // Some sanity checks not to accidenally break websites if(!(elem.sandbox.contains("allow-scripts") && elem.sandbox.contains("allow-same-origin") && elem.sandbox.length == 2)) { return false; } if(!elem.src.toLowerCase().includes("gdpr")) { // Ad iframes very often include a `?gdpr=...` in the URL return false; } return true; } }, ], ignore: { selector: ["body", ".ad-layout", "#game-holder.game-holder-with-ad", ".no-interstitial-ads"], func: [(elem) => { let articles = document.getElementsByTagName('article'); for(let a of articles) { if(elem.contains(a)) { return true; // ignore if an article descends from it } } }] } }) ```

Code size

As of 2024-08-07: Code version Size Improvement over Original (TS) Improvement over Terser (release)
Original TS-types 4807 B 🟰 ⬆️
Original CC-types 4779 B 🟰🔻 0.6% ⬆️
Terser (debug) 2288 B ⬇️ 54.2% 🔺 26.8%
Terser (release) 1804 B ⬇️ 62.5% 🟰
CC simple* 1792 B ⬇️ 62.7% ⬇️ 0.7%
CC advanced* 1681 B ⬇️ 65% ⬇️ 6.8%

*But it prepends "use strict"; which we can remove to gain ~13B.

Pros & Cons

Pros Cons
Smaller code size (esp. advanced) Need to redo the annotations in CC style
Faster code? / Can write more code* Need to maintain 2 version of the code (or abandon TS-types) (or somehow make a TS->CC compiler)
Running Actions is free SLOW (15-45s)

*I presume bookmarks have a max size

MarcellPerger1 commented 1 month ago

If we do, it will have to be the advanced one. For now, I don't think this is too important, but if the size gets out of hand, we can do this.

It would be annoying to maintain 2 versions and I don't want to loose the IDE type hints that come with the TS types.

Maybe the best way would be to create a TS-types -> CC-types converter.