I'm writing Chrome extension (manifest v3), the main aim is to override some of the Window native functions and replace them before any other webpages scripts can access them.
I have contentscript.js
that has run_at = document_start
. The contentscript.js
successfully injects my script.js
into the webpage DOM either into <html>
or <head>
tag (by mutation observer).But (!) i cannot force and guarantee my script.js
will run first before any other website scripts.
When i debug contentscript.js
, the DOM of the page does contain only <html>
and my newly injected <script>
element that loads script.js
. The run_at
thus works fine. But, when i step with debugger after last line, instead of stepping into script.js
, i'm inside websites script (even though my script.js reference is the first in header above all other referenecs). All would be solved easily if contentscript.js could write directly into the webpages window
, but it cannot.
I've tried to add mutator observer inside contentscript.js
where i'm able to detect addition of tags into DOM and i'm able to edit/remove them without (?) letting them execute, but i need the page working.
What i've tried:
debugger;
command into any <script>
so i can see which script runs first
-- everytime it is the websites script, not mine.async=false
, defer=false
to all scripts -- failed,<script>
by rewriting or smart-disabling them and then re-running them after my script.js
registers as read. I'm re-enabling the scripts in order the scripts (a) were observed by observer or (b) by order in DOM from document.querySelectorAll. This approach works for some websites, but some sites throw errors on "not-existing object references" which are then all defined when i check them in console -- for me this seems odd as i evaluate the original scripts in order and look like some race condition by authors of the website (?).Edit: I've also tried to add a custom <script>
with direct script.text = ... code ...
but this is refused due to CSP needing either hash, nonce or unsafe-inline (however, i'll try to edit the HTTP header to contain unsafe-inline now).
Is there any hope to have my script running first with a guarantee? Thank you
The problem is that your injector script is loaded via DOM script
element's src
, so it loads asynchronously and runs after the other scripts loaded by the page.
The solution is to register the injected script at document_start
directly in the context of the page:
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["injected-script.js"],
"run_at": "document_start",
"world": "MAIN"
}
]