You can do the same with any system that treats templates as expressions that return a value (the big innovation of React, IMO), it doesn't require vdom.
In Lit, we do this with tagged standard template literal expressions that return what we call a TemplateResult. You can compute, store, abstract over those however you want - they're just JS values. This indeed gives programers a ton of expressive power.
Sure, that's the most straightforward way to approach these things, but doesn't this mean your elements don't have persistent identity between two renders? Tracking elements between renders is what allows animations and other nice things. So it's not exactly the same.
No, it's better. Retaining identity is _easier_ with such a system.
You mark in the DOM where the expressions are, and on updates instead of a vdom diff you check if the template rendering to a DOM location is the same as before. If it is then you just update the expressions. All the unchanged elements stay the same, and sine you don't traverse the DOM or a VDOM, the update is much faster.
In Lit, we do this with tagged standard template literal expressions that return what we call a TemplateResult. You can compute, store, abstract over those however you want - they're just JS values. This indeed gives programers a ton of expressive power.