Search code examples
javascriptweb-componentecmascript-6traceur

A web component with ECMA6


index.html

<!DOCTYPE html>
<html>
    <head>
        <script src="https://google.github.io/traceur-compiler/bin/traceur.js"></script>
        <script src="https://google.github.io/traceur-compiler/src/bootstrap.js"></script>
        <script>
            traceur.options.experimental = true;
        </script>
        <link rel="import" href="x-item.html">
    </head>
    <body>
        <x-item></x-item>
    </body>
</html>

and my web component: x-item.html

<template id="itemtemplate">
    <span>test</span>
</template>

<script type="module">
    class Item extends HTMLElement {
        constructor() {
            let owner = document.currentScript.ownerDocument;
            let template = owner.querySelector("#itemtemplate");
            let clone = template.content.cloneNode(true);
            let root = this.createShadowRoot();
            root.appendChild(clone);
        }
    }
    Item.prototype.createdCallback = Item.prototype.constructor;
    Item = document.registerElement('x-item', Item);
</script>

and I get no error nor what I expect to be displayed, any idea if this should actually work?

Is this how one would extend an HTMLElement in ECMA6 syntax?

E: putting it altogether in one page solves the problem at least now I know its the right way to create a custom component, but the problem is having it in a separate file I think it has to do with how traceur handles <link rel="import" href="x-item.html"> I tried adding the type attribute to the import with no luck.


Solution

  • Traceur's inline processor does not appear to have support for finding <script> tags inside <link import>. All of traceur's code seems to access document directly, which results in traceur only looking at index.html and never seeing any <scripts> inside x-item.html. Here's a work around that works on Chrome. Change x-item.html to be:

    <template id="itemtemplate">
        <span>test</span>
    </template>
    
    <script type="module">
    (function() {
        let owner = document.currentScript.ownerDocument;
    
        class Item extends HTMLElement {
            constructor() {
                // At the point where the constructor is executed, the code
                // is not inside a <script> tag, which results in currentScript
                // being undefined. Define owner above at compile time.
                //let owner = document.currentScript.ownerDocument;
                let template = owner.querySelector("#itemtemplate");
                let clone = template.content.cloneNode(true);
                let root = this.createShadowRoot();
                root.appendChild(clone);
            }
        }
        Item.prototype.createdCallback = Item.prototype.constructor;
        Item = document.registerElement('x-item', Item);
    })();
    </script>
    
    <script>
    // Boilerplate to get traceur to compile the ECMA6 scripts in this include.
    // May be a better way to do this. Code based on:
    //   new traceur.WebPageTranscoder().selectAndProcessScripts
    // We can't use that method as it accesses 'document' which gives the parent
    // document, not this include document.
    (function processInclude() {
        var doc = document.currentScript.ownerDocument,
            transcoder = new traceur.WebPageTranscoder(doc.URL),
            selector = 'script[type="module"],script[type="text/traceur"]',
            scripts = doc.querySelectorAll(selector);
    
        if (scripts.length) {
            transcoder.addFilesFromScriptElements(scripts, function() {
                console.log("done processing");
            });
        }
    })();
    </script>
    

    Another possible solution would be to pre-compile the ECMA6 into ECMA5 and include the ECMA5 only. This would avoid the problem of traceur not finding the <script> tags in the import and would remove the need for the boilerplate.