wcc icon indicating copy to clipboard operation
wcc copied to clipboard

investigate requirement of needing a `default export` for rendering entry points

Open thescientist13 opened this issue 3 years ago • 1 comments

Type of Change

  • Question / Documentation

Summary

Currently, wcc requires a default export from the first entry point custom element definition it parses.

For example, is you do this

// src/index.js
import './components/footer.js';
import './components/header.js';

const template = document.createElement('template');

template.innerHTML = `
  <wcc-header></wcc-header>

  <h1>Hello!</h1>

  <wcc-footer></wcc-footer>

  </main>
`;

class Home extends HTMLElement {

  connectedCallback() {
    if (!this.shadowRoot) {
      this.attachShadow({ mode: 'open' });
      this.shadowRoot.appendChild(template.content.cloneNode(true));
    }
  }
}

export { Home };
const { html } = await renderToString(new URL('./src/index.js', import.meta.url));

wcc will throw this error

file:///Users/owenbuckley/Workspace/github/repos/wcc/src/wcc.js:80
  const elementInstance = new element(data); // eslint-disable-line new-cap
                          ^

TypeError: element is not a constructor
    at initializeCustomElement (file:///Users/owenbuckley/Workspace/github/repos/wcc/src/wcc.js:80:27)
    at async renderToString (file:///Users/owenbuckley/Workspace/github/repos/wcc/src/wcc.js:99:27)
    at async init (file:///Users/owenbuckley/Workspace/github/repos/wcc/build.js:38:22)

Details

Maybe it's because this doesn't call customElements.define, so we have no way to know the name? Perhaps that's the tradeoff

// THIS
customElement.define('wcc-header', Header);

// OR THIS?
export default Home

Not sure if this is the same thing, or supplemental to https://github.com/ProjectEvergreen/wcc/issues/117 so should review them both as part of doing either these tasks.


Somewhat related, we should better handle the case where you use a custom element, but not import it

// NO FOOTER IMPORT, but `wcc-footer` is still used in the HTML
import './components/header.js';

const template = document.createElement('template');

template.innerHTML = `
  <wcc-header></wcc-header>

  <h1>Hello!</h1>

  <wcc-footer></wcc-footer>
`;

class Home extends HTMLElement {

  connectedCallback() {
    if (!this.shadowRoot) {
      this.attachShadow({ mode: 'open' });
      this.shadowRoot.appendChild(template.content.cloneNode(true));
    }
  }
}

export { Home };

which will casue wcc to throw this error

[0] file:///Users/owenbuckley/Workspace/github/repos/wcc/src/wcc.js:23
[0]         const { moduleURL } = deps[tagName];
[0]                 ^
[0]
[0] TypeError: Cannot destructure property 'moduleURL' of 'deps[tagName]' as it is undefined.
[0]     at renderComponentRoots (file:///Users/owenbuckley/Workspace/github/repos/wcc/src/wcc.js:23:17)
[0]     at renderComponentRoots (file:///Users/owenbuckley/Workspace/github/repos/wcc/src/wcc.js:36:13)
[0]     at renderComponentRoots (file:///Users/owenbuckley/Workspace/github/repos/wcc/src/wcc.js:36:13)
[0]     at async renderToString (file:///Users/owenbuckley/Workspace/github/repos/wcc/src/wcc.js:107:21)
[0]     at async file:///Users/owenbuckley/Workspace/github/repos/wcc/build.js:16:28

thescientist13 avatar May 08 '22 16:05 thescientist13

I suppose I was just missing the obvious here at first, but unless we pick an explicit name (named imports) then default is the most standards compliant, unassuming API we could pick. Unless we specifically dictated it as something like

class EntryComponent extends HTMLElement { ... }

export { EntryComponent }

So, unless we try to guess / enforce names, default just removes the discussion entirely it seems.

But again, maybe there is another more appropriate hint I am missing here? Maybe I am overthinking it? 🤔

thescientist13 avatar Aug 05 '22 20:08 thescientist13