Using webNavigation.onCommitted to inject script into web page asap

I want to find a way to inject a script element, as soon as DOM is usable into the web page and before any other script is loaded, within my web extension.

I’ve attempted achieving this by using webNavigation.onCommited event
which is supposed to be fired when a navigation is committed. At least part of the new document has been received from the server and the browser has decided to switch to the new document. (quoting the previously linked page).

The fact is that, by the time I’m injecting the script, the document has already been parsed and rendered by the browser, so the objects I want to reference from the web page perspective aren’t defined yet.

I’ve tested on Firefox only, I do not care for other browsers support at the time being.

I’ve built a minimal, reproducible example. The whole source can be fetched here.

Basically, in the background script I register my event handler, which injects a content script to the “committed” tab:

browser.webNavigation.onCommitted.addListener(details => {
  browser.tabs.executeScript(
    details.tabId,
    {
      'file': 'inject.js',
      'runAt': 'document_start'
    })
  console.log(details)
})

In inject.js, I create a script element and attach it to the document root:

const script = document.createElement('script')
script.src = browser.runtime.getURL('script.js')
script.onload = () => {
  console.log('injected')
}

console.log('injecting')
document.documentElement.appendChild(script)

0

script.js is dead simple:

TEST=1

To test the extension, I’ve built yet another dead simple web page:

<!doctype html>
<html>
  <head>
    <meta charset=utf-8>
    <title>Test</title>
    <script>
console.log('too late?', window.TEST ? 'no' : 'yes :\\')
    </script>
  </head>
</html>

I expect to see in the console a log line ‘too late? no’.
It always happens to be ‘too late? yes :’, except few cases such as opening the web page for the first time, closing the tab containing the page and restoring it (CTRL + SHIFT + T).
Refreshing the page (F5, CTRL + F5, whatever) always results in ‘too late? yes :’

I hope you can provide some helpful insights,
thanks.