-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.mld
85 lines (61 loc) · 3.52 KB
/
index.mld
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
{1:intro Introduction}
server-reason-react is an implementation of react-dom/server and some of React's internals in OCaml. Its purpose is to render HTML markup from the server for a Reason React application natively.
{[
module Greetings = {
[@react.component]
let make = (~name) => {
<div>
<h1>
{React.string("Hello " ++ name)}
</h1>
</div>
}
};
let html = ReactDOM.renderToStaticMarkup(<Greetings name="visitor" />)
// <div><h1>Hello visitor</h1></div>
]}
{1:core React and ReactDOM}
server-reason-react provides {!React} and {!ReactDOM} modules with the same interface as reason-react, including the JSX transformation via [server-reason-react.ppx].
- {!React} server-reason-react.react
- {!ReactDOM} server-reason-react.reactDom
[server-reason-react.ppx] needs to be a different ppx than [reason-react-ppx] to transform domProps into an interal representation of Props where the type is known ahead of time in order to render them on the server.
Add [server-reason-react.ppx] to your pps list in your dune files
{[ (preprocess (pps server-reason-react.ppx)) ]}
{2:universal Make sure your code is universal}
One big challenge of sharing code between client and server is that the server side has different API environment with client side. In this respect server-reason-react SSR is not much different than Node.js, except on native you should prevent browser's API calls and Js and compile it properly while in Node.js is just a matter of not calling those browser APIs.
There're a few utilities that will be handy to make your frontend code work in native, such as {!Belt}, {!Js}, [Promise], and [Webapi].
All of them are implementations of the same APIs as their originals. [Belt] is feature complete while the rest are still alpha, some missing APIs and incorrect functionality.
Visit each API page for more information:
- {!Belt} server-reason-react.belt
- {!Js} server-reason-react.js
- server-reason-react.promise (vendored https://github.com/aantron/promise and make it compatible)
- server-reason-react.webapi (vendored https://github.com/melange-community/melange-webapi and stripped down to the bare minimum)
{2:pipe_first_ppx Make pipe first work on native}
Add [pipe_first_ppx] to your pps list in your dune files
{[ (preprocess (pps pipe_first_ppx)) ]}
{2:browser_ppx Exclude client code from the native build}
Thanks to [browser_ppx], we can easily discard what's meant to be running on the client and avoid the execution on the server:
{[
let%browser_only countDomNodes = (id) => {
let elements = Webapi.Element.querySelector("#" ++ id);
let arr_elements = Webapi.Element.toArray(elements);
Array.length(arr_elements);
};
]}
Add [browser_ppx] to your pps in your dune files. Don't forget to add it on both "server" and "client" dune files, since you want to discard the content and add [browser_only -js] only to the client.
On client's dune:
{[ (preprocess (pps browser_ppx -js)) ]}
On server's dune:
{[ (preprocess (pps browser_ppx)) ]}
The method used by [browser_only] to discards the function is transforming the body of your function into a raise exception ([ReactDOM.Impossible_in_ssr]). Sometimes is useful to wrap it in a try/catch block to prevent the exception from crashing and maybe set a default value or do something else.
{[
let%browser_only countDomNodes = (id) => {
let elements = Webapi.Element.querySelector("#" ++ id);
let arr_elements = Webapi.Element.toArray(elements);
Array.length(arr_elements);
}
let main = id =>
try(countDomNodes(id)) {
| _ => 0
};
]}