Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

example of a progressive, self hydrating, custom element #2

Draft
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

thescientist13
Copy link
Member

@thescientist13 thescientist13 commented Apr 23, 2022

Related Issue

#3

Summary of Changes

  1. Exploring how to use the compiler to enable self-defined, runtime, hydration instructions per element

So this is getting interesting. Now, we can extract special functionality from the custom element without needing to load all of its JS at runtime.

class TestComponent extends HTMLElement {
  constructor() {
    super()

    this.attachShadow({ mode: 'open' });
  }

  static __hydrate__() {
    console.debug('special __hydrate__ function from TestComponent :)')
  }
}

export { TestComponent }

customElements.define('wcc-test', TestComponent)

Screen Shot 2022-04-27 at 8 47 24 AM
Screen Shot 2022-04-27 at 8 47 37 AM

1. Just exploring the intercept concept a bit just to get a feel for it and its limitations.

TODO

  1. Implement actual IntersectionObserver functionality to load TestComponent
  2. Come up with good demo
  3. Maybe this __hydrate__ function could be a good candidate to put into a HydrateElement?

@thescientist13 thescientist13 added feature New feature or request question Further information is requested labels Apr 23, 2022
@thescientist13 thescientist13 self-assigned this Apr 23, 2022
@netlify
Copy link

netlify bot commented Apr 23, 2022

Deploy Preview for merry-caramel-524e61 ready!

Name Link
🔨 Latest commit 5321284
🔍 Latest deploy log https://app.netlify.com/sites/merry-caramel-524e61/deploys/6263535df97d6c0009b877b8
😎 Deploy Preview https://deploy-preview-2--merry-caramel-524e61.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site settings.

@thescientist13 thescientist13 added invalid This doesn't seem right and removed feature New feature or request labels Apr 23, 2022
@thescientist13 thescientist13 changed the title example of intercepting a custom element definition [DRAFT] example of intercepting a custom element definition Apr 23, 2022
@thescientist13 thescientist13 linked an issue Apr 25, 2022 that may be closed by this pull request
5 tasks
@thescientist13 thescientist13 force-pushed the intercepting-custom-elements-define branch from 5321284 to dda232c Compare April 27, 2022 00:06
@thescientist13 thescientist13 force-pushed the intercepting-custom-elements-define branch from dda232c to f144430 Compare April 27, 2022 11:42
@thescientist13
Copy link
Member Author

thescientist13 commented Apr 28, 2022

Had a chance to advance some of my experiments on hydration, thinking of a “bottom up” strategy I suppose, to explore the prospect of what if custom elements could self define their own hydration logic as an alternative to having the framework orchestrate that via attributes / DSL, etc? I know there are a ton of terms being throw around for it now (progressive, resumable, etc) and so not sure what this would be exactly, but premise is that a custom element would define a static __hydrate__ method that could be used to encapsulate its own hydration, loading, whatever the logic may be.

So the SSR framework mechanism (e.g. community protocol) would just need to extract this logic and inject it into the runtime so we don’t have to load the entire custom element definition.

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

template.innerHTML = `
  <style>
    h6 {
      color: red;
      font-size: 25px;
    }

    h6.hydrated {
      animation-duration: 3s;
      animation-name: slidein;
    }

    @keyframes slidein {
      from {
        margin-left: 100%;
        width: 300%;
      }

      to {
        font-size: 25px;
      }
    }
  </style>

  <h6>This is a test</h6>
`;

class TestComponent extends HTMLElement {
  connectedCallback() {
    if (!this.shadowRoot) {
      this.attachShadow({ mode: 'open' });
      this.shadowRoot.appendChild(template.content.cloneNode(true));
    } else {
      const header = this.shadowRoot.querySelector('h6');

      header.style.color = this.getAttribute('color');
      header.classList.add('hydrated');
    }
  }

  static __hydrate__() {
    alert('special __hydrate__ function from TestComponent :)');
    window.addEventListener('load', () => {
      let options = {
        root: null,
        rootMargin: '20px',
        threshold: 1.0
      };

      let callback = (entries, observer) => {
        entries.forEach(entry => {
          console.debug({ entry })
          if(!initialized && entry.isIntersecting) {
            import(new URL('./www/components/test.js', import.meta.url));
          }
        });
      };

      let observer = new IntersectionObserver(callback, options);
      let target = document.querySelector('wcc-test');

      observer.observe(target);
    })
  }
}

export { TestComponent }

customElements.define('wcc-test', TestComponent)

so anything could go here since you have full access to the browser, for IntersectionObserver, MutationObserver, addEventListener, etc. Plus, the runtime overhead is entirely sized by the user, so no extra JS except for what the user themselves chooses to ship.

So for this scenario, you could just use it as

<wcc-test color="green"></wcc-test>

and in action, it would look like the recording below.

wcc-ssr-self-hydration.mov

Notice we get an alert when the hydration logic runs, even though test.js has not loaded. when we scroll down to the intersecting point, the test.js loads the custom element, which then initiates the color change and CSS animation.

I think what’s neat is that at a top level, you could still set attributes on non defined custom element, maybe to preload some data or state, if you’re already running a single pass over the HTML. So could make for a really nice combination of techniques.

Let me know your thoughts, if it sounds appealing, I could open an issue in the community protocols repo. I suppose we could also just export __hydrate__ as well? That might be better for tree shaking / dead code elimination? 🤔

@thescientist13 thescientist13 changed the title [DRAFT] example of intercepting a custom element definition [DRAFT] example of self hydrating custom element Apr 29, 2022
@thescientist13 thescientist13 changed the title [DRAFT] example of self hydrating custom element [DRAFT] example of a progressive, self hydrating, custom element May 1, 2022
@thescientist13 thescientist13 marked this pull request as draft June 17, 2022 16:45
@thescientist13 thescientist13 changed the title [DRAFT] example of a progressive, self hydrating, custom element example of a progressive, self hydrating, custom element Jun 17, 2022
@thescientist13 thescientist13 added community protocol and removed invalid This doesn't seem right labels Jun 17, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
community protocol question Further information is requested
Projects
None yet
Development

Successfully merging this pull request may close these issues.

self defined progressive hydration for custom elements
1 participant