NHacker Next
  • new
  • past
  • show
  • ask
  • show
  • jobs
  • submit
Proposal for Standardized JSX (vanillajsx.com)
pwdisswordfishz 12 hours ago [-]
> There has been no push for JSX standardization.

https://facebook.github.io/jsx/ is a mirage, apparently.

90s_dev 12 hours ago [-]
> *It's NOT a proposal to incorporate JSX into the ECMAScript spec itself.* It's intended to be used by various preprocessors (transpilers) to transform these tokens into standard ECMAScript.

(Emphasis theirs.)

elehack 7 hours ago [-]
I like this — JSX is a little annoying to work with outside the major implementations.

If this existed, I might not have found the need to make my little Hyperstatic library (https://jsr.io/@mdekstrand/hyperstatic).

90s_dev 3 hours ago [-]
> JSX is a little annoying to work with outside the major implementations

There are dozens of us, dozens!

aatd86 15 hours ago [-]
because react decided to return JSX like element syntax instead of being simply a function returning a dom element doesn't mean that this should be standardized.
afavour 9 hours ago [-]
The argument to standardize it isn't really "because React does it", it's "because a ton of developers find it really useful". That seems kind of undeniable to me, even as someone that dislikes a lot of React.
aatd86 4 hours ago [-]
I don't think that it is sound to incorporate a DSL that imitates html only approximately into a language. That should remain an external library at best.

And that's irrespectively of my view on jsx, the latter which I find non ergonomic and confusing. That many people are being force fed it to the point of familiarity does not mean that it is the best DX.

we went from (html + js> to html in js and js in html. Quite very confusing to me. Knotty (naughty) complexity pun intended.

It's more akin to stockolm syndrom to not improve on the statu quo at this point.

90s_dev 3 hours ago [-]
> I don't think that it is sound to incorporate a DSL that imitates html only approximately into a language.

The beauty of JSX is that it's not HTML, it's much more generic.

> And that's irrespectively of my view on jsx, the latter which I find non ergonomic and confusing.

You're in the very, very small minority here. JSX is very clear and intuitive and natural and ergonomic and lovely to most of us.

And I don't even like React!

Compare:

Without JSX: https://github.com/sdegutis/sys32.90s.dev/blob/26bcb088a3df6...

With JSX: https://github.com/sdegutis/os.90s.dev/blob/cc7310633d9ab186...

aatd86 2 hours ago [-]
To provide a quick feedback, I believe the 'without jsx' version could have been improved. One advantage it already has is that it doesn't need the repetition of /closing> elements.

But it doesn't go far enough in terms of function composition to pass arguments. The signature (that resembles react.createElement I guess) is too cumbersome.

That creates a succession of braces and comma which is unfortunate. Just to specify some object attributes. That could be easily a function Attr().

We have higher order functions easily in javascript. We should make use of it.

That eliminates html looking jsx since we just use functions. That's less confusing than pseudo html syntax.

90s_dev 1 hours ago [-]
Show me what that code would look like if it was done better.
aatd86 59 minutes ago [-]
Maybe you could try with hyperscript syntax for react(which I've just found the existence of).

https://github.com/hyperhype/hyperscript

https://github.com/mlmorg/react-hyperscript

which might be actually similar except for the dollar sign which adds some noise.

But some of your prop/attr setting would be inner function/methods instead of being passed as an array. That would shorten some lines.

> Show me what that code would look like if it was done better

I'm definitely not going to try to provide an example if you do not offer the courtesy of a smaller representative example though.

By the way, why is $(Label,...) not simply Label()? That could be a function.

90s_dev 39 minutes ago [-]
Eventually I got new Label() working, but Label() by itself isn't possible while keeping them as ES6 classes.

After a while of managing commas, you just begin to long for JSX again. Hyperscript wouldn't solve that.

afavour 4 hours ago [-]
> It's more akin to stockolm syndrom to not improve on the statu quo at this point.

Describing something very popular as “Stockholm syndrome” because you don’t like it isn’t logical at all.

And it’s easy to say that but I think it's incumbent on you to propose something better if you do.

"No, not JSX. Something better than that." ...but what?

aatd86 2 hours ago [-]
I was far from the only one to not like it when it got introduced.

As I have explained somewhere else, plain function and method composition is clearer in my humble opinion.

silverwind 8 hours ago [-]
Yep, JSX is even supported in Vue and probably other tooling. This kind of adoption calls for standardization.
90s_dev 3 hours ago [-]
He's right, guys.
90s_dev 13 hours ago [-]
Given <foo bar={qux}>bla</foo>

React used to transform it into React.createElement("foo", { bar: qux }, "bla")

Now it transforms it into import _jsx from "react/jsx-runtime"; _jsx("foo", { bar: qux }, "bla")

My proposal transforms it into { [Symbol.for('jsx')]: 'foo', bar: qux, children: "bla" }

It's self-contained and generic, doesn't rely on auto-imports or globals, and doesn't have key collisions.

It's the only way I can imagine it ever being standardized.

aatd86 4 hours ago [-]
In my opinion, first sin of react is that createElement should be a method of a document at best.

There are a few things missing but jsx is sugar that complicates things for me.

Just teach people function composition. It's easier.

pwdisswordfishz 13 hours ago [-]
What does <foo children={qux}>bla</foo> do?
90s_dev 13 hours ago [-]
This is a known ambiguity in JSX, to the point where TypeScript gives this error:

> 'children' are specified twice. The attribute named 'children' will be overwritten. ts(2710)

pwdisswordfishz 13 hours ago [-]
No, that's an ambiguity in React. JSX defines only syntax.
90s_dev 12 hours ago [-]
True. Then can you suggest a standardized ECMAScript JSX proposal that doesn't turn this into a "children" key on an object? Would you just transform it into an array? ["foo", { bar: qux }, "baz"] ?
WorldMaker 11 hours ago [-]
That array does better match the current function parameters, so would be a simpler proposal to existing transpilers.
90s_dev 10 hours ago [-]
Yeah it seems fine. I wouldn't be strongly opposed to it. Standardization of either is better than nothing.
orta 7 hours ago [-]
There was some interesting work on standardising on "ESX" in the TC39 discourse that folks in the thread may want to follow: https://es.discourse.group/t/proposal-esx-as-core-js-feature...

Core docs: https://gist.github.com/WebReflection/2d64f34cf58daa812ec876...

90s_dev 13 hours ago [-]
Hi, I'm the guy who wrote this proposal.

tl;dr:

My proposal transforms <foo bar={qux}>bla</foo> into { [Symbol.for('jsx')]: 'foo', bar: qux, children: "bla" }

It's self-contained, generic, doesn't rely on imports or globals, and avoids tag key collisions. It's the only way I can imagine it ever being standardized.

I currently use JSX for:

* Creating custom GUI view objects in https://90s.dev/os/

* Using JSX as a convenient & composable string-builder in Node.js via https://immaculata.dev/ when generating all my sites at build-time e.g. https://github.com/sdegutis/immaculata.dev/blob/main/site/te...

* Using JSX to generate plain DOM objects in the browser in some of my sites like https://github.com/sdegutis/minigamemaker.com/blob/main/site...

WorldMaker 10 hours ago [-]
I think it is still useful as a function call syntax. There's a variety of data structures that people convert JSX to already, including direct-to-DOM. Choosing a blessed one seems harder than a function calling convention, and a function calling convention resembles other language things like tagged templates.

I agree that the current "auto-imports" to find that function are nonsense and far too React specific. But the current "global" approach isn't actually "require a global" it is "requires a variable in scope" so it works with "Bring-Your-Own-Import" just fine. We just need a better standard for what that BYOI function is called by default. `React.createElement` is obviously silly. I've been happy in my own projects standardizing on `jsx` as the function name. (It resembles the auto-imports, too, even if I still don't understand why React thought it needed an extra underscore.)

I think the biggest tweak that would be nice if we are also wishing for ponies would be a way to set that function per block of JSX like the way that you can tag a template. That would make it far easier than the current per-file or per-project configurations.

    jsx<foo bar={qux}><zoot>bla</zoot></foo>
That doesn't look terrible. Not great either. But I'm sure the big problem with it is that it makes the `jsx < foo` less than versus `jsx<foo />` tag parsing a lot harder.

ETA: New idea, what if it was a fake dot tag .< operator?

    jsx.<foo bar={qux}><zoot>bla</zoot></foo>
    react.<foo bar={qux}><zoot>bla</zoot></foo>
    snabbdom.<foo bar={qux}><zoot>bla</zoot></foo>
Maybe?
90s_dev 10 hours ago [-]
If it's just a variable in scope, you could do:

  if (condition) {
    // new scope
    const jsx = // ...
    return <foo/>
  }
In practice, "variable in scope" is essentially the same as "global in scope" and React used to require you to import 'react' at the top of every JSX file for this reason. Your solution is tantamount to just changing that to import jsx from 'react' but still requiring it explicitly.

The main problem with this is that it's non-trivial to make sure variables are in scope before/while loading a file, and they should be loaded on an as-needed basis instead of always, which is what inevitably ends up happening when you need React classic, you import React at the top of every HTML file. These problems seem to be what led to auto-imports.

I admit that my solution still does require you do something like import interpretJsx from 'something', and even further it requires you to manually call interpretJsx(<foo/>) which can be tedious and verbose.

The main benefit is that at least it becomes a standard. And besides, we probably won't need to call those functions everywhere, just at the top of a tree, like the same place you call React.render(root)

The main downside is lack of monomorphism, especially if you're passing an entire tree to interpretJsx(). I admit this is not solved by my proposal. But I still wanted to put the proposal out before smarter eyes than mine anyway.

WorldMaker 9 hours ago [-]
A problem with going straight to objects is you potentially create a lot of GC churn if the `interpretJsx()` converts it to a different data structure. Also because it is a tree structure, you are probably talking a recursive depth-first-search or other tree-walker algorithm that can easily blow up the stack while it works. If you are doing something Virtual DOM-like and evaluating lots of trees, that memory/GC and CPU churn compound quickly.

This is part of why JSX has always been function calls rather than a data structure to interpret: the recursion to walk the tree is flattened at "compile time".

I don't see why it is a problem you'd need to import your `jsx` function in every file that uses JSX syntax, but perhaps because that's how I've always preferred to use JSX, even with React. Explicit imports are better than implicit ones. If you use lit-html you have to import its `html` function everywhere to get html`` template literals to work. It's not a lot of overhead and it works well. You can add the auto-import smarts to your editor, to your snippet files and template files. Typescript already has a ton of auto-import suggestions as you write a file.

90s_dev 9 hours ago [-]
Yeah I guess you're right. This proposal has serious performance issues.

Still, I don't like the React-classic style, the React-autoimport style, or the hybrid that you're advocating for. None work be very ergonomic and require tooling to at least give you errors that you forgot an import, which defeats the purpose of standardizing it at that point.

silverwind 8 hours ago [-]
I hope a future standard will allow multiple elements in expression contexts without the need for fragments, or arrays, e.g.

    const els = <div/><div/>;
Compare to current ugly solutions:

    const els = <><div/><div/></>;
    const els = [<div/>, <div/>];
eyelidlessness 8 hours ago [-]
Maybe it’s ugly, that seems like a matter of personal taste. But it’s syntactically unambiguous which is valuable especially for a language which mixes expressions and statements in often very subtle ways. There are also other ambiguities to consider:

  const trailingIntetpolation = <><div/>{foo}</>;
  const leading = <>{foo}<div/></>;
  const bare = <>{foo}</>;
90s_dev 7 hours ago [-]
Sure and while we're at it why not support `const x = 3 5` also.
palmfacehn 16 hours ago [-]
I'm happy with <template> elements. No shade on JSX, but I prefer the abstraction of HTML, CSS and vanilla JS.
WorldMaker 10 hours ago [-]
Template elements don't have great Typescript type checking today. I've been very happy with both, writing things in TSX with deep type checking and then statically rendering them to Template tags.

[0] https://worldmaker.net/butterfloat/#/stamps

cluckindan 15 hours ago [-]
I consider the slots-based approach clunky and prefer implementing my own templating system with simple functions returning HTML in template strings.
palmfacehn 14 hours ago [-]
I did this in the past, but I found that templates simplified the process. The same functions I use to populate/update elements can be reused on existing elements and newly cloned template elements. It can be done in JS by returning strings of unpopulated elements, but then my display is further mixed with logic.

I like to create the HTML and CSS as I'd like it with test data, then just wrap that with <template> tags. Easy to preview without triggering function calls or pasting it into code.

Probably not important, but as I recall I think there was some minor overhead in translating from a JS String to an Element.

pwdisswordfishz 12 hours ago [-]
Even better – return a DocumentFragment: https://stackoverflow.com/a/79233706

I wish this were available natively.

HelloNurse 14 hours ago [-]
Can you recommend examples and tutorials of happy <template> usage, showing advantages over building values for innerHTML etc. as text from strings and template string literals?
palmfacehn 14 hours ago [-]
HelloNurse 12 hours ago [-]
This MDN page is where I first discovered the <template> element, and I wasn't very impressed: verbosely operating on one textContent at a time, using ordinal indices into very untyped querySelectorAll results, apparently gratuitous complications with document fragments and shadow DOM.
90s_dev 13 hours ago [-]
I made this proposal because JSX is more generally useful than generating HTML. You can use it for configuration, or views for other GUIs like I do in https://90s.dev/os/ or to describe basically any kind of tree.
gherkinnn 7 hours ago [-]
Now that I am paid to occasionally write templates in languages other than JSX, I do miss it so much. All the ERBs and ng-for s and handlebars of this world don't remotely come close.
Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact
Rendered at 00:38:42 GMT+0000 (Coordinated Universal Time) with Vercel.