package server-reason-react

  1. Overview
  2. Docs
Legend:
Library
Module
Module type
Parameter
Class
Class type

Make sure your code is universal

One big challenge of sharing code between client and server is that the server and the client platforms have different APIs available. You can't use browser's APIs on the server, such as document.querySelectorAll and you can't use server related APIs on the client such as any filsystem operation.

In this aspect server-reason-react SSR is not much different than Node.js. Node.js doesn't provide a window/document/etc and leaves the user to manually check for them on each usage. In our case, we don't provide any implementation for the browser APIs but we want the code to compile.

There're a few utilities that will be handy to make your frontend code work in native (and viceversa).

Universal modules

server-reason-react comes with a few modules that are compatible with both server and client, to make it easier to write universal code and don't worry about the platform.

  • Belt is an implementation of Belt that would work on both server and client. server-reason-react.belt
  • Js is an half-implementation of the Js module from melange.js, and many parts aren't implemented and some other parts aren't possible to implement on the server (Unstable, can raise "NOT IMPLEMENTED"). server-reason-react.js
  • Webapi is a stripped down version of melange-webapi that will crash at runtime if you call those APIs on the server. server-reason-react.webapi

let%browser_ppx

Exclude client code from the native build

Even when Belt, Js, and other modules are universal, sometimes you want to discard some code from native, and only execute it on the client. For example, if you're using Webapi to query the DOM, you only want to run that on the client, or if your piece of code uses some binding.

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 server-reason-react.browser_ppx into to your pps in your dune files.

In order to have browser_only available on both libraries, you need to add it on both "server" and "client" dune files. Adding the js flag: server-reason-react.browser_ppx -js will make browser_only remove the client-only code in the native build, but leave untouched the client code on the melnage build.

On client's dune:

(preprocess (pps browser_ppx -js)) 

On server's dune:

(preprocess (pps browser_ppx)) 

For example:

let%browser_only countDomNodes = (id) => {
  let elements = Webapi.Element.querySelector("#" ++ id);
  let arr_elements = Webapi.Element.toArray(elements);
  Array.length(arr_elements);
}

The method used by browser_only to discards the function is transforming the body of your function with a raising exception Runtime.Impossible_in_ssr.

It can be useful to wrap your browser_only functions in a try/catch to prevent the exception from crashing, or in order to provide a default value.

Continuing with the example:

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
  };

Externals and melange.ppx attributes

Since melange.ppx is not compatible with native, we provide server-reason-react.melange_ppx instead.

It's a drop in replacement that allows us to have support for the same features as melange.ppx, so all externals, mel attributes and other features are available. This doesn't mean it will work, in fact, most of the features won't work on the server and it will tell the compiler to wrap it in browser_only functions.

Here's the list of features

Supports all mel. attributes

mel.* attributes are stripped out of the native build, and transformed into raising functions to raise at server runtime.

Enables pipe_first ->

it's a syntax sugar for pipe_last |>, but it's not supported by default in native. server-reason-react.melange_ppx enables it and works fine in native.

Supports RegExp [%re "/regex/"]

Transforms [%re ...] into Js.Re.t from server-reason-react.js and works ok in native (There might be some features missing in the implementation, such as backtracking or grouping). Here for the issue tracking the implementation: https://github.com/ml-in-barcelona/server-reason-react/issues/45

Debugger %debugger

It removes the debugger in native. It's a noop on the server context, and it's pretty uncommon to use it on shared code.

Supports Object access ##

Unstable. It's not supported by default in native, since ## operates on JavaScript Objects, and the interface of that isn't polished.

(preprocess (pps server-reason-react.melange_ppx)) 

Next

  1. How to structure the code
OCaml

Innovation. Community. Security.