ProjectEvergreen / greenwood

Greenwood is your full-stack workbench for the web, focused on supporting modern web standards and development to help you create your next project.
https://www.greenwoodjs.io
MIT License
94 stars 9 forks source link

HTML Modules plugin (experimental) #1221

Open thescientist13 opened 2 months ago

thescientist13 commented 2 months ago

Summary

Coming out of the work done in #923, it would be nice to have some form of support for HTML Modules (at least our interpretation of it). Ex:

<!-- hero.html -->
<div class="hero">
  <h2>Welcome to my website</h2>

  <a href="#">
    <button>Get Started</button>
  </a>
  <a href="#">
    <button>Learn More &#8594</button>
  </a>

</div>
import template from "./hero.html" with { type: "html" };

export default class HeroBanner extends HTMLElement {
  connectedCallback() {
    if (!this.shadowRoot) {
      this.attachShadow({ mode: 'open' });
      this.shadowRoot.appendChild(template.content.cloneNode(true));
    }
  }
}

customElements.define('app-hero', HeroBanner);

As a super duper bonus would be great to also get some sort of DOM Parts / templating API in there too (which might require WCC support)

<!-- card.html -->
<div class="card">
  <h2>{{heading}}</h2>
  <img src="{{imageUrl}}" alt="{{heading}}"/>
</div>
import template from "./card.html" with { type: "html" };

export default class Card extends HTMLElement {
  connectedCallback() {
    if (!this.shadowRoot) {
      template.replace('heading', this.getAttribute('heading'));
      template.replace('imageUrl', this.getAttribute('imageUrl'));

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

customElements.define('app-card', Card);

And use it like this

<app-card
  heading="My Item"
  imageUrl="/path/to/image.png"
></app-card>

Details

Would definitely to call this out as experimental and very much an interpretation of the specification, and should probably start a discussion to track those future facing implementations for when they land / co-alece at the standards level.

Would be nice to see if this could be used in conjunction with #955 to achieve something like this?

import fragment from './html?type=html';

export default class PageLayout extends HTMLElement {
  async connectedCallback() {
    this.innerHTML = fragment.innerHTML;
  }
}

Might also want to revisit our html-includes plugin and deprecate the the Custom Element flavor since I think this was all conceived before SSR and WCC? 🤔