-
Notifications
You must be signed in to change notification settings - Fork 8
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
base: master
Are you sure you want to change the base?
Conversation
✅ Deploy Preview for merry-caramel-524e61 ready!
To edit notification comments on pull requests, go to your Netlify site settings. |
5321284
to
dda232c
Compare
dda232c
to
f144430
Compare
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 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.movNotice 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 |
Related Issue
#3
Summary of Changes
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.
TODO
__hydrate__
function could be a good candidate to put into aHydrateElement
?