How to get document.currentScript.ownerDocument in <script type="module">?
Asked Answered
V

2

7

How i can get ownerDocument in script type="module"?

<template>
  text
</template>
<script type="module">
  let owner = document.currentScript.ownerDocument // is null
  
  // But i need get <template>
  
  let tpl = owner.querySelector('template')
</script>
Vina answered 21/7, 2017 at 4:11 Comment(5)
Works for me on FF. Had to fix </template> closing tag though.Colon
@Colon it not works on Chrome and other browsersCannibalism
Indeed just tried in canary and it doesn't work. I have no source on who is right here, but FF executes module scripts before the DOMContentLoaded event, while chrome does it after... But at the end, in this example, owner === document.Colon
So after testing a bit more canary, I would tend to a bug in how they deal with defer scripts. It should fire before DOMContentLoaded, but fails at it. Hence at this moment, currentScript is nullColon
I haven't found how to achieve what you want. However, I can say that the described behavior is correct. In, fact Edge filled in a bug report for the opposite (currentScript was set). developer.microsoft.com/en-us/microsoft-edge/platform/issues/…Cimah
P
6

The spec clearly states that when using <script type="module"> the document.currentScript property is set to null during execution. See spec under "execute a script block".

Which, of course, is obvious if using src attribute. The source has no way of knowing it will be called by a script tag and not an import statement (or both). When inlining the module there always is a script tag, but my guess is that they want to make the experience consistent.

If your document actually is the window.document that is still available as a global. Otherwise you have two options if you still want the script to be loaded as a module:

  • Not the prettiest; create a global above the module and store the template.

    <script type="text/javascript">
    window.myTemplates = ((ns) => {
      const owner = window.document.currentScript.ownerDocument;
      ns.fancyButton = owner.querySelector("template");
      return ns;
    })(window.myTemplates || {});
    </script>
    
    <script type="module">
    const tpl = window.myTemplates.fancyButton;
    // ...
    </script>
    
  • Don't write the template as a HTML template and instead as a ES/JS template. Your editor may not support highlighting literal HTML and linting of the tags is a problem.

    <script type="module">
    const tpl = window.document.createElement("template");
    tpl.innerHTML = `
      <strong>example</strong>
      <span style="background-color: rgba(127,127,127,0.6);">text</span>
    `;
    // ...
    </script>
    
Pinkster answered 23/8, 2017 at 17:17 Comment(0)
B
2

I came across the same problem yesterday and spent hours trying to figure it out and I think I might have a better solution using dynamic import.

The trick is to create a loader script that is not a module like this:

<script src="loader.js"></script>

In loader.js:

var ownerDocument = document.currentScript.ownerDocument;

import('module.js').then((module) => {

     module.main(ownerDocument);

});

And your module:

function main(ownerDocument){

     console.log('Hello from the module!');
     console.log(ownerDocument);

}

export {main};

I hope this helps!

Britteny answered 13/2, 2023 at 16:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.