0

I was trying to understand how web components work so I tried to write a small app that I served on a webserver (tested on Chrome which support rel="import"):

index.html:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <link rel="import" href="my-app.html" />
  </head>
  <body>
    <my-app />
  </body>
</html>

my-app.html:

<template id="template">
  <div>Welcome to my app!</div>
</template>

<script>
class MyApp extends HTMLElement {
  constructor() {
    super();
    const shadow = this.attachShadow({mode: "open"});
    const template = document.getElementById("template");
    const clone = document.importNode(template.content, true);
    shadow.appendChild(clone);
  }
}
customElements.define("my-app", MyApp);
</script>

But it doesn't seem to work. The <my-app /> tag is not rendered at all in the DOM and I get this error on the console:

Uncaught TypeError: Cannot read property 'content' of null

What cannot I retrieve the template node? What am I doing wrong?

What I would also like to know is if I am allowed to write an HTML document without the boilerplate code (doctype, head, body, ...), because it's meant to describe a component and not an entire document to be used as is. Is it allowed by the HTML5 specs and/or is it correctly interpreted by a majority of browsers?

Thank you for your help.

JacopoStanchi
  • 1,962
  • 5
  • 33
  • 61
  • 1
    be aware the ` is going away and should no longer be used. ES6 Modules are one way to replace it. – Intervalia May 04 '19 at 19:06
  • Yes but IMO ES6 modules are used to import JS modules not HTML. – JacopoStanchi May 04 '19 at 19:09
  • Right. Meaning that the ` – Intervalia May 04 '19 at 19:16
  • It makes me a bit sad. Firstly because I prefer the `.vue` file syntax to the React's component syntax, and secondly because it's not even JSX that the `render()` method returns, it's a template string, which means that there won't be the highlights of the HTML in your IDE and all. – JacopoStanchi May 04 '19 at 19:20

1 Answers1

2

While inside the template, don't use the document global:

<template id="template">
  <div>Welcome to my app!</div>
</template>

<script>
class MyApp extends HTMLElement {
  constructor() {
    super();
    const shadow = this.attachShadow({mode: "open"});

    // while inside the imported HTML, `currentDocument` should be used instead of `document`
    const currentDocument = document.currentScript.ownerDocument;
    // notice the usage of `currentDocument`
    const template = currentDocument.querySelector('#template');

    const clone = document.importNode(template.content, true);
    shadow.appendChild(clone);
  }
}
customElements.define("my-app", MyApp);
</script>

Plunker demo: https://plnkr.co/edit/USvbddEDWCSotYrHic7n?p=preview



PS: Notes com compatibility here, though I assume you know HTML imports are to be deprecated very soon.

acdcjunior
  • 132,397
  • 37
  • 331
  • 304
  • Thank you for your quick answer. Why do HTML imports are to be deprecated though? Will there be something to replace them? – JacopoStanchi May 04 '19 at 19:04
  • If you are using chrome, have a look at the console: **[Deprecation] HTML Imports is deprecated and will be removed in M73, around March 2019. Please use ES modules instead. See https://www.chromestatus.com/features/5144752345317376 for more details.** The alternative at the moment is ES Modules. It is more of a pure-javascript solution. – acdcjunior May 04 '19 at 19:12
  • But how could we continue to import HTML templates? – JacopoStanchi May 04 '19 at 19:14
  • More on why here: https://www.polymer-project.org/blog/2018-10-02-webcomponents-v0-deprecations. Mostrly it is because the spec was never uniformly implemented by the major browsers and the community came to a conclusion it was bad before widespread adoption. – acdcjunior May 04 '19 at 19:15
  • You do want to continue using html templates or are you asking about the "new best" alternative? – acdcjunior May 04 '19 at 19:16
  • I like Vue.js so I wanted to use natively something that looks like the `.vue` file syntax but if there is a more elegant way to do this I'm all ears. – JacopoStanchi May 04 '19 at 19:17
  • I could point some ES Module resources, but I guarantee you using Vue.js will be a better solution (better documentation, more examples online) right now. These web components spec are frequently changing (like HTML imports being deprecated) and, unless you have a hard reason (e.g. stubborn employer) to choose native web components, I'd go Vue.js all the way. Furthermore, if, or when, the web components become really a mature stable standard, there will certainly be ways to generate/migrate web components from vue code. – acdcjunior May 04 '19 at 19:21
  • @acdcjunior In fact I'm writing an essay on IPFS, which is a protocol meant to replace HTTP and would be completly serverless. I asked myself how to continue to do templating without webservers, and the thing is, even front-end frameworks like Vue or React need a Node server. So that was the reason I wanted to document myself on native solutions like web components. – JacopoStanchi May 04 '19 at 19:24
  • Vue/React don't really need a node server. The product of a vue/react app can be just one big `.js` file (aka "bundle") that is imported into the page via a regular ` – acdcjunior May 04 '19 at 19:29
  • Yes I know, especially Vue can be used browser-side, but using components becomes way more complicated. You cannot use `.vue` files on the browser in short. – JacopoStanchi May 04 '19 at 19:34