12 ms·
VanillaJSX.com
- arjvik 2y agoWhat benefit does the virtual DOM add?
- spoiler 2y agoDOM interactions (read, writes) are synchronous, they're very slow, and it must happen on the main thread. This can cause the browser tab to freezing if access and updates aren't carefully "curated" (ie you don't want to read-check-then-write in a tight loop; or even write too often, even if it's the same value). It can also simplify some stuff surrounding event handling (but that's not it's main goal I think) So people wrote various ways to defer/batch/denounce updates. Virtual DOM is a general solution/implementation. It's not the only one, but I think you always need at least a tiny runtime to avoid too much DOM access (ie Svelte, Solid JS are fairly minimal)
- meiraleal 2y ago> but I think you always need at least a tiny runtime to avoid too much DOM access Unless you use lit-html, which has a very efficient diffing algorithm that only updates the nodes that have changed.
- smallnamespace 2y agoHow is that done without a vdom?
- meiraleal 2y agoLit-html uses template literals for that https://lit.dev/docs/libraries/standalone-templates/ https://lit.dev/docs/libraries/standalone-templates/ "lit-html lets you write HTML templates in JavaScript using template literals with embedded JavaScript expressions. lit-html identifies the static and dynamic parts of your templates so it can efficiently update just the changed portions."
- smallnamespace 2y agoA a high level there's not much difference between template literals and JSX, they are both syntax-sugary ways to represent trees of essentially function calls. > efficiently update just the changed portions Since actually applying each change to the real DOM is too slow, the only way to efficiently update is to batch changes and then apply the delta to the actual DOM. That means we need to keep track of some state, namely the previously applied state and the current goal state, which you then compare. Now, you may have noticed that we've just independently invented the concept of diffing. And the extra state that needed to be tracked can be given a spiffy name, like "virtual DOM", since it's like the DOM, but not the real thing. So, I'm quite unconvinced by Lit-html's claim that they are able to efficiently mutate the DOM without using a vDOM anywhere. Either their method is not efficient (for example it falls over for rapid updates), or there is a data structure under the hood that is analogous to a vDOM, even if they prefer to give that data structure a different name.
- meiraleal 2y agoOh well, we gotta thanks the great developers of Lit-html for making it transparent then. And a lot faster than React. https://krausest.github.io/js-framework-benchmark/current.html https://krausest.github.io/js-framework-benchmark/current.ht...
- smallnamespace 2y agoYes, looking it into it more, Lit-html is doing a few things to make it all work: 1. It leans on support for the <template> element from browsers to hold fragments of HTML 2. For most use cases, it has a more restricted programming model compared to React or other vdom libraries, because templates are not allowed to change the shape (the tree structure of nodes) of the templated DOM. 3. For some cases where you want it to act more like React (for example, dynamically picking an HTML tag) you must use other mechanisms such as unsafeStatic. The docs explicitly tell you this immediately triggers a re-render = slow. So I guess that answered my own curiosity: the vDOM is mostly replaced by a collection of static templates that don't need to be diffed, because the onus is on the dev to write DOM fragments where the tree does not change. This is a more restrictive model that what React gives you, where you can generate any fragment tree, including ones with different shapes, entirely programatically. If you do want the tree's shape to change, then lit-html isn't promising you good performance. You'll need to use methods like unsafeStatic which are slow. All in all, this is pushing more work off onto the developer. Is this a good tradeoff? I think for most websites you can probably work within Lit's programming model. But the benchmarks you yourself linked points to many, many vDOM libraries that are about as performant as Lit (including React, whose main downside somewhat more memory usage) and has a more convenient React-like programming model.
- samwillis 2y agoThe virtual dom makes implementing a declarative templating system easer, and declarative templates are easer for a developer to reason about, and less error prone, than having to mutate the dom directly. People often mistakingly describe the vdom as faster than the dom, this is incorrect. It would be faster than throwing away the whole components dom and rebuilding, so the same templating code building a new dom, rather than a vdom that's then diffed. Hand crafter mutations will be faster than a vdom diff, simply because the computer is doing les work, however much more error prone.
- spoiler 2y ago> People often mistakingly describe the vdom as faster than the dom, this is incorrect. You'll get better performance with _carefully crafted_ DOM access, but that's easier said than done, especially on a larger applications. vDOM takes care of the "carefully crafted" part with some trade offs, especially if it also defers rendering and doesn't wccess the DOM on every update. So yes, it's easier to write declarative UIs with it, but it's also there to address common performance issues with unchecked/eager DOM access. Even if you don't throw away the whole tree and insert a new one, it can be very slow. Just _reading_ from the DOM is slow _and_ everything stops while that's being done too.
- miki123211 2y agoVirtual DOM is to classical JS what garbage collection is to malloc and free. Garbage collection is less efficient, but it is sometimes very difficult to figure out exactly when a piece of memory stops being used, which leads to use-after-free, double-free and memory leak bugs. Same goes for classical UI approaches. In classical UI, most pieces of state are kept in at least two places, once in code and at least once in the DOM. For example, in a shopping cart, the total might appear three times, implicitly in the code (as a function that sums the prices of all the items), once as the label of the "open cart" button in the navbar, and once as text in the "your cart" modal, which that button shows or hides. THe cart may be modifiable from different places, the cart modal itself, product pages, product collection pages, order history (when re-ordering recently purchased items) etc. In the classical approach, you need to make sure that all modifications to the cart accurately change the state in all three places. You also need to ensure that if you remove a product from the cart using the modal and you're currently on a page that lets you order the product in any way, the "remove from cart" button on that page needs to turn back into "add to cart", and there may be hundreds of different such buttons, which the cart modal needs to handle somehow. It is very easy to make mistakes here and have the state in the code (array of products) fall out of sync with what the user sees on the page. In React, there's just one array of products, one function to calculate the total, and a lot of places in the code that use this array. WHenever the array changes, the pieces of the page that rely on it automatically re-render, while everything else stays the same. There's no way for the UI and the array to fall out of sync, and there's no need to track where the array is being used and where it's being modified.
- edflsafoiewq 2y agoIt enabled a style of view library where you write immediate-mode type code that always recreates a whole component from scratch, versus having to write finicky code that both creates and then updates pieces of the page as state changes (dirty tracking, etc). Behind the scenes, you're creating the vDOM from scratch, which is diffed against the actual retained-mode DOM, and then only the pieces that are different are updated.
- ProofHouse 2y agoSlows down your app too, sometimes. Depends how well you can work with and mutate a DOM, but if all things equal no VDOM is always faster cause no diffing.
- ProofHouse 2y agoA lot of people can benefit from offsetting mutations with rAF and dbl rAF and batching reads/writes (FastDOM), before needing or considering a VDOM. VDOM came to prominence because of REACT and then started becoming used even when it wasn't needed. It does serve a purpose and scenario when needed, tho
- __s 2y agoWith vDOM I could say `x = JSX` then cache that in state, inserting it in multiple places. Switching to Solid you have to make sure to use `x = () => JSX` & there's some mental model adjustments since logic outside JSX isn't reactive
- acdha 2y agoIf you couldn’t efficiently batch updates, a vDOM could avoid repetitive updates in close succession, especially on IE6 (the browser React was designed for). If you can control your app’s structure, it primarily adds significant increases in the RAM and CPU required for your app and slows load time because you are using a huge amount of JavaScript to emulate the carefully tuned C++ code built in to the browser. If you notice, most of the benchmarks from when React launched claiming performance wins were compared to heavyweight frameworks or complex jQuery plug-in combinations where a single user interaction might trigger cascading updates forcing the browser to rerender things which didn’t change along or to reflow multiple times in cascading update-measure-update chains. Pure DOM implementations were always faster, often by multiple orders of magnitude and once you could drop IE6, and then IE11, the DOM APIs and CSS were rich enough that much of the library code is now a net negative as well (e.g. people used to use complex code trying to build layouts which CSS grids solved).
- config_yml 2y agoReminds me of Action Script 3 which had XML at the core of the language. It was a fun language to work with, but famously failed to become ES4. Oh well, took us 10+ years to arrive close to that with Typescript and JSX.
- quink 2y agohttps://en.wikipedia.org/wiki/ECMAScript_for_XML https://en.wikipedia.org/wiki/ECMAScript_for_XML - Firefox had it too, but people at large just didn't want it, so it got removed. It got disabled for web pages with the release of Firefox 17, 6 months prior to the first release of React.
- sltkr 2y agoPersonally I never heard about it. So it might not be that people didn't want it, but that it wasn't promoted much. Also, it sounds like the only browser to ever support it was Firefox? That was probably much more of a limiting factor for adoption.
- kibibu 2y agoIf you weren't coding for the flash platform you would have easily missed it. Its a shame, E4X was really nice
- mhitza 2y agoPeople didn't want it because browsers didn't support it (except FF, as you noted). Some of us had our fingers crossed that other browsers would pick it up.
- shove 2y agoI don’t recall being able to construct XML inline like this unless maybe that was a Flex server thing?
- dugmartin 2y agoIt was an extension to ES4 called E4X - it allowed inline xml along with a new xml data type. More info here: https://evertpot.com/ecmascript-4-the-missing-version/ https://evertpot.com/ecmascript-4-the-missing-version/
- waynenilsen 2y agoThis plays very nicely with the locality of behavior model of htmx
- sophiebits 2y agoThese examples are cool but I think it’s important to note that none of them show components whose props can change over time, since that ability doesn’t seem to be modeled at all. Clever if you don’t need that but I’m having trouble seeing how it would scale to more complex apps.
- numpad 2y agoMaybe I'm missing something, but how would this prevent you from using setTimeout/setInterval? But I agree that these projects often work great in small use cases, but quickly crumble under "real world" scenarios.
- novocantico 2y agoI admit that the two most complex "interactive apps" I've built with this are not that complex according to many standards: * https://www.immaculatalibrary.com/books.html https://www.immaculatalibrary.com/books.html (src = https://github.com/sdegutis/immaculatalibrary.com/blob/main/site/scripts/books-page.tsx https://github.com/sdegutis/immaculatalibrary.com/blob/main/...) * https://www.immaculatalibrary.com/prayers/ https://www.immaculatalibrary.com/prayers/ (src = https://github.com/sdegutis/immaculatalibrary.com/blob/main/site/prayers/client.tsx https://github.com/sdegutis/immaculatalibrary.com/blob/main/...)
- _heimdall 2y agoI'd be hesitant to run something like a 30fps render loop in a web app. Its been years since I last saw or tried that in a real world app but it didn't end well for performance. Your best bet would be to queue up specific UI changes that need to be made as diff's rather than checking the entire UI state. At that point, though, you might as well run them immediately as the change is needed. If that was still a perf problem you would end up chasing a very complex solution like react fiber to partially update the UI on a loop while periodically pausing for user events.
- sophiebits 2y agoSure, if you blow away the entire app on every state change. But that would lose not only state defined in components (like `i` in ClickMe) but also all state implicitly stored in DOM elements (selection, focus, scroll position, input value, media playback).
- ibash 2y agoPeople forget what problem the virtual dom and react is supposed to solve. No better article than this: https://blog.vjeux.com/2013/javascript/react-performance.html https://blog.vjeux.com/2013/javascript/react-performance.htm...
- Spivak 2y agoAnd then Svelte showed that you could avoid all that with a compilation step and live update the dom efficiently. https://svelte.dev/blog/virtual-dom-is-pure-overhead https://svelte.dev/blog/virtual-dom-is-pure-overhead React is also at the point where re-rendering the whole app is a fiction the library maintains for you while being smarter and doing less, why not go the whole way?
- guax 2y agoFor me is because is hard to remember that problem while dealing the the ones react brings.
- insane_dreamer 2y agoThere are plenty of cases where optimizing for performance isn't necessary. This is where React is not worth the extra headache and complexity.
- cribbles 2y agoThese "what ifs" are kinda funny because the origins of JSX can be traced back to Facebook's XHP[1], which took explicit inspiration from E4X[2], an early JS standard that looked and behaved similar to the library described here. [1] https://engineering.fb.com/2010/02/09/developer-tools/xhp-a-new-way-to-write-php/ https://engineering.fb.com/2010/02/09/developer-tools/xhp-a-... [2] https://en.m.wikipedia.org/wiki/ECMAScript_for_XML https://en.m.wikipedia.org/wiki/ECMAScript_for_XML
- spankalee 2y agoE4X had the unfortunate downside of returning actual DOM instances, which needed to be updated imperatively. That's why JSX eclipsed it, and there hasn't been a serious proposal for HTML templating in JS since then. But maybe we can revive the general idea with a modern take: https://github.com/WICG/webcomponents/issues/1069 https://github.com/WICG/webcomponents/issues/1069
- lolinder 2y ago> had the unfortunate downside of returning actual DOM instances, which needed to be updated imperatively. Isn't this what we have in TFA?
- bastawhiz 2y agoYes, for elements. The project here also supports a notion of components, though, which E4X didn't contemplate.
- olliej 2y agoAlso E4X was only ever implemented in Firefox, never really got traction even in Firefox. But even considering the single implementation problem, it also was just not a good language model, nor was it well specified or defined and it brought with it a pile of weird baggage and complexity. Then because it was The Future there was no real thought into proper interop with JS (it was essentially a completely independent spec so adopted general syntax but specified in a way that meant JS could not simply adopt that syntax).
- spullara 2y agoI was bummed when they removed E4X from the browser implementations.
- novocantico 2y agoThanks for taking some interest in my project. It came from being frustrated with the state of SSGs over the past 10 years. I mostly just make static websites, and I wanted something that was simple and intuitive to me, and JSX seemed like a great fit. But I got very tired of the disproportionately scaled complexity of JSX frameworks like React. Long story short, I made an SSG that just renders JSX as strings. It was natural to extend that to the browser to just render JSX as DOM elements. And in a few cases (mostly layout) it lends well to shared components. Overall I'm happy with what I came up with, although some of it is admittedly a little hacky, and IDE support isn't as good as it could be. [edit] Oh also, this solution works really well for SEO. That's another problem I didn't find solved well in other JSX frameworks.
- thelastinuit 2y agonot the hero we deserve but the villain we need
- hyperhello 2y agoWhat I’m seeing here is not new. It’s this vanilla pattern but with enough back support to leave off the framing and get the syntax highlighting: Var button = html(’<button>im a button</button>’); The html() function is trivial, but it just doesn’t feel like real programming to do this, even though there’s nothing else to it in the end.
- hyperhello 2y agoDownvote me but tell me why. The example is using .onclick, .textContent, etc in a completely vanilla way. I'm just pointing out you can get all the way vanilla and it still works. What's the issue?
- dangsux 2y ago[dead]
- novocantico 2y agololinder explained it well in here
- nashashmi 2y agoI wonder what The examples would look like in ECMAscript 5.
- spankalee 2y agoReturning actual DOM nodes entirely blunts the big advantage of JSX (and non-JSX libraries like Lit) - which is their immediate mode style API, and UI=f(state) model. You want to return a description of the DOM, rather than the real DOM, because you want to be able to reevaluate your templates repeatedly with new state, and efficiently update the DOM where that template is rendered to. All the examples here use imperative DOM APIs to do updates, like with this: function TodoInput(attrs: { add: (v: string) => void }) { const input = <input /> as HTMLInputElement; input.placeholder = 'Add todo item...'; input.onkeydown = (e) => { if (e.key === 'Enter') { attrs.add(input.value); input.value = ''; } }; return input; } class TodoList { ul = <ul class='todolist' /> as HTMLUListElement; add(v: string) { const item = <li>{v}</li> as HTMLLIElement; item.onclick = () => item.remove(); this.ul.append(item); } } Avoiding those `input.onkeydown = ...` and `this.ul.append(item)` cases, and instead just iterating over items in your template, is probably the main benefit of a VDOM. (The problem with VDOMs is that diffing is slow, a problem solved by using templates that separate static from dynamic parts, like Lit - a library I work on).
- recursive 2y ago> You want to return a description of the DOM, rather than the real DOM, because you want to be able to reevaluate your templates repeatedly with new state, and efficiently update the DOM where that template is rendered to. Depends who "you" are. I prefer to have my DOM nodes updated in place without all the reconciliation machinery. (no implication about what you want)
- spankalee 2y agoYou don't need diffing or reconciliation to turn a description of DOM into DOM. Lit works without a VDOM. If all JSX does is return a DocumentFragment that you then need to imperatively add event listeners to and imperatively update, how is it much better than innerHTML?
- lolinder 2y ago
- recursive 2y agoI also made a UI library based on the idea of jsx template expressions that produce real DOM nodes. It also binds model objects to attributes, eliminating some of the imperative event handler boiler-plate. I think it's a great idea, but of course I would. https://github.com/tomtheisen/mutraction https://github.com/tomtheisen/mutraction It lets you do stuff like this. const model = track({ clicks: 0}); const app = ( <button onclick={() => ++model.clicks }> { model.clicks } clicks </button> ); document.body.append(app);
- cyanydeez 2y agoI just don't understand how people can configure their brains to parse html inside JavaScript
- zazaulola 2y agoYou're not alone. Someone suggested that the W3C should convene a Community Group to discuss JSX, but the grown guys involved in writing standards immediately scrapped the idea.
- 1attice 2y agoThere's a trick to it. Kind of like one of those 'magic eye' stereograms that were popular in the nineties. You sort of unfocus and boom, there it is. It also reminds me of that Douglas Adams line about flying: it's the trick of falling and completely missing the ground, so in order to do it, you can't think about it too hard.
- xigoi 2y agoIf there can be JS inside HTML, why not HTML inside JS?
- flowerlad 2y agoThis is very similar to Vanilla TSX: https://github.com/wisercoder/uibuilder https://github.com/wisercoder/uibuilder Here’s an app written using Vanilla TSX: https://github.com/wisercoder/eureka/tree/master/webapp/ClientApp https://github.com/wisercoder/eureka/tree/master/webapp/Clie...
- slmjkdbtl 2y agoI never understand the appeal of JSX over something like h("div", {}, [ h("p", {}, "this is easy"), ...list.map((l) => h("li", {}, l), ]) With this you automatically get loops, variable interpolation etc without having to invent a compiler and new syntax. Can someone help me understand?
- fredmerc 2y agoKeep going down that logical rabbit hole. You end up with Common Lisp!
- erikpukinskis 2y agoYou might be confusing JSX for something else. In JSX you also don’t need new syntax for loops. JSX Is JavaScript, as people like to say. But to your point, JSX doesn’t really do much. Your h function is basically what React.creatElement does. Google “React without JSX” and you’ll see how it looks. JSX is just syntactic sugar over React.creatElement. And that is what makes it so nice… there _are_ no special constructs for loops, or variables, or components. They are actual JavaScript loops, JavaScript variables, and JavaScript function. It makes JSX easier to reason about than most templating languages.
- sim0n 2y agoI would assume that lot of people just find the JSX equivalent a lot more readable and familiar (a matter of opinion, of course.) <div> <p>this is easy</p> {list.map((l) => <li>{l}</li>)} </div> > you automatically get loops, variable interpolation etc without having to invent a compiler and new syntax To be fair to JSX, you use regular loops, interpolation, etc without any different syntax (`{}` accepts a vanilla JS expression), you just obviously need the compiler step to de-sugar the element tags to `createElement` calls.
- slmjkdbtl 2y agoYeah the syntax is almost identical to vanilla js, but requiring a compiler is quite cumbersome compared to the advantage it provides imo.
- andrewstuart 2y agoJust out of interest I wanted to see something a little bit similar in Web Components: <html lang="en"> <body> <h1>Web Components Examples</h1> <h2>Counter Component</h2> <counter-component></counter-component> <h2>Clickable Button Component</h2> <clickable-button></clickable-button> <h2>Toggler Component</h2> <toggler-component></toggler-component> <script> class CounterComponent extends HTMLElement { constructor() { super(); this.count = 0; this.button = document.createElement('button'); this.button.textContent = this.count; this.button.addEventListener('click', () => { this.count++; this.button.textContent = this.count; }); this.attachShadow({ mode: 'open' }).appendChild(this.button); } } class ClickableButton extends HTMLElement { constructor() { super(); this.clicked = false; this.button = document.createElement('button'); this.button.textContent = "Click me!"; this.button.addEventListener('click', () => { this.clicked = !this.clicked; this.button.textContent = this.clicked ? "Clicked!" : "Click me!"; }); this.attachShadow({ mode: 'open' }).appendChild(this.button); } } class TogglerComponent extends HTMLElement { constructor() { super(); this.on = false; this.button = document.createElement('button'); this.button.textContent = "OFF"; this.button.addEventListener('click', () => { this.on = !this.on; this.button.textContent = this.on ? "ON" : "OFF"; }); this.attachShadow({ mode: 'open' }).appendChild(this.button); } } customElements.define('counter-component', CounterComponent); customElements.define('clickable-button', ClickableButton); customElements.define('toggler-component', TogglerComponent); </script> </body> </html>
- girvo 2y agoDoes the final example not work in Firefox for anyone else? It worked in Edge, but not Firefox for me Uncaught (in promise) TypeError: Map.groupBy(...).entries().map is not a function
- iammrpayments 2y agoObject.groupBy doesn’t seem to be available to all browsers before march 2024: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/groupBy#browser_compatibility https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
- ilrwbwrkhv 2y agoImba is what anyone interested in this sort of thing should look at. I have no idea why it is not more popular. Maybe because JS devs falls for Faang marketing easily. https://imba.io/ https://imba.io/
- xigoi 2y agoMany programmers seem to be scared of anything that doesn’t have semicolons and braces.
- spartanatreyu 2y agoSometimes you need to lay things out differently to help comprehensibility. Braces and semicolons exist so you can do that. Sometimes it's just easier to read an array that's split over multiple lines. Sometimes it's just easier to read a statement that's split over multiple lines. Sometimes it's just easier to read two statements sharing the same line. If your language's restrictions is making code harder to read, then it's making your job harder than it needs to be.
- EugeneOZ 2y agoAs often happens with minimalistic approaches, it only looks interesting on very small and very simple examples. After “How would they handle large data?” it turns into an unreadable mess. Communication between elements is not covered, global deps, DOM updates scheduling, content projection, and so on - you “just don't need it” in small demo examples, but you do need it in the real apps.
- frabjoused 2y agoIt’s already solved. It works well. Just walk away.
- hizanberg 2y agoAnyone else used Hono with SSR JSX? [1] Was super productive and easy to create a Cloudflare Worker Web App that’s free to host thanks to Cloudflare’s generous 100k daily worker request limit. Generally don’t believe in serverless for larger Apps, but for small websites that you just want to create, deploy and ignore - it’s great! https://hono.dev/docs/guides/jsx https://hono.dev/docs/guides/jsx
- drikerf 2y agoNice project! I do wonder though if jsx is the best way to represent elements in code? Clojure datastructures makes this so much more enjoyable. Everything is just basic lists and maps which makes it very flexible and powerful. [:ul [:li "task 1"] [:li "task 2"]] It's weird that it's not more common for making web apps.
- globular-toast 2y agoThere is a library for Python called htpy that does this. Trouble is if you're used to HTML it can take a while to get used to it. It's like a learned helplessness or something.
- edflsafoiewq 2y agoThere are a lot of DOM util libraries that look like h("ul", h("li", "task 1"), h("li", "task 2")) This is called "hyperscript-style" after an early library that used it. This is basically what JSX compiles to too. There used to be a lot of JSX vs hyperscript debates. There's also variants like h.ul(h.li("task 1"), h.li("task 2")) using Proxies now too.
- mg 2y agoWhat is the benefit of mixing js and html? el = <button>Click me</button> as HTMLButtonElement; What would be the downside of el = html.button('<button>Click me</button>'); ? That way no compilation step would be needed and debugging would be easier as the code executed in the browser is the same code the developer writes.
- littlestymaar 2y agoWith the first example you have syntax highlighting and compile-time check. With the second of you have stringa.
- mg 2y agoWhy wouldn't one be able to tell syntax highlighters and code checkers that the string that goes into the html.something() functions is html?
- Joeri 2y agoIf you use a html`` tagged template literal combined with the html-in-template-string vs code extension you get syntax highlighting. A simple html identity literal function is a one-liner: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/raw#building_an_identity_tag https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
- moffkalast 2y agoThe benefit is that it makes people puke from looking at it so you have more job security I guess. Putting xml onto the same line with a scripting language is like mixing toothpaste and orange juice. I don't understand why people take such offense to calling document.createElement() or document.getElementById() or kind of document. or window. function. It's consistent and native.
- Zecc 2y agoCompare class Item extends EventTarget { #checkbox = <input type='checkbox' /> as HTMLInputElement; li; constructor(private list: List, text: string) { super(); this.li = ( <li class='item'> {this.#checkbox} <span onclick={() => this.toggle()}>{text}</span> <button class='close' onclick={() => this.remove()}></button> </li> as HTMLLIElement ); this.#checkbox.onclick = () => this.toggle(); } } with class Item extends EventTarget { #checkbox; li; constructor(private list: List, text: string) { this.#checkbox = createElement('input'); this.#checkbox.setAttribute('type', 'checkbox'); this.li = document.createElement('li'); this.li.className = 'item'; this.li.appendChild(this.#checkbox); const span = document.createElement('span'); span.onclick = (() => this.toggle()); span.textContent = text; this.li.appendChild(span); const button = document.createElement('button'); button.className = 'close'; button.onclick = (() => this.remove()); this.li.appendChild(button); } } Of course you can create helper functions to avoid all the `createElement`s followed by `setAttribute`s. As mentioned elsewhere you can even used tagged strings. But doing things "manually" is painful.
- whazor 2y agoI don't see why the type casting (as HTMLButtonElement) is needed. Because document.createElement("button") returns HTMLButtonElement in TypeScript.
- miika 2y agoI used to explore similar stuff and prototyped something I call “Vanilla Components” but then in the end I fell in love with Web Components and quit React (and all other frameworks).
- merlindru 2y agoVanJS deserves a mention here! https://vanjs.org/ https://vanjs.org/ Another interesting thing is that other JSX libraries like Solid.JS also return DOM nodes, and I love that this idea is gaining traction The closer we get to the platform we're using, the better. Being removed by layers of abstractions CAN be useful, but in practice, I haven't found a use for abstracting away the platform. (yet.) Maybe huge projects like Facebook benefit from this tho (which I haven't worked on)
- croes 2y agoIsn't SolidJS useless in the bundle size comparison?
- novocantico 2y agoThat may be a point in favor of imlib. Technically this is the only code bundled with vanilla jsx: https://vanillajsx.com/@imlib/jsx-browser.js https://vanillajsx.com/@imlib/jsx-browser.js
- dqh 2y agoThose interested in this space may find my fairly unknown project interesting: https://nakedjsx.org/ https://nakedjsx.org/ It started as a static site generator but added a bunch of support for client JavaScript too.
- n3storm 2y agoFor me is like old PHP where HTML and controlling and data access was all around. We use to call it spaghetti code.
- NaN1352 2y agoHow does this stack up aginst using lit-html?
- NaN1352 2y agoI’m having fun using vanilla js with lit-html. Using string templates instead of jsx. VSCode extensions for lit make it almost identical to editing vue templates with type checking etc
- cies 2y agoI frown at JSX. Just a layer of abstraction that is so "leaky" that you have to know what actually goes on in the layers below or you are fucked. It looks simpler at first glance/ to a untrained eye; but it's just adding complexity without really solving any problems. I like approaches like Kotlinx.html, scalatags, Elm's HTML package or HtmlFlow. They are also abstractions, but they add typesafety that html-as-a-string does not offer. On top of that you get breakpoints, code completion, and you can keep working in one language.
- talkingtab 2y agoA side question. The advantage of JSX I see is the ability to connect, declaratively, components. I find this very helpful in terms of understanding programs I write. I wonder if I use React not because of the virtual dom, but simply because of JSX. So I would like to explore the ability to use JSX in non-DOM environments. react-three-fiber does this with Threejs, but then it is still React oriented. I found this article about parsing JSX https://blog.bitsrc.io/demystifying-jsx-building-your-own-jsx-parser-from-scratch-caecf58d7cbd https://blog.bitsrc.io/demystifying-jsx-building-your-own-js.... And I know babel has something that parses JSX. Does anyone have recommendations for doing this. Threejs to me a good candidate - a non React version, since it is a hierarchical system (scene, meshes, materials etc), but I suspect there are other applications. I made an attempt to implement a Javascript version of Hickey's transducers - a sort of conveyor belt of functions and that is another instance of a series of processing steps that might be best represented in JSX
- erikpukinskis 2y agoI see what you’re getting at, but technically the virtual DOM is what makes JSX declarative. JSX doesn’t actually write anything, it’s just a templating language over React.createElement. It’s the virtual DOM that actually syncs those structures created by createElement to the real DOM. So it’s the virtual DOM that allows you to write your code declaratively. That’s evidenced by OP’s project, which is JSX without the declarative piece. You just get an Element and then you have to update it imperatively if you want to change anything.
- deleted 2y ago[deleted]
- andruc 2y agoIt's very strange that when I land on the page for the very first time, I land halfway down the page and I'm staring at a block of random code. Not what you'd expect to see.
- andruc 2y ago#real-todolist has an autofocus element and I'm using Firefox
- novocantico 2y agoOops. Fixing now.
- andruc 2y ago\o/
- andruc 2y agoAny comparisons on performance?
- emadda 2y agoOne of the reasons for JSX originally was to reduce usage of the DOM APIs, as they are slower than direct JS object manipulation. The JSX diff of prev/next allows you to minimize DOM API calls. I would guess there is more overhead in creating a dom element than a JS object (which JSX elements compile to).
- austin-cheney 2y agoReact came out in 2013. At that time object manipulation would likely have been, at best, only marginally faster than writing to the DOM. First, you have to understand that at that time Firefox was about 500x faster at accessing the DOM than Chrome and about 250,000x faster accessing the DOM via the API methods than via querySelectors. Firefox and Chrome performed about equally in use of querySelectors with Chrome being a tiny bit faster. So, the DOM was already fast, but occupied a different memory space than JS. At any rate the original motivation had nothing to do with performance. The goal was to introduce a template system that fit with React’s state/component system. JS modules weren’t a thing yet, so code organization was very different at that time and centered around concepts like AMD and Common.js, though it was mostly some form of AMD typically require.js. The design of the template system in Vue was created to solve for the exact same conditions according to the internal organization of Vue.
- emadda 2y agoRespectfully, my experience says otherwise: https://jsben.ch/cSWJa https://jsben.ch/cSWJa - JS object appears to be at least 2x faster than document.createElement() (Chrome) - Note: JS object only loosely represents JSX element so it is a bit unfair. But with actual JSX objects I would assume it is still somewhat faster than the DOM API. https://youtu.be/DgVS-zXgMTk&t=1532 https://youtu.be/DgVS-zXgMTk&t=1532 - Pete Hunt, one of the React devs, says "JSX is faster than the DOM because it is JS memory."
- austin-cheney 2y agoYour current benchmark does not represent browsers in 2013. It also presents a wildly different use case. It’s common to rapidly create and destroy nodes only because that is what convenient for framework logic. Outside of frameworks DOM nodes are modified more frequently than created anew. > - Pete Hunt, one of the React devs, says "JSX is faster than the DOM because it is JS memory." That doesn’t make sense. Your only choices to display content in the browser using JS is via DOM modification or canvas. If not using canvas you are touching the DOM no matter what. It is true that DOM memory is different than JS memory, but the DOM API is fast enough that it doesn’t matter, especially since you are touching the DOM no matter what. If your approach to DOM interaction is too slow it’s because of string parsing on things like innerHTML and querySelectors. So if performance is important then don’t do things that parse strings and don’t abstract away the DOM interaction because you are touching it no matter what.
- NohatCoder 2y agoFor anyone who can live without <> syntax I made DOM Maker, no compilation step, no injection vulnerability footguns, just make a bunch of function calls in a tree structure, and you get DOM with the same tree structure, complete with non-string event handlers. Mostly I just do Vanilla.js, but the vanilla DOM creation functions turn really verbose, I got tired of that and created this to cut back on code size and increase readability. There are other libraries that do something similar, but in my own very biased opinion this is one of the better. https://github.com/NoHatCoder/DOM_Maker https://github.com/NoHatCoder/DOM_Maker
- jwtorres 2y agoI genuinely don't understand why anyone would be interested in using frameworks on top of JS. None of them can do anything that pure JS can't do (+libraries), they just make it less readable and less intuitive compared to the original C-like syntax of JS. JS libraries make sense, of course, but why keep messing with the syntax?
- nf17 2y agoGreat job, is there something similar but for SwiftUI?
- xwall 2y agoNo matter how complex your app is but still React will not break, performance on web is not a big issue as benchmarks say, even a junior developer can achieve 90%+ lighthouse score, but any senior developer may fail to ship it successfully. ultimately go to react.dev because: "Maturing is realizing React is best"