Giter VIP home page Giter VIP logo

jsaddle's Introduction

JSaddle

JSaddle is an interface for JavaScript that works with GHCJS or GHC. It is used by ghcjs-dom when compiled with GHC and is compatible with ghcjs-dom when compiled with GHCJS.

You can use JSaddle directly as follows:

module Main ( main ) where

import Control.Monad.IO.Class (MonadIO(..))
import Control.Concurrent.MVar (takeMVar, putMVar, newEmptyMVar)
import Control.Lens ((^.))
import Language.Javascript.JSaddle
       (jsg, js, js1, jss, fun, valToNumber, syncPoint)
import Language.Javascript.JSaddle.Warp (run)

main = run 3709 $ do
    doc <- jsg "document"
    doc ^. js "body" ^. jss "innerHTML" "<h1>Kia ora (Hi)</h1>"

    -- Create a haskell function call back for the onclick event
    doc ^. jss "onclick" (fun $ \ _ _ [e] -> do
        x <- e ^. js "clientX" >>= valToNumber
        y <- e ^. js "clientY" >>= valToNumber
        newParagraph <- doc ^. js1 "createElement" "p"
        newParagraph ^. js1 "appendChild" (
            doc ^. js1 "createTextNode" ("Click " ++ show (x, y)))
        doc ^. js "body" ^. js1 "appendChild" newParagraph
        return ())

    -- Make an exit button
    exitMVar <- liftIO newEmptyMVar
    exit <- doc ^. js1 "createElement" "span"
    exit ^. js1 "appendChild" (
        doc ^. js1 "createTextNode" "Click here to exit")
    doc ^. js "body" ^. js1 "appendChild" exit
    exit ^. jss "onclick" (fun $ \ _ _ _ -> liftIO $ putMVar exitMVar ())

    -- Force all all the lazy evaluation to be executed
    syncPoint

    -- In GHC compiled version the WebSocket connection will end when this
    -- thread ends.  So we will wait until the user clicks exit.
    liftIO $ takeMVar exitMVar
    doc ^. js "body" ^. jss "innerHTML" "<h1>Ka kite ano (See you later)</h1>"
    return ()

When compiled with GHC this code will run a Warp web server you can connect to at http:\\localhost:3709\.

Here is the same program using ghcjs-dom to call JSaddle. As well as better type safety this version uses JS FFI directly (rather than via JSaddle) when compiled with GHCJS:

module Main (
    main
) where

import Control.Monad.IO.Class (MonadIO(..))
import Control.Concurrent.MVar (takeMVar, putMVar, newEmptyMVar)

import GHCJS.DOM (run, syncPoint, currentDocument)
import GHCJS.DOM.Document (getBody, createElement, createTextNode)
import GHCJS.DOM.Element (setInnerHTML)
import GHCJS.DOM.Node (appendChild)
import GHCJS.DOM.EventM (on, mouseClientXY)
import qualified GHCJS.DOM.Document as D (click)
import qualified GHCJS.DOM.Element as E (click)

main = run 3708 $ do
    Just doc <- currentDocument
    Just body <- getBody doc
    setInnerHTML body (Just "<h1>Kia ora (Hi)</h1>")
    on doc D.click $ do
        (x, y) <- mouseClientXY
        Just newParagraph <- createElement doc (Just "p")
        text <- createTextNode doc $ "Click " ++ show (x, y)
        appendChild newParagraph text
        appendChild body (Just newParagraph)
        return ()

    -- Make an exit button
    exitMVar <- liftIO newEmptyMVar
    Just exit <- createElement doc (Just "span")
    text <- createTextNode doc "Click here to exit"
    appendChild exit text
    appendChild body (Just exit)
    on exit E.click $ liftIO $ putMVar exitMVar ()

    -- Force all all the lazy evaluation to be executed
    syncPoint

    -- In GHC compiled version the WebSocket connection will end when this
    -- thread ends.  So we will wait until the user clicks exit.
    liftIO $ takeMVar exitMVar
    setInnerHTML body (Just "<h1>Ka kite ano (See you later)</h1>")
    return ()

When compiled with GHC this code will run a Warp web server you can connect to at http:\\localhost:3708\.

How does it work on GHC

There are a number of different JSaddle runners to choose from

In all of these cases a web control or browser of some sort is used. An HTML file and a small JavaScript command interpreter are loaded into it. Then the native GHC compiled JSaddle code runs. In order to interact with the browser it sends commands to the JavaScript command interpreter. The mechanism for sending the commands differs for the different runners, but they are always combined into batches and encoded in JSON.

Haskell callbacks from JavaScript are supported by sending JSON back from the command interpreter. These can be synchronous (blocking the JavaScript thread until the Haskell callback completes) or asynchronous.

Why use a JavaScript command interpreter?

Older versions of JSaddle relied on the WebKit1 interface to WebKitGTK and JavaScriptCore that is only supported in older versions of WebKitGTK. With the newer WebKit2 interface this level of access is only available to WebKit Extensions. The general advice for people migrating from WebKit1 to WebKit2 seems to be to use JavaScript.

As a bonus we have been able to support a number of different platforms with the JavaScript command interpreter and it should be easy to support more in the future.

JSVal

When compiling with GHC a JSVal is represented by a integer key for a JavaScript Map in jsaddle.js code. The first five keys [0..4] are null, undefined, true, false and window. This means the Haskell code can quickly create a JSVal with one of these values. Both the Haskell code and jsaddle.js can allocate new JSVal keys. The Haskell code allocates negative keys and jsaddle.js allocates positive keys to avoid clashing.

The haskell code will not know the value to go with the key, but it will include it in commands to the server that are sort of "hey call this function and put the result in the map with this key"). This allows for the lazy execution of the JSaddle code.

A finalizer is added on the Haskell code and an asynchronous FreeJSVal command is automatically sent to jsaddle.js when the JSVal is no longer reachable. The jsaddle.js code then deletes the key from the Map.

JSStrings

These are haskell Text type and so reside on the native side of the WebSocket. If you want to avoid transferring large string values over the WebSocket use toJSVal to convert it to a JSVal.

Lazy Execution

To improve performance commands are sent to jsaddle.js in batches that contain any number of asynchronous commands followed by one synchronous one. To get the best performance you should avoid synchronous commands, these are:

Synchronous Command What will trigger it
ValueToString converting a JSVal to a JSString (Text when using GHC)
ValueToBool converting a JSVal to a Bool
ValueToNumber converting a JSVal to a Double
ValueToJSON converting a JSVal to a JSON
DeRefVal converting a JSVal to a Value
IsNull testing to see if a JSVal is null
IsUndefined testing to see if a JSVal is undefined
InstanceOf testing to see if a JSVal is an instanceOf a given type
StrictEqual testing too JSVal values for equality (===)
PropertyNames getting the list of properties in an JS object

So basically if you don't look inside a JSVal to find out something the state of the JavaScript context you will not produce any synchronous commands and your code will run fast. As soon as you look at what is in a JSVal we have to wait for jsaddle.js to send the results back and your code will block.

In some cases you may wish to make sure all the JSaddle commands are executed. You can use the syncPoint and syncAfter functions to force all the pending asynchronous commands to be executed.

How does it work on GHCJS

It uses a handful of JS FFI calls to execute JavaScript functions indirectly. This indirection will be small compared to the overhead of the WebSockets approach (used when JSaddle is compiled with GHC), but it will be significant compared to hand crafted JS FFI calls.

For the best performance you may want to write both JS FFI and JSaddle wrappers for your JavaScript code. This is the approach taken by ghcjs-dom.

For instance here is getElementById from the ghcjs-dom-jsffi (used by ghcjs-dom when compiled with GHCJS)

foreign import javascript unsafe "$1[\"getElementById\"]($2)"
        js_getElementById :: Document -> JSString -> IO (Nullable Element)

getElementById ::
               (MonadIO m, IsDocument self, ToJSString elementId) =>
                 self -> elementId -> m (Maybe Element)
getElementById self elementId
  = liftIO
      (nullableToMaybe <$>
         (js_getElementById (toDocument self) (toJSString elementId)))

Here is getElementById from jsaddle-dom (used by ghcjs-dom when compiled with GHC)

getElementById ::
               (MonadDOM m, IsDocument self, ToJSString elementId) =>
                 self -> elementId -> m (Maybe Element)
getElementById self elementId
  = liftDOM
      (((toDocument self) ^. jsf "getElementById" [toJSVal elementId])
         >>= fromJSVal)

Exceptions

JSaddle does not support exceptions well. When compiled with GHCJS an exception will result in termination of the thread at the point the exception is thrown.

When using GHC the Haskell executions will probably continue for a while before the exception is received at all by the Haskell code (because the lazy execution of the JS code). The exception will be thrown when the next synchronous command is executed. When it reaches the synchronous command a haskell type JSException will be thrown (this may not be the thread that initiated the command that caused the exception). You can use syncPoint and syncAfter to force the exception to be thrown. There are JSM versions of catch and bracket that also include a syncPoint call.

Building with Stack

The jsaddle-webkit2gtk runner can be difficult to build with stack. See this issue if you get stuck.

jsaddle's People

Contributors

adetokunbo avatar alexfmpe avatar ali-abrar avatar alios avatar amesgen avatar avanov avatar bhurt avatar bitonic avatar cgibbard avatar charlestaylor7 avatar chessai avatar dfordivam avatar elvishjerricco avatar ericson2314 avatar hamishmack avatar joshmeredith avatar kabuhr avatar kmicklas avatar maralorn avatar matthewbauer avatar noinia avatar peterbecich avatar samtay avatar srid avatar tdimiduk avatar teofilc avatar tomsmalley avatar wdanilo avatar wizek avatar y-taka-23 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jsaddle's Issues

hackage revision made due to build-failure in `jsaddle-0.9.5.0`

On https://matrix.hackage.haskell.org/package/jsaddle I noticed that w/ GHC 7.10.3 there's the compile failure below:

Configuring library for jsaddle-0.9.5.0..
Preprocessing library for jsaddle-0.9.5.0..
Building library for jsaddle-0.9.5.0..

src-ghc/Data/JSString/Internal/Type.hs:41:8-21:
    Could not find module ‘Data.Semigroup’
    It is a member of the hidden package ‘semigroups-0.18.5@BngcGoLg8o2DvNNrfcIa4q’.
    Perhaps you need to add ‘semigroups’ to the build-depends in your .cabal file.
    It is a member of the hidden package ‘semigroups-0.18.5@6vBhP1Zoku6HniDcB4OnAf’.
    Perhaps you need to add ‘semigroups’ to the build-depends in your .cabal file.
    Use -v to see a list of the files searched for.

src-ghc/GHCJS/Types.hs:31:8-20:
    Could not find module ‘GHC.IO.Unsafe’
    Use -v to see a list of the files searched for.
<<ghc: 341606272 bytes, 225 GCs, 4107345/9728384 avg/max bytes residency (7 samples), 24M in use, 0.001 INIT (0.001 elapsed), 0.184 MUT (0.275 elapsed), 0.143 GC (0.145 elapsed) :ghc>>

consequently I've made the revisions at

respectively

closing the wkwebview window kills jsaddle apps (macOS)

When the main UI window is closed with the red close button, a jsaddle-wkwebview app will exit immediately rather than running any actions that follow the call to run ...

I've only verified this on Mojave, but it may exist on other macOS versions as well.

Build error with current version (4ce7398681ee)

cabal build yields:

Building jsc-0.0.1...
Preprocessing library jsc-0.0.1...
[3 of 5] Compiling Language.Javascript.JSC.Object ( src/Language/Javascript/JSC/Object.hs, dist/build/Language/Javascript/JSC/Object.o )

