SPA's need not be complex nowadays. I use
https://lit.dev 's templating engine. When I want something simple, I use just the templating engine not the full web component framework.
Lit's templating engine is just html that is made super efficient to render because only parts that change are re-rendered. There is no inter language to learn like JSX. It uses native browser html parser, native browser templating capabilities (<template> tag), native event handling and native literal template capabilities of javascript.
I have a simple wrapper class that renders and composes components efficiently and reactively when state changes. The views look like:
class TestView extends LittleLit {
static get properties() {
return {
paramter: {}
};
}
constructor(){
super();
this.el=document.querySelector('#main');//root component attached to the dom
this.subcomponent=new SomeView();
}
render(){
this.subcomponent.somestate=this.somestate;//propagate state down if necessary.
let h=html`<H1>Hellow ${parameter}</H1>${subcomponent.el}`;
render(h, this.el,{host:this});
}
}
To use
v=new TestView();
v.parameter='world';//this triggers rendering if the parameter changed.
Here is my whole framework:
class LittleLit {
constructor() {
this.el=document.createElement("div");
this.refreshScheduled=false;
this._properties={};
let properties =this.constructor.properties;
if(properties!==undefined){
for (let prop in properties) {
this.property(prop,properties[prop]);
}
}
}
refresh(){ //you can call refresh to trigger rendering efficiently
if(this.refreshScheduled===false){
this.refreshScheduled=true;
window.queueMicrotask(()=>this._update());//deduplicated rendering in an efficiently scheduled microtask
}
}
_update(){
this.render();
this.refreshScheduled=false;
}
property(name,options){
Object.defineProperty(this, name, {
set(v){
if(this._properties!==v){ //refresh only if property changed
this._properties[name]=v;
this.refresh();
}
},
get(){return this._properties[name];}
});
}
}
Most of the power comes from the templating library: https://lit.dev/docs/templates/overview/