-
Notifications
You must be signed in to change notification settings - Fork 0
Assessment: native solidJS support in rescript #14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Hi @zth, thanks! currently (with version v3) the The first one is the mentioned "preserve" mode that needs to be implemented by the compiler. Here is the corresponding ticket for rescript: rescript-lang/syntax#539 The second one is that the // rescript
module Comp = {
@react.component
let make = (~text) => {
<div> {React.string(text)} </div>
}
}
// resulting javascript
function Playground$Comp(Props) {
var text = Props.text;
return React.createElement("div", undefined, text);
} I just checked the playground with the new version v4 and it seems that the problem with props reassignment is no longer present. So that's good news. Now we only really need the JSX preserve mode. If I remember correctly, they also introduced props spread with the new version. I have to check out, how this is implemented too. Hopefully this is not an issue. |
I made some more tests and I found some scenarios, where the problem with the prob reassignment is still present. In the older version, all props have been reassigned (i.e. // rescript
module TwoProps = {
@react.component
let make = (~className, ~height) => {
<div className height>
<div className height />
</div>
}
}
// resulting javascript
function Playground$TwoProps(props) {
var height = props.height;
var className = props.className;
return JsxRuntime.jsx("div", {
children: JsxRuntime.jsx("div", {
className: className,
height: height
}),
className: className,
height: height
});
} From a solidjs perspective this is problematic, since this behaviour would break reactivity of props. It would be interesting to know why the compiler behaviour changed for "single-use-props", but not in every case. The current props handling would result in minimally shorter code. But that is such a small optimisation that perhaps it would be worth dropping it, in favour of supporting reactive libraries like solidjs. |
I found an additional case where the behaviour of the rescript compiler interferes with the reactivity model of solidJS. When a thunk (function with no argument) returns an optional value (option<>), and is accessed inside a switch statement, the compiler will store the result of that function inside a variable and only used the variable afterwards: I'm using a slightly simplified version of @module("solid-js")
external createSignal:'value => (unit => 'value) = "createSignal"
@react.component
let make = () => {
let maybe = createSignal(Some("option"))
<div>
{
switch maybe() {
| Some(m) => m
| _ => ""
}->React.string
}
</div>
} And here the compiled output: function Playground(props) {
var partial_arg = "option";
var maybe = function (param) {
return SolidJs.createSignal(partial_arg);
};
var m = Curry._1(maybe, undefined);
return JsxRuntime.jsx("div", {
children: m !== undefined ? m : ""
});
} The problematic part is: var m = Curry._1(maybe, undefined); The variable is assigned outside the tracking scope of solidJS and as a result, the component never receives any updates. |
I found another potential issue with the ReScript compiler behaviour and solidJS. The compiler produces slightly different results for a manually created component. The major part being, that the variable name of the custom component is lowercase. Here is a Playground example with the full code: Playground The relevant parts: // custom component
module M1 = {
type props<'msg> = {msg: 'msg}
let make = props => React.string(props.msg)
}
// standard component
module M2 = {
@react.component
let make = (~msg) => React.string(msg)
} And the resulting JavaScript // custom component
function make(props) {
return props.msg;
}
// standard component created with @react.component
function Playground$M2(props) {
return props.msg;
} Those snippets, while functionally identical will be compiled differently in solidJS. After babel transform the code looks like this (again, only the relevant part): function Playground(props) {
return <><make msg="hi" /><Playground$M2 msg="hi" /></>;
} And this will be transformed by solidJS like this: const _tmpl$ = /*#__PURE__*/_$template(`<make msg="hi"></make>`, 2);
function Playground(props) {
return [_tmpl$.cloneNode(true), _$createComponent(Playground$M2, {
msg: "hi"
})];
} Basically the custom component will be turned into a template and only the standard component will be converted into an actual solid component. This is a problem for the current solution with the babel transform. So when implementing the JSX preserve mode it is important to make sure, that component names always start with a capital letter. |
@Fattafatta Sorry for ping. What do you think about compatibility today? |
ReScript v12 will ship with preserve mode, which means that the JSX part of the issues of using Solid should be solved. Here's some investigation for what might now work and/or might still be broken for SolidJS to work flawlessly. Props destructuring and component names - ✅ ?I haven't tested thoroughly, but the type props = {name: string}
module SolidComponent = {
@jsx.componentWithProps(: props)
let make = props => {
<div> {React.string(props.name)} </div>
}
} Ignore the function Playground$SolidComponent(props) {
return JsxRuntime.jsx("div", {
children: props.name
});
} The Intermediate values created when switching - ✅ ?
Isn't this the same in TypeScript? The equivalent in TS would be using a ternary, but you'd still need to call The ReScript equivalent would be that you'd call Seems SolidJS is proposing using Summing upSumming this up, I think we should have what we need to make this work in v12...? You'll need to follow a few principles to not make this break. Most of them are the same in TS, but some are ReScript specific. Enforcing those principles is probably something we can look at doing centrally for Solid if it proves to be something people want to use. I guess the next step would be to try SolidJS again in 2025, with v12 preserve mode, and see if it works now in practice. |
I tried this awhile ago. I remember there were problems with gentype making tsx files that broke reactivity. If gentype creates .d.ts codeless output that problem would go away. |
Just wanted to say that this is a cool project!
I'm wondering, could you at some point do a renewed assessment of what'd be needed from the ReScript side to support SolidJS more "natively", now with JSX v4 etc released?
I understand we need a "preserve" mode for JSX. Is there more things needed, like swapping out JSX factory functions etc in a better way? And if so, has that been (partly) solved by JSX v4?
I'm very interested in what we can do to make SolidJS and ReScript a great combination. It feels like they fit each other quite well.
The text was updated successfully, but these errors were encountered: