javascript-bridge: Remote Monad for JavaScript on the browser

[ bsd3, library, network, program ] [ Propose Tags ] [ Report a vulnerability ]

Bridge from Haskell to JavaScript on the browser


[Skip to Readme]

Downloads

Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees

Candidates

Versions [RSS] 0.2.0
Change log CHANGELOG.md
Dependencies aeson (>=1.4 && <1.5), base (>=4.9 && <4.14), binary (>=0.8 && <0.9), containers (>=0.5 && <0.7), javascript-bridge, scotty (>=0.11 && <0.12), stm (>=2.4 && <2.6), text (>=1.2 && <1.3), time (>=1.6 && <1.10), transformers (>=0.4 && <0.6), wai (>=3.2 && <3.3), wai-websockets (>=3.0.1 && <3.1), websockets (>=0.10 && <0.13) [details]
Tested with ghc ==8.4.4, ghc ==8.6.5, ghc ==8.8.1
License BSD-3-Clause
Copyright Copyright (c) 2016-2019 The University of Kansas
Author Andy Gill
Maintainer andygill@ku.edu
Category Network
Source repo head: git clone https://github.com/ku-fpg/javascript-bridge
Uploaded by AndyGill at 2019-09-12T15:53:35Z
Distributions
Reverse Dependencies 1 direct, 8 indirect [details]
Executables javascript-bridge-examples, javascript-bridge-simple
Downloads 532 total (2 in the last 30 days)
Rating (no votes yet) [estimated by Bayesian average]
Your Rating
  • λ
  • λ
  • λ
Status Docs available [build log]
Last success reported on 2019-09-12 [all 1 reports]

Readme for javascript-bridge-0.2.0

[back to package description]

javascript-bridge Build Status

javascript-bridge is a straightforward way of calling JavaScript from Haskell, using web-sockets as the underlying transport mechanism. Conceptually, javascript-bridge gives Haskell acccess to the JavaScript eval function. However, we also support calling and returning values from JavaScript functions, constructing and using remote objects, and sending events from JavaScript to Haskell, all using a remote monad.

Overview of API

javascript-bridge remotely executes JavaScript fragments. The basic Haskell idiom is.

     send eng $ command "console.log('Hello!')"

where send is an IO function that sends a commands for remote execution, eng is a handle into a specific JavaScript engine, and command is a command builder.

There are also ways synchronously sending a procedure, that is a JavaScript expression that constructs a value, then returns the resulting value.

  do xs :: String <- send eng $ procedure "new Date().toLocaleTimeString()"
     print xs

There are ways of creating remote values, for future use, where Haskell has a handle for this remote value.

data Date = Date -- phantom

  do t :: RemoteValue Date <- send eng $ constructor "new Date()"
     send eng $ procedure $ "console.log(" <> var t <> ".toLocaleTimeString())"

Finally, there is a way of sending events from JavaScript, then listening for the event in Haskell.

  do -- Have JavaScript send an event to Haskell
     send eng $ command $ event ('Hello!'::String)"
     -- Have Haskell wait for the event, which is an Aeson 'Value'.
     e :: Value <- listen eng
     print e

Bootstrapping

Bootstrapping the connection is straightforward. First, use a middleware to setup the (Haskell) server.

import Network.JavaScript

        ...
        scotty 3000 $ do
          middleware $ start app
          ...

app :: Engine -> IO ()
app eng = send eng $ command "console.log('Hello!')"

Next, include the following fragment in your HTML code.

    <script>
        window.jsb = {ws: new WebSocket('ws://' + location.host)};
        jsb.ws.onmessage = (evt) => eval(evt.data);
    </script>

That's it!