Building cross-platform native desktop apps in 

Agenda

  • Revery - overview & under the hood
  • React & Revery
  • Package manager & external libraries
  • Using C/C++ libraries
  • OCaml threads
  • Demo & code walkthrough
  • Why desktop cross-platform apps
  • Electron - most popular framework for desktop
  • Why not Electron
  • Intro

Example apps

  • Code editors
  • Chat applications
  • Web browsers
  • Microsoft Office applications

Desktop app

  • Works offline
  • Local resources (file system, hardware)
  • OS features (notifications, registry, launch on startup)
  • Much faster than web apps

Build for each OS *

Web inside desktop

  • Use JS, HTML, CSS
  • Runs inside chromium (Chrome, Edge and Opera)
  • 270,025 downloads per week
  • An app becomes a web-browser
  • High memory and CPU usage
  • High bundle size

Revery

  • Alternative to electron
  • Cross-platform
  • Compiles to native code (assembly code)
  • Super fast & instant startup
  • Functional code with OCaml/Reason
  • Still work-in-progress
  • Started from Onivim2 code editor

Revery

  • Built with ReasonML
  • Uses C/C++ libraries with OCaml/Reason bindings

* Under the hood

  • SKIA for drawing - 2D graphics library in C++ (graphics engine of Google Chrome)
  • SDL2 (Simple DirectMedia Layer) - access to audio, keyboard, mouse and graphics hardware, written in C

Revery & React

  • React UI model
    • UI = function(State)
    • Components
    • Hooks 
  • Built-in components: Checkbox, Button, View etc.
  • React concepts: props, state, children
  • Hooks: effect, reducer, state

Component

let make = (~onClick, ()) => {
  <View style=Style.[alignItems(`Center)]>
    <Text 
      style=Style.[fontSize(20)] 
      text="Do eeeet"
     />
    <Button width=200 title="Go" onClick />
  </View>
}

State & reducer

  type state = {count: int};

  type action =
    | Increment
    | Decrement;

  let reducer = (action, state) => {
    switch (action) {
    | Increment => {count: state.count + 1}
    | Decrement => {count: state.count - 1}
    };
  };

State & reducer

  let%component make = () => {
    let%hook (state, dispatch) =
      Hooks.reducer(~initialState={count: 0}, reducer);

   let onPlus = _ => dispatch(Increment);
   let onMinus = _ => dispatch(Decrement);

    <View>
      <Button onClick={onPlus} title="+" />
      <Button onClick={onMinus} title="-" />
    </View>;
  };

Package manager

  • npm for JavaScript libraries
    • package.json, package-lock.json
    • node_modules
  • esy for native Reason/OCaml libraries
    • npm and opam (OCaml) registries

    • package.json / esy.json, esy.lock

Libraries

  • install esy package hosted on npm
  • install OCaml package hosted on opam
npm install -g esy
esy add my-lib
esy add @opam/my-lib
  • C/C++ library - write OCaml bindings

Using C++ library

OCaml/Reason bindings

#include "audio.h"

CAMLprim value SDL_playMusicCAML(value name, value volume)
{
  CAMLparam2(name, volume);

  const char *filename = String_val(name);

  playMusic(filename, volume);

  CAMLreturn(Val_unit);
}

 threads

  • OCaml run-time can execute only one thread at a time
  • Runtime lock prevents threads from running parallel
  • Parallelism is achieved for system calls and C code
  • Revery runs render loop 
  • Blocking calls to C code will freeze the UI
  • Release and re-acquire the lock,
caml_release_runtime_system(); caml_acquire_runtime_system();

DEMO

Negatives

  • No hot reloading
  • Debugging with print_endline into console
  • Limited support for windows (code editor, installer etc.)
  • Missing implementation for native features (coming soon!)

Quick start

esy install
esy build
esy run

Tack!!!

Revery

By margaretkru

Revery

  • 257