Skip to content

Commit d0d8514

Browse files
Add JSX section
1 parent 2d46678 commit d0d8514

File tree

1 file changed

+142
-1
lines changed

1 file changed

+142
-1
lines changed

docs/blog/2022/2022-05-31-Snake_Island_alpha.md

Lines changed: 142 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,149 @@ You can track the current progress for Dart compilation [here](https://github.co
5050

5151
## JSX
5252

53-
...
53+
Fable JS wasn't supposed to get any new feature with Snake Island, but at the last minute we've implemented support for yet another language or, more exactly, a language-in-a-language. [JSX](https://reactjs.org/docs/introducing-jsx.html) was introduced by the React team as a way to declare HTML-like UIs directly in JavaScript without the need of a template language. Although Fable has supported React from the start, it never used JSX. Instead it directly output the JS code generated by JSX templates. This made sense because for React JSX was only syntax sugar and this way we could save a compilation step.
54+
55+
However, given the popularity gained by JSX, there are now tools that take advantage of this compilation step to perform code analysis or other operations. Like [SolidJS](https://www.solidjs.com/) which uses JSX to analyze the dependency tree in your code and translate the declarative render functions into surgical imperative updates that don't need a Virtual DOM and are smaller and faster than equivalent React apps (while maintaining the same developer experience overall). We have already implemented a [Feliz](https://zaid-ajaj.github.io/Feliz/)-like API to create Solid apps with good results. For example, the following code:
56+
57+
```fsharp
58+
open Browser
59+
open Feliz.JSX
60+
open Fable.Core
61+
62+
[<JSX.Component>]
63+
let Counter() =
64+
let count, setCount = Solid.createSignal(0)
65+
let doubled() = count() * 2
66+
let quadrupled() = doubled() * 2
67+
68+
Html.fragment [
69+
Html.p $"{count()} * 2 = {doubled()}"
70+
Html.p $"{doubled()} * 2 = {quadrupled()}"
71+
Html.br []
72+
Html.button [
73+
Attr.className "button"
74+
Ev.onClick(fun _ -> count() + 1 |> setCount)
75+
Html.children [
76+
Html.text $"Click me!"
77+
]
78+
]
79+
]
80+
81+
Solid.render(Counter, document.getElementById("app-container"))
82+
```
83+
84+
Which looks like much of the current existing Feliz apps, will be translated by Fable to:
85+
86+
```js
87+
import { createSignal } from "solid-js";
88+
import { render } from "solid-js/web";
89+
90+
export function Counter() {
91+
const patternInput = createSignal(0);
92+
const setCount = patternInput[1];
93+
const count = patternInput[0];
94+
const doubled = () => (count() * 2);
95+
const quadrupled = () => (doubled() * 2);
96+
return <>
97+
<p>
98+
{`${count()} * 2 = ${doubled()}`}
99+
</p>
100+
<p>
101+
{`${doubled()} * 2 = ${quadrupled()}`}
102+
</p>
103+
<br></br>
104+
<button class="button"
105+
onClick={(_arg1) => {
106+
setCount(count() + 1);
107+
}}>
108+
Click me!
109+
</button>
110+
</>;
111+
}
112+
113+
render(() => <Counter></Counter>, document.getElementById("app-container"));
114+
```
115+
116+
Which in turn gets translated by Solid into something similar to:
117+
118+
```js
119+
import { render, createComponent, delegateEvents, insert, template } from 'solid-js/web';
120+
import { createSignal } from 'solid-js';
121+
122+
const _tmpl$ = /*#__PURE__*/template(`<p></p>`, 2),
123+
_tmpl$2 = /*#__PURE__*/template(`<br>`, 1),
124+
_tmpl$3 = /*#__PURE__*/template(`<button class="button">Click me!</button>`, 2);
125+
126+
function Counter() {
127+
const patternInput = createSignal(0);
128+
const setCount = patternInput[1];
129+
const count = patternInput[0];
130+
131+
const doubled = () => count() * 2;
132+
133+
const quadrupled = () => doubled() * 2;
134+
135+
return [(() => {
136+
const _el$ = _tmpl$.cloneNode(true);
137+
138+
insert(_el$, () => `${count()} * 2 = ${doubled()}`);
139+
140+
return _el$;
141+
})(), (() => {
142+
const _el$2 = _tmpl$.cloneNode(true);
143+
144+
insert(_el$2, () => `${doubled()} * 2 = ${quadrupled()}`);
145+
146+
return _el$2;
147+
})(), _tmpl$2.cloneNode(true), (() => {
148+
const _el$4 = _tmpl$3.cloneNode(true);
149+
150+
_el$4.$$click = _arg1 => {
151+
setCount(count() + 1);
152+
};
153+
154+
return _el$4;
155+
})()];
156+
}
157+
158+
render(() => createComponent(Counter, {}), document.getElementById("app"));
159+
160+
delegateEvents(["click"]);
161+
```
162+
163+
Your nice, declarative code has been magically transformed into performant imperative instructions :)
164+
165+
Soon JSX will be available to Fable React apps too! Though as commented above, it won't make a big difference in React (and in fact it can be more limiting as JSX needs to be interpreted statically, so list comprehensions for example can be trickier) but we are also introducing JSX templates which can be particularly helpful when bringing external HTML code to your app. And with the [F# template highlighting VS Code extension](https://marketplace.visualstudio.com/items?itemName=alfonsogarciacaro.vscode-template-fsharp-highlight) you can achieve a very similar experience to [Fable.Lit](https://fable.io/Fable.Lit/).
166+
167+
```fsharp
168+
let gradient, setGradient = React.useState(5)
169+
170+
Html.fragment [
171+
Html.div [
172+
Html.input [
173+
Attr.typeRange
174+
Attr.min 1
175+
Attr.max 100
176+
Attr.value $"{gradient}"
177+
Ev.onTextInput (fun (value: string) -> value |> int |> setGradient)
178+
]
179+
]
180+
181+
JSX.html $"""
182+
<svg height="150" width="300">
183+
<defs>
184+
<linearGradient id="gr2" x1="0%%" y1="60%%" x2="100%%" y2="0%%">
185+
<stop offset={ length.perc gradient } style="stop-color:rgb(52, 235, 82);stop-opacity:1" />
186+
<stop offset="100%%" style="stop-color:rgb(52, 150, 235);stop-opacity:1" />
187+
</linearGradient>
188+
</defs>
189+
<ellipse cx="125" cy="75" rx="100" ry="60" fill="url(#gr2)" />
190+
Sorry but this browser does not support inline SVG.
191+
</svg>
192+
"""
193+
```
54194

195+
Basically this means you'll be able to write JSX code directly into your F# app! And you can try it out already with Solid and Snake Island by cloning [this repo](https://github.com/alfonsogarciacaro/Feliz.Solid).
55196

56197
<br />
57198

0 commit comments

Comments
 (0)