Greasemonkey: document.head is null when @run-at document-start

Created on 15 Jun 2017  路  9Comments  路  Source: greasemonkey/greasemonkey

Environment

Key | Value
-- | --
System Platform | AMD64, Windows-10-10.0.14393
Browser | Firefox Developer Edition (55.0 Beta 1, 64 bit)
User Agent | Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:55.0) Gecko/20100101 Firefox/55.0
Build Config | https://hg.mozilla.org/releases/mozilla-beta/rev/6872377277a618b2b9e0d2b4c2b9e51765ac199e
Grease Monkey | 3.11

Test user script:

// ==UserScript==
// @name        HeadTest
// @namespace   HeadTest
// @include     *
// @run-at      document-start
// @version     1
// @grant       none
// ==/UserScript==
AddGlobalStyle('body{background-color:red;}');

function AddGlobalStyle(css) {
    var head, style;
    head = document.getElementsByTagName("head")[0];
    console.log("[Test]: Head: %o", head); //DEBUG
    console.log("[Test]: document.head: %o", document.head); //DEBUG
}

Expect Result:

[Test]: Head:  <head> 
[Test]: document.head:  <head>

Actual Result:

[Test]: Head:  undefined
[Test]: document.head:  null

This issue also applies to GM_addStyle

Most helpful comment

@the8472 If the behavior of current document-start is correct and intentionally, then we need to using an observer every time you need to add style
Something like

function addGlobalStyle(css){
  let headHunter = new MutationObserver(
    records => {
    ; check mutation records
    ; is added node's tag name 'head'?
    ; create a style node then throw it in
    ; then disconnect us
   }
  );
  headhunter.observer(document, {childlist : true});
}

is needed for every script that add a style before document-end. That's boring.

I hope GM_addstyle could do that for me, or write some useful warning in the wiki ("GM_addstyle is not available for scripts with @run-at document-start,don't' use it, find a solution yourself", etc)

All 9 comments

@janekptacijarabaci Found a workaround:

setTimeout(()=>{
    AddGlobalStyle('body{background-color:red;}');
});

It looks unstable and unreliable, but that's the simplest way I can found currently that make things work.

I don't think this is a bug. document-start happens very early. This allows userscripts to manipulate the page before any content javascript has executed.

If you want to execute later just use document-end or use mutation observers to wait for a particular element to be inserted.

@the8472
Maybe you're right.
According to MDN:

document-element-inserted
Sent immediately after the root element of a document has been created, but before executing any script on it.

document-start (based on document-element-inserted) is fired immediately after <html></html> is created, at this time, <head> is null.

But this breaks many scripts that try to add style before the page is rendered (if you use GM_addstyle with document-end you will noticed that the page is blinking) as it works before

I'm not sure this is intentionally

GM_addStyle is silly anyway, it just inserts a <style> tag into <head>, you can do that yourself, with a mutation observer if necessary.

But if that is the actual concern it could be patched to check for the presence of <head> use observers if it is not.

@the8472 If the behavior of current document-start is correct and intentionally, then we need to using an observer every time you need to add style
Something like

function addGlobalStyle(css){
  let headHunter = new MutationObserver(
    records => {
    ; check mutation records
    ; is added node's tag name 'head'?
    ; create a style node then throw it in
    ; then disconnect us
   }
  );
  headhunter.observer(document, {childlist : true});
}

is needed for every script that add a style before document-end. That's boring.

I hope GM_addstyle could do that for me, or write some useful warning in the wiki ("GM_addstyle is not available for scripts with @run-at document-start,don't' use it, find a solution yourself", etc)

Yes, gm_addstyle should be fixed.

But everything else a script might do also has to jump through the same hoops at document-start too, adding styles not special in that regard. Nothing of the DOM is available, so you have to wait for whatever you need. I.e. you need to use observers anyway if you run things at document-start.

Thanks for the detailed report, but this is WAI, and the 3.x branch is ~dead anyway. (I, for one, welcome our new web extension overlords.) Things like GM_addStyle will be fixed by never existing in 4.x.

Scripts like https://arantius.com/misc/greasemonkey/amazon-url-cleaner.user.js exist which don't need a DOM at all, and should run ASAP.

Was this page helpful?
0 / 5 - 0 ratings