I am at Present Promoting the HTML Component Pattern that i have invented and want to exchange it more with the world to get Response from none Senior Devs if they understand it or not.
I found on this page this article and thought I should Post my Pattern here.
I also hate react for what they did with the Specs and how they try to compensate that with even more bad code.
A Little CodePen to play with https://codepen.io/frank-dspeed/pen/xxGRYxp?editors=1011
So let me start to introduce the pattern I will let you think about it.
The Rules:
Return always String and let the Browser do the Execution we call this Declarative Templating.
Here is a basic HTML Component no custom-element is needed to Archive our Goal while we could use customElement api if we want to but we have no need most times if we only use the connectedCallback the Script tag is like a custom Controlled connectedCallback or let us Say ComponentDidMount Hook
<!-- gets processed before DOMContentLoaded -->
<p>My <span>component</span></p>
<script defer>{
const customElement = document.currentScript.previousElementSibling;
customElement.querySelector('span').innerText = 'Component'
customElement.innerHTML += ' Works!';
}</script>
this example defers also code execution and Component Handling to be executed after DOMContentLoaded event the example before will be executed before DOMContentLoaded
<p>My <span>component</span></p>
<script defer>{
const customElement = document.currentScript.previousElementSibling;
document.addEventListener('DOMContentLoaded', () => {
customElement.querySelector('span').innerText = 'Component'
customElement.innerHTML += ' Works after DOMContentLoaded!';
});
}</script>
//import.meta.scriptElement.getRootNode()
I hope you get the idea and that I could give you some insights into how the Browser Works. As the First that a Browser does is Parsing HTML it makes sense to Work with HTML to control the Loading pipeline.
I also want to show a class based Example
This is the customElement aka Component
lets call the file my-element.js
export class myElementDefinition {
connectedCallback() {
this.querySelector('span').innerText = 'Component'
this.innerHTML += ' Works after DOMContentLoaded!';
}
}
index.html
<p>My <span>component</span></p>
<script defer>{
const customElement = document.currentScript.previousElementSibling;
// Download the Module and Instantiate it but don't use it
// Thanks to defer this gets done in parallel none-blocking.
const myElementModule = import('./my-element.js')
document.addEventListener('DOMContentLoaded', async () => {
// At this Stage our Module is fetched and Instatiated lets use it
const { myElementDefinition } = await myElementModule
const { connectedCallback } = myElementDefinition.prototype
connectedCallback.apply(customElement)
});
}</script>
If you wonder why the hell I used apply and all that this is related to the customElement Spec its the same process that the Browser uses to register nativ customElement definitions.
And Please comment any suggestions or problems that you have with this Pattern thanks a lot happy coding.
Final lets show NodeJS SSR of such a Component
import fs from 'fs'
// This references the index.html from prev example assuming everything in same folder
function requestHandler(req,res) {
res.end(`<html><body>${fs.readFileSync('./index.html')}</body></html>`)
}
This illustrates that we can render such components and the component handles it self the loading
Note for my Self
I should expand on this to a few other general topics like
- How to Import a .html file as single file component.
- In that i should introduce the template tag
- I should show inharitance. of HTML Components.
- I Should show Reactive State via Stream Observeables
Top comments (3)
I used similar approaches when creating vanilla components in the past, when the App needed to support browsers that didn't have
customElements.define(...)
:)This is a nice start but I think there is still a lot missing.
One thing you might want to add are ways to easily put your components in templates, find them in the DOM, call DOM operations on them (as in
myComponent.addEventListener
) and so on.On top of that there are the problems that modern frameworks are trying to solve regarding auto refreshing your views as your 'state' changes in a performant manner.
nice to hear that from you and yes there is more stuff to solve and there are a lot of ways to solve them. The view part ist interristing i will keep you updated because i solve that via Streams to compose Observeable State for DOM Updates.
RequireJS, Backbone enable this approach and Vue use it on whole new level that concept to success. In Core Vue is a way to force standard on String. No one do it on Vanilla as this go out of control.