[RFC] Generic JSX transform

There’s now an implemented RFC for a generic JSX transform (being able to use the built in JSX transform easier with anything not React). A generic JSX transform will allow us to for example plug in other JSX libs easily like Vue/Preact/Hyperons/Kittens and whatever else that might use JSX.

It’s not to be confused with JSX preserve mode, which is another functionality we eventually want to have where the JSX from ReScript is preserved in the JS output so other JS based tools can process the JSX.

Please have a look at the RFC and give any feedback you might have:

18 Likes

season-20-nbc-gif-by-the-voice

5 Likes

This is now released (as experimental) in 11.1.0-rc.1.

Relevant docs here: JSX | ReScript Language Manual

3 Likes

Nice! I’m gonna test out some Solidjs.

1 Like

Exactly at the right time :slight_smile:

Please report back how it went if you try it.

First things first: It’s working fine!

My first observations:

  1. I had to implement a DOM module instead of Elements.
  2. It’s not clear which methods have to be implemented. Some methods have to be implemented in the “root” jsx module and some in the DOM module. Some methos in both.

Well, I could copy all bindings from the docs, but I would like to understand when which method is used. It’s the same in the original react I guess (What is the difference between jsx and jsxs, what is the difference between react and reactDOM bindings, etc.).

What framework are you testing out? I’m trying to get this to work with Solid.js.

1 Like

A bunch of fixes related to this has landed and will be in the next rc for 11.1. About the docs - yes, a deeper dive into the specifics in the docs would be great, I agree.

1 Like

Tried solid, but had problems with some optimizing steps of rescript (destructuring of signals break their reactivity). Anyways I didn’t want to include babel or some other additional tools.

Then I played with vobyjs (like solid but without babel). Not finished (yet), but could work quite nice. You can see some small examples here: GitHub - dkirchhof/rescript-voby.

Right now, I’m trying out some own stuff. No external deps, no babel, no nothing.

Don’t know how far my journey will go. If I will finish my own lib, using voby or keep working with react :man_shrugging:

3 Likes

I’m trying to use email template frameworks in rescript, let’s see how it goes!

1 Like

For anyone interested in how the generic JSX transform looks in action, ResX (GitHub - zth/res-x: A ReScript framework for building server-driven web sites and applications. Use familiar tech like JSX and the component model from React, combined with simple server driven client side technologies like HTMX. Built on Bun and Vite.) is now integrated fully with the generic JSX transform. It uses a modified version of Hyperons to render JSX to HTML on the server.

  • It defines a module Hjsx which holds all JSX related things that the transform needs.
  • It also defined a module H that binds to the render-jsx-to-string functions.
  • You then configure rescript.json to use Hjsx as the module, and set up a few relevant open: https://github.com/zth/res-x/blob/main/demo/rescript.json

Viola, now you can use @jsx.component to create JSX components, and use Hjsx.string|int|array etc to render JSX elements.

Side note: It comes with its own custom DOM props with a few interesting bits of “magic” baked in, like HTMX props driven by variants and a custom mini fw for doing simple declarative DOM updates.

6 Likes

Hey,

I have a custom function which should create a jsx element

type options<'props> = {
  name: string,
  render: 'props => Jsx.element,
}

let makeWithProps = options => {
  ...
}
module TestComp = {
  type props = {message: string}

  let make = makeWithProps({
    name: "test-comp",
    render: props => <div> {JSX.string(props.message)} </div>,
  })
}

Now I would like to create components without props like this:

module TestComp2 = {
  let make = makeWithProps({
    name: "test-comp",
    render: () => <div/>,
  })
}

Unfortunately, the compiler complains about the props type (unit). Only records are allowed.

Empty record literal should be annotated or used in a record context.

My workaround is to define a second make function:

type empty = {}

let makeWithoutProps = (options: options<empty>) => {
 ...
}

Which is used like this:

module TestComp3 = {
  let make = makeWithoutProps({
    name: "test-comp",
    render: _ => <div/>,
  })
}

TLDR;
Is it possible to define JSX.elements with unit as props type?

I think you should use an empty record for such cases.