Images created using `document.currentScript.ownerDocument.createElement` (from within <link> imported HTML) never load
Asked Answered
U

1

2

Here's a function that returns the width of an image, given the image's url:

async function getImageWidthByUrl(imgUrl) {
  const imgEl = document.createElement("img");
  let untilImgLoaded = new Promise((resolve, reject) => {
    imgEl.onload = resolve;
    imgEl.onerror = reject;
  });
  imgEl.src = imgUrl;
  await untilImgLoaded;
  return imgEl.naturalWidth;
}

It works fine. It also (of course) works if we use new Image() instead of document.createElement("img").

However, the document.createElement("img") method doesn't work if document refers to the document object of a <link> html import.

Have a look at this example which imports this html. Notice that the console outputs:

"Starting..."
512
512

and never outputs the final 512 and then "Finished.", like it (seemingly) should. That's because the onload event of the imgEl never fires; the image never loads if it was created with document.currentScript.ownerDocument.createElement. I've tested this in Chrome 69.

Is this expected behaviour, or a bug? Shouldn't it at least throw an error if it's not possible to create an image using a <link>'s document?

Utilize answered 15/9, 2018 at 12:42 Comment(4)
Firefox doesn't seem to run an HTTP request at all for the <link>.Asuncionasunder
... and the MDN documentation does not mention "import" as a recognized value for the "rel" attribute.Asuncionasunder
@Asuncionasunder Firefox hasn't implemented imports (and may not do so in their current state). I should have mentioned this (and probably added the chrome tag). You'll need to add the polyfill to test on firefox (I tried, but couldn't get it to work with that either). Regarding the fact that it seemed to be working fine, I seemed to have accidentally linked to an older version. I've updated the link, and here it is, to be sure: jsbin.com/kuruluzike/2/edit?html,console Please remove the close vote if that was yours.Utilize
And to be clear: I'm perfectly fine using new Image() to get around this, but am just curious as to whether it's a chromium bug or not. This isn't a "please debug my code for me" question.Utilize
V
2

It's the normal behaviour.

The image referenced in the src attribute <img> element in an imported document with <link rel="import"> is not loaded until it is appended to the main document.

From the HTML Imports tutorial:

Think of content as inert until you call upon its services. [...]

Unless you append it's content to the DOM, it's a no-op. In fact, the only thing that "executes" in the import document directly is <script>.

You can apend it to the main document with document.apendNode().

Also, note that in your example, you should pass the imported document reference as an argument of the main function of simple-test.html for some reasons explained in this post or that post.

( function( ownerDocument ) {
    //...
    if( method === "document.currentScript.ownerDocument.createElement") {
        imgEl = ownerDocument.createElement("img")
        var imgOK = document.adoptNode( imgEl )
    }
    //...  
} ) ( document.currentScript.ownerDocument )
Vegetarian answered 15/9, 2018 at 15:22 Comment(4)
Ah, I see. Interesting that new Image() behaves differently - but I guess that does make a bit of sense. In some cases you might not want it to load until it's actually appended. Is this stated anywhere in the spec? I'll add another answer here to help others with this.Utilize
Hmm can you please clarify what you mean in your edit? Which main function are we talking about here? Do you mean that the last line of the HTML import script should be something like ... })(window, document.currentScript.ownerDocument); instead of ... })(window, document);? Thanks!Utilize
@Joe i cannot find the explanation in the specs but in the tutorial (link added). For you 2nd comment: yes right, I've updated the answer and added another link.Vegetarian
Brilliant! Thanks for your research!Utilize

© 2022 - 2024 — McMap. All rights reserved.