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.
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 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!