_hyperscript: A jQuery and JavaScript Alternative
hyperscript.org
hyperscript.org
_hyperscript is much more speculative than htmx, but it is working out pretty nicely. One aspect of the language that HN readers might find interesting is that it is async-transparent: the distinction between synchronous and asynchronous code is largely hidden:
https://hyperscript.org/docs/#async
This allows for some pretty interesting programming techniques, such as event-driven control flow:
https://hyperscript.org/docs/#event-control-flow
One thing to be aware of with _hyperscript is that it is intended as a light weight, event oriented scripting language, I would not recommend a huge application being build out in it exclusively. It is designed to make it easy to plug into the event models of htmx and other libraries.
EDIT: I should also mention, it is still very early in development (0.0.9)
https://journal.stuffwithstuff.com/2015/02/01/what-color-is-...
For light weight scripting I didn't want to have to think about that. I had implement a "wait" command in the old ic-action attribute from intercooler:
https://intercoolerjs.org/attributes/ic-action.html
And I wanted to generalize that.
(A motivation for creating _hyperscript was because I removed ic-action as well as a bunch of other event-based attributes when rewrote intercooler.js as htmx: https://hyperscript.org/docs/#history)
That post from Bob Nystrom's blog makes the point I was trying to make much more eloquently than I could, thanks for sharing!
In the intro section I walk through adding a fetch to some code that jams text into a button and you can see how you don't end up having to change your code to do it: you just write the normal linear code with a fetch command in it:
https://hyperscript.org/docs/#introduction
<button class='btn primary' _="on click fetch /clickedMessage then transition opacity to 0
put the result into me then transition opacity to 1
wait 2s then transition opacity to 0
put 'Click Me!' into me then transition opacity to 1">
Click Me!
</button>
The fetch, wait and transition commands are asynchronous (in javascript terms) but to hyperscript it's all just linear code.[1] https://solovyov.net/blog/2020/a-tale-of-webpage-speed-or-th...
But I salute twinspark as well and if it dovetails better with your sensibilities I encourage you to use it.
It would be really cool to see two projects merge (htmx and twinspark) and join forces.
If a triggering event is received while an event handler is executing, you can specify various behaviours:
https://hyperscript.org/features/on/#queueing
The default is queue last, which will queue the last event and trigger the event handler again once it completes. I agree that is wrong in this case, and so it should specify `queue none` in the handler. I will update the code.
Thank you for taking a close look at the example!
"Focus on the fundamentals of HTML, CSS and JS. Everything else is ephemeral."
I don't mean to pick on whomever wrote these examples, but the ~7 lines of JS for the first example (fading out) shows either a lack of basic understanding or intentional complication to make hyperscript appear better in comparison. A more reasonable solution is 3 lines of code.
.fade { transition: opacity 500ms ease-out; }
<div class="fade" onclick="
this.style.opacity=0;
this.addEventListener('transitionend', () => this.remove());
">Remove Me</div>Instead of finding a more descriptive name or adding a short description below, they put it on a completely different site.
But I'm a bit of a contrarian and every time someone tells me to drop IE support I think "Maybe I won't."
Still, there's a pretty steep curve to developing them, and that generally translates into a shorter lifetime unless they take off in popularity. For example, tooling support, for things like autocomplete, highlighting, debugging will need to be implemented. There's also a lack of community answering questions, making it difficult to pick up for beginners (no stack overflow, etc).
I realize this sounds harsh but truthfully, it made me immediately disregard the library. If this is how you would solve these issues in JavaScript I'm not taking you seriously.
The web API offers an elegant separation of content, style and logic and these examples are just stuffing everything into logic. Don't do this
Separation of HTML/CSS/JS doesn't always mean separation of concerns. Every application has a different definition of a "concern", and if it doesn't align with the separation between languages, you don't get decoupled code, you intensify the symptoms of tight coupling.
hyperscript[0]
hyperscript[1]
hyperscript[2]
hyperapp[3]
[0]: https://github.com/hyperhype/hyperscript
[1]: https://cycle.js.org/api/dom.html#api-h
[2]: https://github.com/vuejs/babel-plugin-transform-vue-jsx/issu...
I mentioned this before[0] but it seems the author is committed to the name, despite the potential confusion downsides </shrug>
Since the author is here, I’d like to take the opportunity to suggest they change it.
If the author is really trying to be a better jQuery without long chains of callbacks, then I'd like to see an example that shows exactly that. Show us an AJAX call that GETs data, add elements to the DOM based on that data, then binds events to those elements that call some existing functions. Maybe an example fetching data to build a draggable/droppable list with separate handlers for click vs. drag, or something along those lines?
<button class='btn primary' _="on click fetch /clickedMessage
put the result into me
wait 2s
put 'Click Me!' into me">
Click Me!
</button>
More here: https://hyperscript.org/docs/I think it's quite natural for there to be large gaps in functionality provided: it looks like a rather young and unpopular project, so the additional code needed to handle more situations from within the language still needs to get written. jQuery also didn't have a whole universe of plugins from day 1, but was useful enough anyway. Not saying this project has a chance to become another jquery, just that it too can be useful even in a far-from-complete state.
[1] https://github.com/bigskysoftware/_hyperscript/blob/master/s...
Wrt. formatting the response, I'm experimenting with a hyperscript template language [1]. However, we don't yet have a design for imperatively building DOM trees (other than just doing it the same way you would in JS).
[0] https://htmx.org
As far as I can tell, where it falls somewhat short is in template dynamism, e.g. keyed arrays in React (which entails that drag/drop might also potentially be tricky), fractal structures like generating HN comment trees from JSON (vue, for example, used to have perf issues in the early days in this area due to recursive-descent rendering instead of batching), etc.
It seems to dabble a bit into normal control flow structures[1] but once you're at that level of language complexity, I'd probably prefer using a more established framework over this natural language DSL. The HN comment tree use case, for example, doesn't seem very easy to optimize if it turns out to be implemented in terms of reading the DOM to trigger subtemplate creation.
I think it's certainly interesting that there's now interest in alternatives to compiled stacks (e.g. React, due to JSX, anything using Typescript, etc) that are mindful of compile time creep and aim to bring development speed back into the limelight, but I fear that projects like this might be making the original "mistake" of shoving the perf pitfalls back to the runtime (where the users care). Personally, I think the future is going to be better compiler infrastructure e.g. esbuild, swc and the projects built on top of them (vite, etc).
I've been working with it and, while it does have a few rough-spots occasionally...in addition to how fast it is, I love how easy it is to work with and write unique behavior for as necessary.
I never really fully digested Webpack, and I think part of that was because of the way it pushed its plugin ecosystem. By contrast, esbuild's plugin system is super easy to understand and placed front and center with the ecosystem off to one side, so if you write a esbuild script (in js OR Go), it's really easy to just write code to do what you want to have done instead of hoping that a bunch of third-party plugins can work together in the way that you want.
Anway, I haven't used swc, but I agree with your assessment. I look at all of the projects that are being worked in that rely on esbuild and swc and they all point to really pleasant development experiences that also have the capability of producing performant code.
What I haven't looked at recently is some of the other language specific pipelines. Is anyone here using non-TypeScript compilers to target JavaScript (like Kotlin, Scala, ClosureScript, ReasonML/Bucklescript) that could speak to the dev experience of the toolchain in 2021, as well as the resulting performance of the js? I'm pretty happy with TypeScript and get happier with each new release, but I'm also really interested in hearing other perspectives about language toolchains targeting js, and what folks are building with them.
> While the underscore (_) attribute is where the hyperscript runtime looks for hyperscript on an element by default, you may also use script or data-script attribute, or configure a different attribute name if you don't like any of those.
_hyperscript:
<button _="on click fetch /clickedMessage/ then put the result into #fetch-target-3">
HyperTalk (https://en.wikipedia.org/wiki/HyperTalk): put the value of card field "typehere" into theValueYes, there's Facebook with React and whatnot, but for every shared news article there you'll find an URL which leads to a WP site with jQuery added for interactivity.
Turns out static pages with JS on top can be even worse than badly done SPAs - especially when the server infrastructure is lacking and a single request takes a significant amount of time.
On the one hand you have a shared-nothing architecture that serves HTML and can enjoy varying forms of caching.
On the other you have an application that still depends on a server, but replaces all of that simplicity with a stateful client-server architecture that requires _more_ infra to manage, at a greater expense.
Just about every programming language has also a web framework implemented in it, so if you want to create a full-stack web app, the range of options is just dazzling, which results in a highly fragmented ecosystem.
Meanwhile on the front-end there's essentially one language(with different flavours) and 3-4 leading frameworks, so once a developer has these covered, they can be hired to do anything in this part of the stack.
The overall result is that it's easier to scale work if you offload it to the front-end, because by the time you found your <insert highly specific language/framework combination>, your front-end developers would have done most of the work twice over.
There are many more reasons why you would want a SPA instead of a full-stack app, but this is one of the strongest.
The same folks who fail to understand that and just recklessly add dependencies aren't going to craft a nice static HTML site with smart, minimal, performant JS; they just don't have the chops for clean solutions. The medium barely matters.
I was there when AngularJS was still this revolutionary new framework and back then any sufficiently sophisticated form would eventually become unmaintainable.
Can you expand on this?
I have created entire applications which are operating off of a single React context, and then also created some generic components which themselves expose a provider to their managed subtree. I have not faced any issues or "coupling" between these layers; I just pass props from the top-level context to the top of another subtree / component, and it works as I would expect.
I don't rely super heavily on derived state, but I find useEffect and useMemo to both be quite simple and effective when I need side effects or to memoize a piece of derived state to prevent throttling.
What situations am I missing that introduce these issues you talk about? How does Redux solve them more cleanly?
Now I do share the concern that it might not be the best approach for really complex stateful applications but we will have to see how it scales once we see the first real world uses of it. It is good to know that the is always the escape of hatch of simply using plain vanilla js. Sure it wont replace React/Svelte/Elm level of use cases but I guess that is not the goal.
Also really dig the fresh take on a human friendly syntax. Sure there are pitfalls with that but hey for this kind of DSL it might work out. Nice to see people trying out non mainstream approaches.
My immediate reaction was "Oh, web Cobol".
Edit: By the downvotes, I'm guessing people think it was a lazy attempt to poke fun. It's not though :) Cobol has a very repeated VERB->NOUN->ADVERB->ETC sentence style pattern that's very similar to what's in that snippet of _hyperscript above. Like:
DIVIDE NUMA BY NUMB GIVING RES-DIV
PERFORM VARYING LoopCount FROM 1 BY 1 UNTIL LoopCount GREATER THAN 4
And so on...
Every command has an initial verb, which makes parsing easier (both by computer, and hopefully by people). Just for fun, here are your examples in hyperscript:
get numA / numB then put it into resDiv
-- or simply
set resDiv to numA / numB
repeat 5 times index loopCount
log loopCount
endAdd a CSS class "hide-animated" tied to your transition, add a transition end listener on the document (not once, perpemtual), with evt => evt.target.remove()
(That's right, ".remove()", not "element.parentNode.removeChild(element)". Actually looking up modern JS is a good idea if you're going to knock it).
And then the only other JS thing you need for your element is a click listener that adds "classList.add(`hide-animated`)".
Is "addEventListener(`click`, evt => evt.target.remove())" overly verbose and cumbersome? Sure is, I have no love for it, but if you want to show that your library is better than vanilla JS, show vanilla JS, not code from 20 years ago.
I'd like to be as fair as possible in these comparisons.
My guess is that most of us have Babel in the mix of a production deployment, in which case I think the “20 year old code isn’t vanilla” loses some of it’s effect.
0: https://www.statista.com/statistics/272697/market-share-desk...
But yeah, I absolutely push modern JS out to prod, because our demongraphic is very much nowhere near 2.5% - our actual number for IE users is 0.4%, for all versions of IE combined (just IE11 would be 0.2%). Even Samsung's browser ("Samsung has a browser?") drives four times as much traffic as all version of IE combined.
IE use has properly died down ever since Microsoft themselves started making sure folks weren't using it anymore. And they really don't want you to use internet explorer: Windows hasn't had IE set as default browser for years now. It comes bundled with Windows 10, sure, and IE11's EOL is contractually tied to the Windows 10 EOL, sure, but Microsoft is working damn hard to make sure you're on Edge instead.
If you have to support IE, because you have a target demographic that for whatever reason is forced into IE use, then sure: roll whatever code you need. But if you're developing for the current web landscape: no, IE is not your concern anymore.
Wrt. transitions:
> use CSS and a transition listener on the JS side
Now you need to have 3 files open in your editor simply to be able to say "this button fades away in half a second when clicked". The onclick is used to somewhat alleviate this (See "Locality of Behavior" [1]).
Separation of concerns is important, but different applications have different definitions of what constitutes a "concern". If one expects that the hiding animation will be changed by designers, one would likely use CSS as you suggested. The nice thing about `settle` in hyperscript (as opposed to just listening for a transitionend) is that you can switch from a transition to a keyframe animation and it will still work with no changes.
> add a transition end listener on the document
Wouldn't this also detect non-disappearing transitions (say, an element expanding or changing color)?
Are you saying that isn't already the case? Do you inline all your CSS and JS directly? Because that'd be super weird.
> Wouldn't this also detect non-disappearing transitions (say, an element expanding or changing color)?
The event comes with information about which class the transition was for. So: sure, but if you have lots of different transitions we're no longer dealing with simple code that we can write simple "vanilla vs. jquery vs. your lib" code for?
[1] http://www.gigamonkeys.com/book/loop-for-black-belts.html
> It is based on an older and somewhat obscure (today) family of programming languages that originated in HyperTalk...
Still, I oughta try this to make a proper judgement.
_hyperscript is far more speculative than htmx, so if you don't need it, don't use it just to use it.
But if there are places where a bit of light scripting might help, it's maybe worth a try.
If you'd like to play around, open the console and try calling the `_hyperscript` function:
_hyperscript(`get the first <button/>
transition its background-color to 'red' over 2s
log ':]'
`)https://hyperscript.org/playground/
Still a work in progress, but you can play around w/ the language.
This VanillaJS example is just plain silly. I've never seen anyone set styles and call requestAnimationFrame & do all that in an inline onClick handler. I mean html elements have a `style` attribute, why would you set `transition` in a click handler?
The vanilla example should look more like the jQuery one, with the the code apart from the markup & referencing the element by id or class, attaching a handler with addEventListener.
Your will still compare favorably, and this a slightly less "intentionally ugly" way to write the code.
I love the natural language approach and simplicity.
I'm definitely going to block off some time to play with this.
- Svelte
- htmlx
- lit-html and perhaps also lit-element
Some of the syntax give me unfortunate flashbacks to AppleScript. Expressions like "the location of window" looks cool at first glance, but in reality "window.location" is easier to both read and write, especially when you start to compose more complex expressions.
No, it's not easier to read. Really. You think it is, but that's only because you're used to it. If you take a step back and look at the "window.location" expression objectively, while forgetting all that you know about programming (but retaining your knowledge of English), you won't be able to tell what is it about, not with any kind of certainty. Or, if you have experience with some other programming languages, you might read it as "a composition of function window and function location". On the other hand, "the location of window", even if it's not 100% correct English, tells you all that you need to know to understand what is happening.
It is easier to write, but only because it has less characters. The docs state pretty clearly that they are optimizing for ease of reading, not writing, so this is expected.
For myself, I can't parse them without my brain trying to read it as actual English. Having programming languages look distinctly different from human communication keeps my mental overhead low. I find Applescript impossible to use.
NLP also has a major issue with rapid comprehension. It's far harder to see the structure of code at a glance if everything is just keywords. While this is an issue with every type of communication, NLP has a significantly lower upper limit to almost every other language I work in. SQL is a middle ground. If you format it properly, it's really easy to scan and see what's happening. Applescript? Not so much.
I am adding things like CSS literals:
https://hyperscript.org/expressions/#css
in the hope that we can increase the expressiveness (and distinctness between different elements) that we don't fall into the wall-of-text nature of applescript.
It's a speculative project, we'll see how it works out.
The fallacy of AppleScript is to think that a syntax which looks familiar on the surface makes the semantics esier to understand. But since the underlying semantics are those of a programming language, not human-to-human communication, the syntax obscures the meaning.
So to me "easier to read" and "simpler to use" both depends on the ergonomics of the programming model and the syntax used.
set the location of the window to 'https://hyperscript.org`I could see this being a joy to work with though if a well determined usage pattern emerges where you have something like a `some_page_template.html` file open next to a `some_page_hyperscript.hy` where you define all the locally scoped functionality and the two are combined by your webserver template engine.
It wouldn't be very hard to set up, but having a de-facto way to structure and organize things it would likely help with adoption and prevent new users from being architechture astronauts.
Kuddos to the author looks cool but personally I wouldn't be able to make a single thing work.
I'm confident the examples given can be simplified as well. The vanilla JS and jQuery examples are not equivalent for example, the vanilla one is (intentionally?) inline JS whereas the jquery one separates it out.
It also doesn't use ES6 arrow functions (neither vanilla nor native), which would remove the need to rebind `this` to `self`.
The vanilla one also sets style via JS, which isn't how you should do things. Transitions can be set in CSS beforehand. The one used sets the animation to 'all' properties as well, instead of just 'opacity' which is the only property changed.
TL;DR the article is making vanilla look more difficult than it is. The jquery example seems lifted off of Stack Overflow.
on click from #some-btn
log 'The button was clicked'
end
However, we really lean towards directly embedding the scripts on HTML elements for Locality of Behaviour https://htmx.org/essays/locality-of-behaviour/See also https://changelog.com/jsparty/171
Possibly for smaller personal projects, but maybe that is what the library is for.
Is there some browser extension of some sorts or some IDE-like tool?
How?
https://hyperscript.org/docs/#event-control-flow
Coupled with an async command:
https://hyperscript.org/commands/async/
The language is very young, so we are still building out the docs and examples.
For something like htmx, where there is already a rich event model around requests, I would instead listen for htmx:beforeRequest and htmx:afterRequest events:
https://htmx.org/reference/#events
And use that event-driven control flow technique to smoothly end the animation.