Using Rescript with Preact?

Just got interested in rescript.

I would definitely love to have support for preact to reduce my bundle size and improving performance. In the vast majority of cases I can use it as a drop in replacement, and even when using react itself preact signals are almost always a better abstraction than react hooks and contexts.

I’m using Rescript + Preact at work and we did the alias thing for react->preact. I just followed preact’s guide to aliasing on their documentation

Seems to have worked with no other differences on the Rescript side, though haven’t tried signals yet. Reducers are too easy in rescript

and it’s probably confusing having React instead of Preact.

// bindings/Preact.res
include React

:stuck_out_tongue:

6 Likes

Okay, what do you do to make it alias in Rescripts build system? Is there some config file where you tell it to grab Preact instead of react ? I’m looking at the interop between rescript and javascript build systems right now.

It depends on which build system you’re using, the preact docs have a specific section with the different methods.

Aliasing React to Preact | Preact: Fast 3kb React alternative with the same ES6 API. Components & Virtual DOM. (preactjs.com)

Yes, I am familiar with that, thank you. I am asking about the rescript side of things. Assume Vite/Webpack if it makes the question specific enough.

Does setting up aliases in webpack make rescript just automatically import the aliased library? Does rescript integrate easily with webpack? Or is that the wrong question to ask because rescript happens to cover something without involving the build system? Etc etc

The point of setting up aliases is that it should ‘just work’ without any other effort. So it may be worth your while to just try it out and report your findings.

1 Like

I haven’t tried it with webpack, but I have used rescript + preact with vite as the build system using the aliases as described in the preact docs. It was just a toy project, not production, but it seemed to work fine.

3 Likes

FYI this is now possible since v11.1:

1 Like

I have a project I’m working on using Preact, Deno, and Fresh. it’s pretty easy to set up.

1 Like

Would you be able to share a pre-configured deno-preact-fresh-rescript application starter on github?

1 Like

It’s on my list! I’ll post here once I can get something cleaned up.

I pushed up some Fresh bindings to NPM and converted the starter Fresh app to ReScript: GitHub - jderochervlk/rescript-fresh-example: An example application using @jvlk/rescript-fresh

I’m going to keep working on it, but I wanted to share what I have so far.

3 Likes

I’m using ReScript 11.1+ and just started a project through create-rescript-app but I want to switch to Preact over React but not sure where to start yet. Anyone have an example or guidance?

I have bindings here in my Fresh repo for Preact: rescript-fresh/bindings/Preact.res at main · jderochervlk/rescript-fresh · GitHub

You can copy those over to your project and set the JSX module to “preact”. As for getting started with swapping over you should be able to follow the Preact getting started guid: Getting Started – Preact Guide

Thanks!

Last night I stumbled upon GitHub - ajaxsys/rescript-preact: Test rescript with preact which covered the changes I needed to make and has similar bindings to yours (maybe they borrowed it from you?)

Took a stab at creating the bindings for Signals, seems to be working but I haven’t used all APIs yet:

module Signal = {
  type t<'value> = {
    mutable value: 'value
  }

  @module("@preact/signals")
  external make: 'a => t<'a> = "signal"

  // @set external set: (t<'a>, 'a) => unit = "value"

  @module("@preact/signals")
  external effect: (@uncurry (unit => unit)) => (@uncurry unit => unit) = "effect"

  @module("@preact/signals")
  external computed: (@uncurry (unit => 'a)) => t<'a> = "computed"

  @module("@preact/signals")
  external batch: (@uncurry (unit => unit)) => 'any = "batch"

  @module("@preact/signals")
  external useSignal: 'a => t<'a> = "useSignal"

  @module("@preact/signals")
  external useComputed: (@uncurry (unit => 'a)) => t<'a> = "useComputed"
}

Trying to write a setter function but my ReScript is really rusty these days :sweat_smile:

1 Like

It’s older than my work, so they didn’t copy from me, but it’s a similar process so the results should be similar.

I’ve been using my own bindings for Signals, but this exists and might work for you: GitHub - ashton/rescript-preact-signals

1 Like

My mistake, should have checked the timestamps. Probably wouldn’t hurt for me to compare against yours and see if anything is different.

As for Signals, I did see that but it seemed aimed at a react specific version and wasn’t feeling the way it was organized. Plus I wanted to relearn how to create bindings, which helped me understand the Signal APIs better :man_shrugging:

1 Like

You could indeed use either a mutable field or a @set binding to create a setter function, just use whatever feels the more natural!

1 Like

I 100% prefer to write my own bindings. I also feel like it helps me understand the source library better, and I get to come up with a solution that matches how I want to use it.

Here’s what I have for signal bindings: rescript-fresh/bindings/Signal.res at main · jderochervlk/rescript-fresh · GitHub

1 Like

Totally fair! I got the mutable version working, but figured it wouldn’t hurt to have a get and set function to play nicely with the chaining → operator.

I did get those working with:

@set external set: (t<'a>, 'a) => unit = "value"
@get external get: (t<'a>) => 'a = "value"
@send external peek: t<'a> => 'a = "peek"
3 Likes