6 ms·
Something close to this is possible already in JS, I'm working on a library for generating HTML in node, heavily inspired by Haskell's blaze and lucid. Example
by glutamate 6y ago
Something close to this is possible already in JS, I'm working on a library for generating HTML in node, heavily inspired by Haskell's blaze and lucid. Example code:
div(
{ class: "table-responsive" },
table(
{ class: ["table table-sm", opts.onRowSelect && "table-hover"] },
thead(tr(hdrs.map(hdr => headerCell(hdr)))),
tbody(
vs.map(v =>
tr(
mkClickHandler(opts, v),
hdrs.map(hdr =>
td(typeof hdr.key === "string" ? text(v[hdr.key]) : hdr.key(v))
)
)
)
)
)
The first argument to a tag is optionally an object with the attributes, any subsequent arguments are children of the tag, or an array with the children.
EDIT:
the library as a gist: https://gist.github.com/glutamate/69d38fb1d2024cb829edfff57da9b162 https://gist.github.com/glutamate/69d38fb1d2024cb829edfff57d...
- applecrazy 6y agoThis actually already exists as a library. This type of syntax is called Hyperscript[1], and it's existed (at least) since 2012. [1]: https://github.com/hyperhype/hyperscript https://github.com/hyperhype/hyperscript (Although this library does not look maintained anymore)
- glutamate 6y agoCool! I was looking for something like this but couldn't find it. Oh well, building my own kept me sane during lockdown. I think combinator libraries like this and one I'm building are definitely better than templating languages, although JSX can also work really well, in particular because it retains the HTML syntax making it easy to copy from the browser into code.
- wilsonfiifi 6y agoYou can also take a look at mithril.js implementation of hyperscript [0] [0] https://github.com/MithrilJS/mithril.js/blob/next/render/hyperscript.js
- holtalanm 6y agowas about to mention Mithril. solid framework, but not great for large applications.
- brlewis 6y agoWhat issues have you encountered that make it not great for large apps?
- holtalanm 6y agoit has been a few years, so maybe these issues have been addressed at some point since I used it last, but: 1) there were multiple issues with deeply nested object models not being reactive within the UI code that cause me to explicitly call m.refresh (can't remember the exact api, as it has been a while, but the function that was called forced a virtual dom refresh, which was _not_ good for performance). I ended up writing a debounce function that would make sure the m.refresh function only got called once per paint at the most, which helped, but it was just a band-aid over the underlying problem, which was that the framework was not detecting reactive property changes within deeply nested models. At the time I was using it, there was no other remedy according to issues that had been brought up on stack overflow. 2) this is probably personal opinion, but the hyperscript model for structuring html, while it looks good on paper, lends to a really tedious process of writing html-generating javascript. I guess I didn't need a numbered list. Those were my main two gripes.
- brlewis 6y agoFor (1), m.redraw() is async; I don't think you have to debounce anymore. The autoredraw system may be more sophisticated than when you used it, too. https://mithril.js.org/autoredraw.html https://mithril.js.org/autoredraw.html For (2), I've been using JSX with Mithril the whole time. My team and I didn't like deeply nested hyperscript either. (At my employment we're in the process of moving away from Mithril, but I'm still using Mithril 2 in a side project)
- 6y ago
- ChristianBundy 6y agoYup, it's almost exactly the same syntax if you use Hyperaxe (built on top of HyperScript): https://github.com/ungoldman/hyperaxe/ https://github.com/ungoldman/hyperaxe/
- schwartzworld 6y agohyperscript itself is basically Elm without the Elm language
- dukoid 6y agoSlightly more verbose (buying code size): https://github.com/stefanhaustein/notemplate https://github.com/stefanhaustein/notemplate
- glutamate 6y agoI really like specifying event handlers with functions, I've got to see if I can get that to work with server side generated HTML.
- pickle-ts 6y agoSolenya does pretty much exactly what you've described: https://github.com/solenya-group/solenya https://github.com/solenya-group/solenya Interestingly, in a very early version classes were allowed to be expressed as arrays of strings just like you had, but in the vast majority of cases a space delimited string worked fine, so this feature was dropped for simplicity/uniformity.
- glutamate 6y agoI added the option to have classes as an array of strings to facilitate conditional classes. (I then filter out falsy values so I can use a simple condition && "conditional-class" At the end of the class list.)
- bwindels 6y agoI went with this syntax as well for a project [1], being just a simple wrapper on top off createElement, with functions as children/attributes being used as one-way bindings. 1: https://github.com/bwindels/brawl-chat/blob/master/src/ui/web/session/room/RoomView.js#L13 https://github.com/bwindels/brawl-chat/blob/master/src/ui/we... Works very well, and don't need to transpile.
- acdha 6y agoThe Re:DOM library might be of interest — it's very similar to your syntax above and it also comes with a robust toolkit for handling updates without the overhead of a virtual DOM: https://redom.js.org/#elements https://redom.js.org/#elements
- seph-reed 6y agoNeat! I made this exact same thing, but a bit more robust a while ago. It's amazing to see how similar it is. The implication is that it's likely logical.
- acdha 6y agoI definitely had a positive experience using in on a moderate sized project last year — the biggest thing I liked was how simple it was. Everything is standard JS & browser APIs so there was zero overhead when debugging.
- anonytrary 6y agoHow is this different from just using a hyperscript library directly and bypassing JSX-like transpilation?