src/Language/Javascript/JSC/Object.hs:247:1:
Unacceptable result type in foreign declaration:
IO
(GHC.Ptr.FunPtr
(GHC.Ptr.Ptr
Graphics.UI.Gtk.WebKit.JavaScriptCore.JSBase.OpaqueJSContext
-> GHC.Ptr.Ptr
Graphics.UI.Gtk.WebKit.JavaScriptCore.JSBase.OpaqueJSValue
-> GHC.Ptr.Ptr
Graphics.UI.Gtk.WebKit.JavaScriptCore.JSBase.OpaqueJSValue
-> CUInt
-> GHC.Ptr.Ptr
(GHC.Ptr.Ptr
Graphics.UI.Gtk.WebKit.JavaScriptCore.JSBase.OpaqueJSValue)
-> GHC.Ptr.Ptr
(GHC.Ptr.Ptr
Graphics.UI.Gtk.WebKit.JavaScriptCore.JSBase.OpaqueJSValue)
-> IO
(GHC.Ptr.Ptr
Graphics.UI.Gtk.WebKit.JavaScriptCore.JSBase.OpaqueJSValue)))
When checking declaration:
foreign import ccall safe "wrapper" mkJSObjectCallAsFunctionCallback
:: JSObjectCallAsFunctionCallback'
-> IO JSObjectCallAsFunctionCallback

GHC 7.6.1 and 7.4.1.

Maybe I'm doing something wrong?

Thanks,
Thomas

Performance Tests and Optimizing

It would be nice to have some simple performance tests. In particular it would be good to be able to identify where the bottle necks are on the with the different runners.

Then we can see what changes are worth making for the sake of performance. For instance is it worth reducing the size of JSON by using shorter names? Should we avoid recomputing JSON for the last async batch when sending a sync batch?

Make behavior of run consistent between jsaddle_wkwebview and jsaddle_webkitgtk

In jsaddle_wkwebview, run leaves the apps base url as about:blank. In Reflex/Dom/Internal.hs#L40 runFile "index.html" "" is used instead.

--TODO: Eliminate this; it is needed because otherwise the app's base
--URL will be set to "about:blank" due to jsaddleMain rather than
--jsaddleMainFile being used
run :: JSM () -> IO ()
run = runFile "index.html" "" def

That means that on MacOS, where native reflex apps are linked using jsaddle_wkwebview the apps need to provide a dummy index.html for the app to be visible, which is tricky to setup for nix projects. (cf reflex-frp/reflex-platform#209)

The best fix would be to make run for jsaddle_wkwebview consistent with run for jsaddle_webgitgtk so that this use of runFile can be avoided.

JSONValueToValue not implemented

My application throws ProtocolErrors due to its use of toJSVal_aeson which requires the JSONValueToValue command which is not implemented.

What can cause `jsaddle Results decode failed` exception when using `fun`?

I've been trying to use the fun and function functions from here: https://hackage.haskell.org/package/jsaddle-0.9.4.0/docs/Language-Javascript-JSaddle-Object.html#v:fun

And I've ran into exceptions like this:

jsaddle3-exe: jsaddle Results decode failed : "{\"tag\":\"Callback\",\"contents\":[0,{},-2,101,102,[103]]}"
CallStack (from HasCallStack):
  error, called at src/Language/Javascript/JSaddle/WebSockets.hs:85:40 in jsaddle-warp-0.9.5.0-EK8DFrM2ZlV7tdElT9ks2n:Language.Javascript.JSaddle.WebSockets

Here is a reproducible minimal example from the docs: Wizek/jsaddle3@967b32~2...967b32

Aside; I've also tried creating a minimal repro case with nix like this:

#!/usr/bin/env nix-shell
#! nix-shell -p "haskell.packages.ghc822.ghcWithPackages (p: with p; with haskell.lib; [(doJailbreak (dontCheck jsaddle-warp))])"
#! nix-shell -i "runghc"

{-# language OverloadedStrings #-}

import            Control.Monad.IO.Class
import            Language.Javascript.JSaddle.Warp
import            Language.Javascript.JSaddle
import            Language.Javascript.JSaddle.Debug
import            Control.Concurrent
import            Control.Monad
import            Data.Text
import            Control.Concurrent.MVar

main = run 3197 $ do
  result <- liftIO newEmptyMVar
  deRefVal $ call (eval "(function(f) {f('Hello');})") global [fun $ \ _ _ [arg1] -> do
    valToText arg1 >>= (liftIO . putMVar result)
    ]
  liftIO $ takeMVar result

But I've run into the following likely unrelated issue:

Configuring jsaddle-warp-0.9.5.0...
CallStack (from HasCallStack):
  die', called at libraries/Cabal/Cabal/Distribution/Simple/Configure.hs:948:20 in Cabal-2.0.1.0:Distribution.Simple.Configure
  configureFinalizedPackage, called at libraries/Cabal/Cabal/Distribution/Simple/Configure.hs:470:12 in Cabal-2.0.1.0:Distribution.Simple.Configure
  configure, called at libraries/Cabal/Cabal/Distribution/Simple.hs:570:20 in Cabal-2.0.1.0:Distribution.Simple
  confHook, called at libraries/Cabal/Cabal/Distribution/Simple/UserHooks.hs:67:5 in Cabal-2.0.1.0:Distribution.Simple.UserHooks
  configureAction, called at libraries/Cabal/Cabal/Distribution/Simple.hs:174:19 in Cabal-2.0.1.0:Distribution.Simple
  defaultMainHelper, called at libraries/Cabal/Cabal/Distribution/Simple.hs:119:27 in Cabal-2.0.1.0:Distribution.Simple
  defaultMain, called at Setup.lhs:5:10 in main:Main
Setup: Encountered missing dependencies:
websockets >=0.9.5.0 && <0.11
builder for ‘/nix/store/76y9xrhvb0hmq2s46qzsvqv1131z13yh-jsaddle-warp-0.9.5.0.drv failed with exit code 1
killing process 105483

A bit of background:

  • Compiling with GHC
  • I'm trying to explore these functions to overcome the issue stated in #51.

jsaddle-warp: Configurable connection url?

Thanks to your help, I managed to setup my app with jsaddle-warp, everything compiles and runs and loads, but the app does not show up, no errors, no exceptions, just nothing happening. I reduced my main to the following, still no output:

main :: IO ()
main = do
  putStrLn "Run it baby!"
  run 3709 $ do
    liftIO $ putStrLn "Before console.log"
    _ <- JS.eval("console.log('ehehehehe we are here!');" :: Text);
    liftIO $ putStrLn "After console.log"
    pure ()

The only output I am getting is "Run it baby!", nothing else, neither in the browser console nor in the terminal.

Backend is serving an index.html, which loads jsaddle.js, which indeed connects to the frontend (no errors).

Thank you, for any help/pointers/fixes!

Support GHC-8.8

If one allows

  • lens-4.18
  • primitive-0.7
  • time-1.9
  • Cabal-3.0
  • base-compat-0.11
  • base-4.13 (jsaddle-dom setup)

in jsaddle, jsaddle-dom and jsaddle-warp, they seem to compile fine with GHC-8.8.

Add Windows XamlWebView backend

With @angerman's recent work on cross compiling GHC to windows (NixOS/nixpkgs#43559), it will hopefully be possible soon to build for Windows on Nix! If we can get a proper backend for jsaddle ready, this could mean building whole apps for Windows.

Originally I was thinking we can reuse the webkitgtk backend. However, Windows is no longer supported by webkitgtk, apparently (https://github.com/Alexpux/MINGW-packages/issues/3484). Instead, I am thinking it would make sense to go the similar route to WKWebView and reuse the OS SDK as much as possible. Microsoft provides WebView that we can make c bindings to:

https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.webview

I think these are usable in the Mingw based environment.

ghci debug support

We should have a way to:

  • Get a list of active JS contexts in ghci
  • send a JSM () to a JS context

Can't cabal install jsaddle 0.4.0.3

Any ideas?

Running PKG_CONFIG_PATH=/usr/local/Cellar/libffi/3.0.13/lib/pkgconfig/:/opt/local/lib/pkgconfig cabal --ghcjs install jsaddle

Output:

Resolving dependencies...
Notice: installing into a sandbox located at
/Users/felipecsl/prj/jsaddle-hello/.cabal-sandbox
Configuring jsaddle-0.4.0.3...
Building jsaddle-0.4.0.3...
Failed to install jsaddle-0.4.0.3
Build log ( /Users/felipecsl/prj/jsaddle-hello/.cabal-sandbox/logs/jsaddle-0.4.0.3.log ):
cabal: Entering directory '/var/folders/hm/b5m3gr_92zn0q9b9zzj5wmkw0000gn/T/cabal-tmp-51153/jsaddle-0.4.0.3'
Configuring jsaddle-0.4.0.3...
Building jsaddle-0.4.0.3...
Preprocessing library jsaddle-0.4.0.3...

src/Language/Javascript/JSaddle/Monad.hs:55:8-46:
    Could not find module ‘GI.JavaScriptCore.Structs.GlobalContext’
    Use -v to see a list of the files searched for.

src/Language/Javascript/JSaddle/Test.hs:23:8-13:
    Could not find module ‘GI.Gtk’
    Use -v to see a list of the files searched for.

src/Language/Javascript/JSaddle/Test.hs:31:8-32:
    Could not find module ‘GI.WebKit.Objects.WebView’
    Use -v to see a list of the files searched for.

src/Language/Javascript/JSaddle/Test.hs:35:8-33:
    Could not find module ‘GI.WebKit.Objects.WebFrame’
    Use -v to see a list of the files searched for.

src/Language/Javascript/JSaddle/Test.hs:44:18-33:
    Could not find module ‘GI.Gtk.Functions’
    Use -v to see a list of the files searched for.

src/Language/Javascript/JSaddle/Test.hs:45:8-24:
    Could not find module ‘GI.GLib.Functions’
    Use -v to see a list of the files searched for.

src/Language/Javascript/JSaddle/Test.hs:46:8-19:
    Could not find module ‘GI.Gtk.Enums’
    Use -v to see a list of the files searched for.

src/Language/Javascript/JSaddle/Test.hs:47:8-27:
    Could not find module ‘Data.GI.Base.Signals’
    It is a member of the hidden package ‘haskell-gi-base-0.18@DJqBsGBbw2z3hzqrdObCdL’.
    Perhaps you need to add ‘haskell-gi-base’ to the build-depends in your .cabal file.
    Use -v to see a list of the files searched for.

src/Language/Javascript/JSaddle/Test.hs:48:8-14:
    Could not find module ‘GI.GLib’
    Use -v to see a list of the files searched for.

src/Language/Javascript/JSaddle/Test.hs:49:8-24:
    Could not find module ‘GI.GLib.Constants’
    Use -v to see a list of the files searched for.

src/Language/Javascript/JSaddle/Test.hs:50:8-28:
    Could not find module ‘GI.Gtk.Objects.Widget’
    Use -v to see a list of the files searched for.

src/Language/Javascript/JSaddle/Test.hs:54:8-32:
    Could not find module ‘GI.Gtk.Objects.Adjustment’
    Use -v to see a list of the files searched for.
cabal: Leaving directory '/var/folders/hm/b5m3gr_92zn0q9b9zzj5wmkw0000gn/T/cabal-tmp-51153/jsaddle-0.4.0.3'
cabal: Error: some packages failed to install:
jsaddle-0.4.0.3 failed during the building phase. The exception was:
ExitFailure 1

generic-builder.nix:13:1 called with unexpected argument 'libraryDarwinFrameworkDepends

#I'm trying to use reunification branch of reflex-platform and this error comes out.

Entering the reflex sandbox...
error: anonymous function at /nix/store/3mfnbjz5ikkax7asvjcchxfaylagkfwb-source/pkgs/development/haskell-modules/generic-builder.nix:13:1 called with unexpected argument 'libraryDarwinFrameworkDepends', at /nix/store/3mfnbjz5ikkax7asvjcchxfaylagkfwb-source/lib/customisation.nix:74:12

I couldn't find any information about libraryDarwinFrameworkDepends parameter
in https://github.com/NixOS/nixpkgs/tree/master/pkgs/development/haskell-modules
or any other places. where did it came from? Just give me direction so I can dig more.

nixos 2.0.2 unstable / host macOS 10.12.5

Static files

works (loads my css file) when I build with it with GHCJS but with jsaddle-warp it seems that it works different and this doesn't allow me to address to my local files through localhost

jsaddle-warp browser DOS on the Haskell program (stuck on sendTextData)

I'm writing a program which draws many things on a canvas - and have found that if I draw too many things, too fast, then jsaddle-warp will freeze up. It works fine in ghcjs in-browser. A reduced version is below.

module Main where

import Control.Monad (forM_)
import Data.Monoid ((<>))
import Control.Monad.IO.Class (MonadIO(..))
import Control.Concurrent (forkIO)
import Control.Concurrent.MVar (takeMVar, putMVar, newEmptyMVar)
import Control.Lens ((^.))
import Language.Javascript.JSaddle
       (jsg, jsg3, js, js1, jss, fun, valToNumber, syncPoint,
        nextAnimationFrame, runJSM, askJSM, global)
import Language.Javascript.JSaddle.Warp (run, debug)
import Language.Javascript.JSaddle.Run (enableLogging)

main = run 3708 $ do
    enableLogging True
    doc <- jsg "document"
    doc ^. js "body" ^. jss "innerHTML" ("<h1>Kia ora (Hi)</h1>")

    -- Create a haskell function call back for the onclick event
    doc ^. jss "onmousemove" (fun $ \ _ _ [e] -> do
        x <- e ^. js "clientX" >>= valToNumber
        y <- e ^. js "clientY" >>= valToNumber

        forM_ [1..10000] $ \_ ->
            doc ^. js "body" ^. jss "innerHTML" ("<h1>Kia ora (Hi)" <> show (x, y) <> "</h1>")

        liftIO $ print (x, y)
        return ())

How to use `jsaddle-clib`

The documentation lists jsaddle-clib as one of the runners to choose from. All the other runners seem to export a more or less compatible run function, but not jsaddle-clib. Some documentation on how to use jsaddle-clib would be helpful.

Q: Are synchronous, UI-blocking XHR requests meant to be issued by JSaddle?

I've found them when I started digging in the network tab after noticing that my UI was feeling sluggish to use, especially when typing in input fields. I am not yet sure if this sluggishness is due to JSaddle or some other portion of my code, but seeing the following deprecation warning from Chrome gave me pause and thought to ask.

jsaddle.js:134 [Deprecation] Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.

I also seem to remember that the UI was more responsive before I upgraded reflex-dom 0.3 to 0.4 — the former of which doesn't use jsaddle, and drives a webkitgtk2 window more directly AFAIU.

I've compiled with GHC, JSaddle.Warp.

I've also noticed a 101 pending websocket connection in the network list, which seemed to have ongoing back and forth messages, so I am all the more confused by the presence of sync xhr.

Is this all by design? Or am I observing some edge-case?

Can't build `jsaddle-webkit2gtk`

It looks like GI.JavaScriptCore and GI.WebKit2 have changed in incompatible ways:

Building library for jsaddle-webkit2gtk-0.9.6.0..
[1 of 1] Compiling Language.Javascript.JSaddle.WebKitGTK ( src/Language/Javascript/JSaddle/WebKitGTK.hs, dist/build/Language/Javascript/JSaddle/WebKitGTK.o )

src/Language/Javascript/JSaddle/WebKitGTK.hs:68:38-54: error:
    Module ‘GI.JavaScriptCore’ does not export ‘GlobalContext(..)’
   |
68 | import GI.JavaScriptCore (Value(..), GlobalContext(..))
   |                                      ^^^^^^^^^^^^^^^^^

src/Language/Javascript/JSaddle/WebKitGTK.hs:77:9-32: error:
    Module ‘GI.WebKit2’ does not export ‘javascriptResultGetValue’
   |
77 |         javascriptResultGetValue, javascriptResultGetGlobalContext,
   |         ^^^^^^^^^^^^^^^^^^^^^^^^

src/Language/Javascript/JSaddle/WebKitGTK.hs:77:35-66: error:
    Module
    ‘GI.WebKit2’
    does not export
    ‘javascriptResultGetGlobalContext’
   |
77 |         javascriptResultGetValue, javascriptResultGetGlobalContext,
   |  

To reproduce, use this default.nix:

let
  nixpkgs-src = builtins.fetchTarball {
    url = "https://github.com/NixOS/nixpkgs/archive/6a0d2ff7c1d024914a3570b85f1c88df8930b471.tar.gz";
    sha256 = "06q10786lj7yig6spzsz1zflcjqxjj11d5qsr305jln34wndlj27";
  };
  jsaddle-src = builtins.fetchTarball {
    url = "https://github.com/ghcjs/jsaddle/archive/98a00b334b0ce62bf6bd3a4af682b25a8ea28193.tar.gz";
    sha256 = "057a4imgyq4aabsqhlv9zd3z855cwii2qq8i5hmfnfmc9wcx403l";
  };
  pkgs = import nixpkgs-src {};
  haskellPackages = pkgs.haskellPackages.override {
    overrides = self: super: {
      jsaddle = self.callCabal2nix "jsaddle" (jsaddle-src + "/jsaddle") {};
      jsaddle-webkit2gtk = self.callCabal2nix "jsaddle-webkit2gtk" (jsaddle-src + "/jsaddle-webkit2gtk") {};
      haskell-gi-overloading = self.callHackage "haskell-gi-overloading" "0.0" {};
    };
  };
in haskellPackages.jsaddle-webkit2gtk

Does not compile with ghcjs

--  While building package jsaddle-wkwebview-0.8.1.0 using:
      /home/m/.stack/setup-exe-cache/x86_64-linux/Cabal-simple_mPHDZzAJ_1.24.0.0_ghcjs-0.2.1.9007008_ghc-8.0.1 --builddir=.stack-work/dist/x86_64-linux/Cabal-1.24.0.0_ghcjs build lib:jsaddle-wkwebview --ghcjs-options " -ddump-hi -ddump-to-file"
    Process exited with code: ExitFailure 1
    Logs have been written to: /home/m/workHS/github/reflex-todomvc/.stack-work/logs/jsaddle-wkwebview-0.8.1.0.log

    Configuring jsaddle-wkwebview-0.8.1.0...
    Preprocessing library jsaddle-wkwebview-0.8.1.0...
    [1 of 1] Compiling Language.Javascript.JSaddle.WKWebView ( src/Language/Javascript/JSaddle/WKWebView.hs, .stack-work/dist/x86_64-linux/Cabal-1.24.0.0_ghcjs/build/Language/Javascript/JSaddle/WKWebView.js_o )
    
    /home/m/workHS/github/reflex-todomvc/.stack-work/downloaded/GGl0UkN_KCcT/jsaddle-wkwebview/src/Language/Javascript/JSaddle/WKWebView.hs:21:37-43: error:
        Module ‘Language.Javascript.JSaddle’ does not export ‘Results’
    
    /home/m/workHS/github/reflex-todomvc/.stack-work/downloaded/GGl0UkN_KCcT/jsaddle-wkwebview/src/Language/Javascript/JSaddle/WKWebView.hs:22:41-53: error:
        Module
        ‘Language.Javascript.JSaddle.Run’
        does not export
        ‘runJavaScript’

runJavaScript is used in multiple places

Not in scope: type constructor or class ‘JSArray’

I'm getting this error (with the hackage version) with ghcjs Quick Start method from today (ghcjs-dom from master branch builds fine with it):

Preprocessing library jsaddle-0.2.1.0...
[ 1 of 12] Compiling Language.Javascript.JSaddle.Types ( src/Language/Javascript/JSaddle/Types.hs, dist/build/Language/Javascript/JSaddle/Types.js_o )

src/Language/Javascript/JSaddle/Types.hs:41:22:
    Not in scope: type constructor or class ‘JSArray’
Failed to install jsaddle-0.2.1.0

wkwebview doesn't work in runghc on macOS Mojave

MacOS has a notion of 'main thread' and in runghc a different thread is being used as the UI thread. On Mojave this no longer works -- you get a big WARNING on stderr, but jsaddle seems to think everything succeeded and keeps running. Unfortunately, the only UI element that comes up is a dock icon.

There may not be a way to make runghc and other things that use a spawned thread as a UI thread work on this version of macOS, but at least they should fail cleanly.

Build with cabal new-build

I just bumped some of the upper bounds, and I would like to confirm that I didn't break anything. However, attempting to build with cabal new-build gives the following error:

$ cabal new-build -w ghc-8.2.2 --constraint=transformers-compat==0.6.0.5 --constraint=http-types==0.12.1 all
Resolving dependencies...
cabal: Could not resolve dependencies:
trying: jsaddle-webkit2gtk-0.9.4.0 (user goal)
next goal: webkit2gtk3-javascriptcore (dependency of
jsaddle-webkit2gtk-0.9.4.0)
rejecting: webkit2gtk3-javascriptcore-0.14.2.1 (conflict: requires pkg-config
package webkit2gtk-4.0>=1.1.15, not found in the pkg-config database)
After searching the rest of the dependency tree exhaustively, these were the
goals I've had most trouble fulfilling: jsaddle-webkit2gtk,
webkit2gtk3-javascriptcore

Compiling module jsaddle-webkit2gtk-0.8.3.1 gives GI.WebKit2 does not export errors

Building jsaddle-webkit2gtk-0.8.3.1 with the appended stack file failes in module jsaddle-webkit2gtk-0.8.3.1/src/Language/Javascript/JSaddle/WebKitGTK with several ‘GI.WebKit2’ does not export error messages.

The goal is to compile and use reflex-dom with the standard GHC compiler.

Attachments:

  • Stack File
  • Build Log

Stack File

flags: {}
extra-package-dbs: []
packages:
- '.'
- location:
    git: https://github.com/reflex-frp/reflex
    commit: 2fe0f566f8d6b6eceb178a85516643390111bb83
  extra-dep: true
- location:
    git: https://github.com/reflex-frp/reflex-dom
    commit: 706ab47df9729bdc5c4ac3f4d8dfd4661d9f6e1a
  subdirs:
  - reflex-dom
  - reflex-dom-core
  extra-dep: true

# Use  dependent-sum-0.3.2.2 from github.
# Version on cabal has wrong base dependency
- location:
    git: https://github.com/mokus0/dependent-sum
    commit: 02173260ce60113ac442da04bf40139119271380 
  extra-dep: true
  
extra-deps:
- ghcjs-dom-0.8.0.0
- ghcjs-dom-jsaddle-0.8.0.0
- jsaddle-0.8.3.2
- jsaddle-dom-0.8.0.0
- jsaddle-webkit2gtk-0.8.3.1
- webkit2gtk3-javascriptcore-0.14.2.1
- gi-webkit2-4.0.12
- gi-javascriptcore-4.0.12
- prim-uniq-0.1.0.1
- ref-tf-0.4.0.1
- zenc-0.1.1
- dependent-sum-template-0.0.0.5
resolver: lts-8.12

Build log

dependent-sum-0.3.2.2: configure (lib)
dependent-sum-0.3.2.2: build (lib)
ref-tf-0.4.0.1: configure
ref-tf-0.4.0.1: build
gi-javascriptcore-4.0.12: configure
dependent-sum-0.3.2.2: copy/register
ref-tf-0.4.0.1: copy/register
gi-javascriptcore-4.0.12: build
webkit2gtk3-javascriptcore-0.14.2.1: configure
gi-javascriptcore-4.0.12: copy/register
webkit2gtk3-javascriptcore-0.14.2.1: build
dependent-map-0.2.4.0: configure
dependent-map-0.2.4.0: build
dependent-sum-template-0.0.0.5: configure
dependent-sum-template-0.0.0.5: build
gi-webkit2-4.0.12: configure
dependent-sum-template-0.0.0.5: copy/register
webkit2gtk3-javascriptcore-0.14.2.1: copy/register
dependent-map-0.2.4.0: copy/register
gi-webkit2-4.0.12: build
jsaddle-0.8.3.2: configure
jsaddle-0.8.3.2: build
prim-uniq-0.1.0.1: configure
prim-uniq-0.1.0.1: build
zenc-0.1.1: configure
zenc-0.1.1: build
prim-uniq-0.1.0.1: copy/register
reflex-0.5.0: configure (lib)
zenc-0.1.1: copy/register
reflex-0.5.0: build (lib)
gi-webkit2-4.0.12: copy/register
jsaddle-0.8.3.2: copy/register
jsaddle-webkit2gtk-0.8.3.1: configure
jsaddle-webkit2gtk-0.8.3.1: build
jsaddle-dom-0.8.0.0: configure
jsaddle-dom-0.8.0.0: build
reflex-0.5.0: copy/register
jsaddle-dom-0.8.0.0: copy/register
Progress: 13/18
--  While building package jsaddle-webkit2gtk-0.8.3.1 using:
      /home/roland/.stack/setup-exe-cache/x86_64-linux/Cabal-simple_mPHDZzAJ_1.24.2.0_ghc-8.0.2 --builddir=.stack-work/dist/x86_64-linux/Cabal-1.24.2.0 build --ghc-options " -ddump-hi -ddump-to-file"
    Process exited with code: ExitFailure 1
    Logs have been written to: /home/roland/Projekte/reflex-dom-stack/.stack-work/logs/jsaddle-webkit2gtk-0.8.3.1.log

    Configuring jsaddle-webkit2gtk-0.8.3.1...
    Building jsaddle-webkit2gtk-0.8.3.1...
    Preprocessing library jsaddle-webkit2gtk-0.8.3.1...
    [1 of 1] Compiling Language.Javascript.JSaddle.WebKitGTK ( src/Language/Javascript/JSaddle/WebKitGTK.hs, .stack-work/dist/x86_64-linux/Cabal-1.24.2.0/build/Language/Javascript/JSaddle/WebKitGTK.o )
    
    /tmp/stack1869/jsaddle-webkit2gtk-0.8.3.1/src/Language/Javascript/JSaddle/WebKitGTK.hs:73:9-54: error:
        Module
        ‘GI.WebKit2’
        does not export
        ‘userContentManagerRegisterScriptMessageHandler’
    
    /tmp/stack1869/jsaddle-webkit2gtk-0.8.3.1/src/Language/Javascript/JSaddle/WebKitGTK.hs:76:9-58: error:
        Module
        ‘GI.WebKit2’
        does not export
        ‘mk_UserContentManagerScriptMessageReceivedCallback’
    
    /tmp/stack1869/jsaddle-webkit2gtk-0.8.3.1/src/Language/Javascript/JSaddle/WebKitGTK.hs:77:9-60: error:
        Module
        ‘GI.WebKit2’
        does not export
        ‘wrap_UserContentManagerScriptMessageReceivedCallback’
    
    /tmp/stack1869/jsaddle-webkit2gtk-0.8.3.1/src/Language/Javascript/JSaddle/WebKitGTK.hs:79:9-55: error:
        Module
        ‘GI.WebKit2’
        does not export
        ‘UserContentManagerScriptMessageReceivedCallback’
roland@goms:~/Projekte/reflex-dom-stack$ 

jsaddle-warp: stopPropagation sometimes doesn't work

e6ba1fc

This commit introduced some odd behaviour for macbooks: for us, closing a modal when an input was focused/blurred. Seems like stopPropagation is not being respected, or something - but the strange thing is it only happens when using tap to click, but not when using a mechanical click.

Error : Unexpected Duplicate. with Warp backend.

I keep getting this error when using the jsaddle-warp backend.
However the same exact reflex widget when using jsaddle-webkit2gtk will work perfectly fine.

To replicate this error:

git clone --recurse-submodule https://github.com/sheganinans/reflex-warp
cd reflex-warp
reflex-platform/try-reflex
nix-shell -A shells.ghc
cabal new-repl warp-reflex
main

Connect a web browser to http://localhost:3911, and click the button a few times and check the output in the cabal repl. Soon enough the error will show up and the webapp will freeze.

However if you instead run cabal new-repl webkit-reflex and try pushing the button, the app will work exactly as expected.

Jsaddle+Reflex breaking when calling `networkHold` for a large data set (~80kb)

I've been trying to isolate this issue as much as I could, doing varying tests due to my unfamiliarity with the system, just a heads up that my conclusions could be way off.

The issue is seemingly caused by a jsaddle wrapped reflex application calling widgetHold/networkHold (or it's networkView variant) on an Event that holds a somewhat large data type, in this case it's a record of the Extensible library that is about 87kb as a json. This leads to an infinite loop of synchronization attempts with a growing footprint in the XHR responses. The issue could be related to the blocking nature of the synchronicity mechanism discussed in here #51

If I were to pause the program in the browser and unpause it, then the view is resolved, jsaddle's synch loop stops and it is as if nothing happened.

Building the same application to a full stack web app with ghcjs yields no problem whatsoever as well as no apparent performance/side effects.

And the funny thing is that if I were to just embedded my json in the code as a large string, then the failure escape sequence becomes a completely different. The app breaks with the following message:

<interactive>: Network.Socket.sendBuf: resource vanished (Broken pipe)
<interactive>: kevent: does not exist (No such file or directory)
<interactive>: ConnectionClosed

I must conclude that these two issues share the underlying cause. Perhaps a segmentation fault bug with the c code? And again, this works just fine if I deploy locally as a web app.

No instance for (ToJSVal Value)

I recently encountered this error while building jsaddle-0.9.4.0:

[12 of 16] Compiling Language.Javascript.JSaddle.Value ( src/Language/Javascript/JSaddle/Value.hs, dist/build/Language/Javascript/JSaddle/Value.js_o )

src/Language/Javascript/JSaddle/Value.hs:567:15-21: error:
    • No instance for (ToJSVal Value) arising from a use of ‘toJSVal’
    • In the expression: toJSVal
      In an equation for ‘valMakeJSON’: valMakeJSON = toJSVal

Anyone come across this?

jsaddle-webkit2gtk: "Not allowed to load local resource"

I'm trying to include a javascript+css widget library from a reflex-dom app compiled with native jsaddle-webkit2gtk.
WebKit refuses:

file:///XXX/index.html:247:76: CONSOLE ERROR Not allowed to load local resource: file:///XXX/node_modules/onsenui/css/onsenui.css
file:///XXX/index.html:247:76: CONSOLE ERROR Not allowed to load local resource: file:///XXX/node_modules/onsenui/css/onsen-css-components.css
file:///XXX/index.html:247:76: CONSOLE ERROR Not allowed to load local resource: file:///XXX/style.css
file:///XXX/index.html:247:76: CONSOLE ERROR Not allowed to load local resource: file:///XXX/node_modules/onsenui/js/onsenui.js

The files are referenced via relative path URLs from my app.

Should a native app refuse to access file URLs? Is there a different way for loading resources in a native app?

Sync callbacks in jsaddle-warp

Currently all callbacks are handled asynchronously when using the jsaddle-warp runner. This means functions that need to be run in the context of a callback like preventDefault do not work.

We need a way to block the JavaScript thread while waiting a response from the jsaddle-warpserver. This should be possible using the (sadly deprecated) synchronous XMLHttpRequest send. If not we may need to do this as some kind of browser extension.

Callbacks freed too early

The removeEventListener is sometimes called after the callback handler was freed. This results in calls being made to an already freed event handler. One way to reproduce this issue was to rapidly type and press enter to create multiple items in the reflex-todomvc-wkwebview example.

default to gtk3; tests hang on server

Preprocessing test suite 'test-tool' for jsaddle-0.3.0.1...
[1 of 1] Compiling Main             ( tests/DocTest.hs, dist/build/test-tool/test-tool-tmp/Main.o )
Linking dist/build/test-tool/test-tool ...
> /tmp/stackage-build8/jsaddle-0.3.0.1$ dist/build/test-tool/test-tool

src/Language/Javascript/JSaddle/Monad.hs:50:8:
    Ambiguous module name ‘Graphics.UI.Gtk.General.General’:
      it was found in multiple packages:
      gtk3-0.14.2@gtk3_LQL6kFfZwEeK6nO9fGGRs5 gtk-0.14.2@gtk_IthCkrmZyC49kGQu4HvvO2

src/Language/Javascript/JSaddle/Test.hs:22:8:
    Ambiguous module name ‘Graphics.UI.Gtk’:
      it was found in multiple packages:
      gtk3-0.14.2@gtk3_LQL6kFfZwEeK6nO9fGGRs5 gtk-0.14.2@gtk_IthCkrmZyC49kGQu4HvvO2

src/Language/Javascript/JSaddle/Test.hs:31:8:
    Ambiguous module name ‘Graphics.UI.Gtk.General.Enums’:
      it was found in multiple packages:
      gtk3-0.14.2@gtk3_LQL6kFfZwEeK6nO9fGGRs5 gtk-0.14.2@gtk_IthCkrmZyC49kGQu4HvvO2

jsaddle-warp does not seem to handle multiple clients well

It seems that jsaddle-warp does not properly handle multiple browser connections well. It seems that they get mixed somehow. I just had the issue, that one private tab requested data from the server and it showed up in the GUI of the other tab, when I closed the private tab. (It did not show up in the private tab at all).

Also when tracing what gets sent to the server it seems that data gets mixed. Can this be the case? Is jsaddle-warp designed to handle multiple connections well?

Is printing to stdout swallowed mistakenly when running with `debug` in ghcid?

If I have a Main.hs like so:

import            Control.Monad.IO.Class
import            Language.Javascript.JSaddle
import            Language.Javascript.JSaddle.Warp

main = do
  liftIO $ print 1
  debug 3197 $ do
    liftIO $ print 2
    eval $ textToStr "document.write('3')"
    liftIO $ print 4

And run

$ nix-shell -p 'haskell.packages.ghc822.ghcWithPackages (p: with p; [(haskell.lib.dontCheck jsaddle-warp)])' -p haskellPackages.ghcid -j4 --run 'ghcid Main.hs -T main'

Then navigate to http://localhost:3197

On stdout, I'd hope to see:

1
<a href="http://localhost:3197">run</a>
2
4

And instead I only see

1
<a href="http://localhost:3197">run</a>
<interactive>: threadWait: invalid argument (Bad file descriptor)

If I change to

import            Control.Concurrent
import            Control.Monad.IO.Class
import            Language.Javascript.JSaddle
import            Language.Javascript.JSaddle.Warp

main = do
  liftIO $ print 1
  debug 3197 $ do
    liftIO $ print 2
    eval $ textToStr "document.write('3')"
    liftIO $ print 4

  threadDelay $ 1000 * 1000 * 5

Then I'll see a bit more:

1
<a href="http://localhost:3197">run</a>
<interactive>: threadWait: invalid argument (Bad file descriptor)
2
4

But surely the delay is counterintuitive and shouldn't be necessary, right?

Could fixing it perhaps be as simple as having a variant of debug that doesn't forkIO inside? As GHCid issues an interrupt anyway.

Could I try such a variant easily somehow? Looking at the source here it's not immediately apparent to me how to make a non-forking variant unfortunately.

And yet another unfortunate attribute is that in a larger codebase of mine (which I am attempting to port over to use JSaddle) I can't even seem to use the threadDelay workaround. One thing or another causes ghc(i(d)) to hang on "Reloading..." when I do that. Meaning that currently, seemingly I have to choose between being able to see stdoutput during development or being able to do auto-refresh. Both of which I find rather important to have at the same time.
This I haven't been able to narrow down to such a small reproducible case as above yet, so my current hope is that if we fix the above error in general and make JSaddle.debug + ghcid + stdout work together nicely then this error will vaporize too.

stack test fails for jsaddle-0.3.0.2

I ran "stack test":

$ cabal unpack jsaddle-0.3.0.2
$ cd jsaddle-0.3.0.2
$ stack --resolver nightly init
$ stack test
jsaddle-0.3.0.2: test (suite: test-tool)

<command-line>:8:0:
     fatal error: dist/build/autogen/cabal_macros.h: No such file or directory
compilation terminated.
test-tool: test-tool: phase `C pre-processor' failed (exitcode = 1)

Test suite failure for package jsaddle-0.3.0.2
    test-tool:  exited with: ExitFailure 1
Logs printed to console

very confusing. [name/description conflict]

This project (referenced at the bottom of the ghcjs readme) has a very unfortunate name, as:

There already is a jsc which could also be described, quite exactly, as a

high level interface for webkit-javascriptcore

And is part and parcel of WebKit and JavaScriptCore proper.

The utility is not unrelated to ghcjs, since it (potentially) could be used as its interpreter.
(OS X: /System/Library/Frameworks/JavaScriptCore.framework/Resources/jsc [script.js])

Perhaps consider a rename before the "big release"?
Or at very least, documenting that the two jsc's are unrelated?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.