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
State machine visualization: https://xstate.js.org/viz/?gist=731a6bcc9291fe38e7edabdca3ce43ef

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
Clone revery-quick-start, https://github.com/revery-ui/revery-quick-start
esy install
esy build
esy runTack!!!


Revery
By margaretkru
Revery
- 437
 
   
   
  