In javascript, <span>Hello world!</span> is a jsx value specifying a span element with a text node as a child; <span>Hello {place}!<span> interpolates a variable into that text node.
In rescript, <span>Hello world!</span> is a syntax error, and <span>greeting</span> works as long as greeting is a variable containing a React.element. This reversal would maybe make sense to me if I could also do <span>toGreeting(place)</span> or some other expression, but it seems the only thing allowable in that position without enclosing braces is a bare symbol.
This makes me wonder why the jsx syntax has this variation in rescript compared to javascript. What motivates this? I don’t think it’s some demand of the type system, since as far as I can think of, text nodes would trivially compile to React.strings. I also can’t think how it could be problematic syntactically.
For me, one of the advantages of jsx/HTMl templating is being able to write things like <span>This is an <em>important</em> message</span>, whereas in Elm, Halogen, or any other framework where VDOM values are built with regular function calls, you have the additional annoyance of chopping it up into text nodes and an em element. This same annoyance comes up in rescript’s jsx where I have to do <span>{React.string("This is an ")}<em>{React.string("important")}</em>{React.string(" message")}</span>, thinking very carefully about the spacing in the strings.
No answers from me but its really always baffled me that JSX, which is designed to make HTML in code much more convenient, takes a turn for the worse in rescript, and makes the simple string a syntax nightmare. Its my opinion that half the people from the JS/TS world, interested in rescript, take one look at this and run away.
This is because things can only ever be of 1 type in ReScript.
If you look at JSX as a function you can think of it like this:
// jsx
<div>hello</div>
// function div("hello")
// jsx
<div>42</div>
// function div(42)
JavaScript and TypeScript are fine with string | number | null | undefined | React.element, but in ReScript a child can only be React.element, which means we need a function to convert a string to a React.element.
It might seem weird at first, but you get used to it very quickly especially if you do it with a pipe operator.
For one of my recent projects I have been using a markdown library to handle things like bold, italics, etc…
// nose.res
let intro = `
# Nose
Before you take a sip put your nose into the glass.
What do you smell?
`
@react.component
let make = () => {
<main>
<Markdown> intro </Markdown>
</main>
}
But in html, everything between tags IS a string. If you type it in your editor between tags, it already is a string. And then the browser displays it as a string, its only rescript that is pretending it could be something else. JSX is already a huge heap of sugar, I don’t see any reason it just cant treat anything between tags as a string by default.
Some type of coercion here would be nice. I personally have adjusted to it, but @kswope makes a good point that this is weird to people coming from JS, which is our target audience.
I understand the confusion coming from JavaScript, but I still find it odd that people consider it such a sore point. In any serious app you would need to support multiple languages, which means you need translation infrastructure, which means you will never use raw strings in your app anyway. And sure, toy projects are what people would typically start out with and experience first, but I’d rather have the language optimized for serious apps than toy projects.
Or maybe single-language apps really are a lot more prevalent than I think they are…
But I don’t think that it’s impossible to make typesafe. For example we already have template literals where you can use ${} to embed a string. Isn’t it pretty much the same case, but instead of ${} we have {} and the embeded type is React.element?
This. Even if you start with React.strings (or some shorter aliases) everywhere, they’re much easier to replace with some localization helper than just raw “html-like” strings.
WTH, You just called every web app I’ve worked on or built in the last 20+ years a toy project, even though they make money or were for major corporations.
This. Even if you start with React.strings (or some shorter aliases) everywhere, they’re much easier to replace with some localization helper than just raw “html-like” strings.
I’d safely bet that most apps are not some international success stories (or swiss) but internal corporate apps or b2b apps that have no use of i18n. Then there are apps that are targeted to a certain nationality or region that have no use of i18n. I’d say i18n is the rare exception for the totality of web apps and shouldn’t be the rational for a hassle for the majority of web developers.
Even if something isn’t localized text and content for anything I’ve worked on comes from a CMS, or in some cases a JSON file. I’ve rarely hardcoded text.
The app I am working on now uses markdown for all of the content.
I too work on a lot of internal company tools and we hardcode our strings, and I also wish I didn’t need to use React.string
This is because things can only ever be of 1 type in ReScript.
If the react compiler can convert <div> into functions and correctly parse the types of <div className> safely, can it also be smart enough to figure out that anything between tags not inside a {} is a React.string? Even if you still needed to convert non strings this would be a huge improvement on DX:
let counter = (
<div>
You've clicked it {React.int(count)} times!
</div>
)
This exactly. As far as I can tell, this is a single radical change which Rescript made to the JSX syntax, and to me it looks like nothing but a footgun.
From this thread it sounds like the majority opinion is in agreement.
For one of my recent projects I have been using a markdown library to handle things like bold, italics, etc…
That’s what I’ve had to do in the past when using Elm, but that’s precisely why I like JSX, because I don’t have to go looking for third-party solutions to formatting large blocks of text, and I don’t have to give the client extra work parsing and rendering the markdown.
In any serious app you would need to support multiple languages
In my workplace we have a b2b product with a strong customer base, which has been evolving for 20 years, and >3 million LoC all-in-all, and we’re just starting to think about i18n. I think there is a huge gulf between “toy project” and “requires i18n” you’re missing.
I see it as a small price to pay to completely eliminate “Objects Are Not Valid as a React Child” and preventing other runtime errors at compile time. My experience from onboarding multiple engineers to ReScript from 0 prior exposure is that it takes very little time to get used to.
It isn’t really a change to JSX syntax. All expressions inside JSX must be inside an expression container:
The example you have put looks more like a printer bug IMO than an indication the JSX PPX parser already handles JSX Children parsing to a union of JSXText / JSXExpressionContainer rather than the React.element type
I think measuring forum activity as a gauge of community consensus is a mistake–my experience has been people are busy building with ReScript and may not necessarily check in all the time.