Hacker News new | past | comments | ask | show | jobs | submit login

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/69d38fb1d2024cb829edfff57d...




This 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 (Although this library does not look maintained anymore)


Cool! 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.


You can also take a look at mithril.js implementation of hyperscript [0]

  [0] https://github.com/MithrilJS/mithril.js/blob/next/render/hyperscript.js


was about to mention Mithril.

solid framework, but not great for large applications.


What issues have you encountered that make it not great for large apps?


it 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.


For (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

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)


Curious why you claim that. It can be used the same way as React is used, and React is largely touted as something that is fitting for large apps.


Yup, it's almost exactly the same syntax if you use Hyperaxe (built on top of HyperScript): https://github.com/ungoldman/hyperaxe/


hyperscript itself is basically Elm without the Elm language


The 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


Neat! 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.


I 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.


I 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/we...

Works very well, and don't need to transpile.


How is this different from just using a hyperscript library directly and bypassing JSX-like transpilation?


Solenya does pretty much exactly what you've described: 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.


I 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.)


Slightly more verbose (buying code size): https://github.com/stefanhaustein/notemplate


I really like specifying event handlers with functions, I've got to see if I can get that to work with server side generated HTML.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: