Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Miso and jsaddle friendly wrapper around XHR #594

Closed
niteria opened this issue Jun 14, 2020 · 9 comments
Closed

Miso and jsaddle friendly wrapper around XHR #594

niteria opened this issue Jun 14, 2020 · 9 comments

Comments

@niteria
Copy link
Contributor

niteria commented Jun 14, 2020

Is your feature request related to a problem? Please describe.
Currently, the Miso's XHR example can't be used directly with jsaddle, because it uses JavaScript.Web.XMLHttpRequest which comes from ghcjs-base which is JSFFI only.

Describe the solution you'd like
There's an alternative that supports both jsaddle and JSFFI which is https://hackage.haskell.org/package/ghcjs-dom. Unfortunately, it's a more low-level API, a thin wrapper around JS functions.

Reflex uses ghcjs-dom to provide some higher level functions: http://hackage.haskell.org/package/reflex-dom-core-0.6.0.0/docs/src/Reflex.Dom.Xhr.html#postJson

It would be nice to have something similar for Miso.

@niteria
Copy link
Contributor Author

niteria commented Jun 14, 2020

Perhaps the way to approach this is in Miso-agnostic way and reimplement the JavaScript.Web.XMLHttpRequest API with ghcjs-dom and release it as a separate library.

Feel free to close this if you consider it out of scope.

@DoctorRyner
Copy link

Oh, I implemented something like this a while ago. On a basic level though

@DoctorRyner
Copy link

DoctorRyner commented Jun 14, 2020

I made 3 packages:

  1. https://github.com/DoctorRyner/miso-spa

It allows you to quickly set up your application for development. In opposite to jsaddle-warp's run and debug, Miso.SPA.Server.{run,debug} redirect every request to root and serve static content in a static/ folder. It also has some helpful data structures and function to use in miso

  1. https://github.com/DoctorRyner/miso-http

A very basic wrapper around XHR that works with ghc and ghcjs.

You can see it's usage here: https://github.com/DoctorRyner/haskell-app-reactor/blob/a13e26dd2def53538e520dd65f9c19118f6566b8/gui/src/Update.hs#L16

-- It's basic and easy to use
Http.send get { url = "/locale/ru.json" }

-- To extract the result you can use fromResp or fromRespDebug
fromResp resp model $ \locale -> model { locale = locale }

You need just 2 constructors for your actions, that fires request and that catches it's result: https://github.com/DoctorRyner/haskell-app-reactor/blob/a13e26dd2def53538e520dd65f9c19118f6566b8/gui/src/Types.hs#L12

The Response data type is defined here: https://github.com/DoctorRyner/miso-spa/blob/6ac0758f9e70f95be4388c2b773b89b5ede6a4f2/src/Miso/SPA/Types.hs#L27

  1. https://github.com/DoctorRyner/miso-styled

It's like elm-css or styled-components, an example of usage is here: https://github.com/DoctorRyner/haskell-app-reactor/blob/a13e26dd2def53538e520dd65f9c19118f6566b8/gui/src/View.hs#L16

Where mempty has Css type from https://hackage.haskell.org/package/clay-0.13.1

Also, like in Elm, Miso.Styled.View is it's own data type, so you need to use toUnstyled :: Miso.Styled.View -> Miso.View

Like here: https://github.com/DoctorRyner/haskell-app-reactor/blob/a13e26dd2def53538e520dd65f9c19118f6566b8/gui/src/App.hs#L16

##########

Just for notice, these are very low-quality packages that were made in haste for urgent order. So I just share some of my work that can be useful, I doubt that I will touch it ever again anyways

https://github.com/DoctorRyner/miso-http/blob/master/src/Miso/Http.hs

This can be too high-level and inflexible, but I think it's possible to use it as a reference to implement something more useful in a couple of days

@niteria
Copy link
Contributor Author

niteria commented Jun 14, 2020

@DoctorRyner

https://github.com/DoctorRyner/miso-http/blob/master/src/Miso/Http.hs looks good enough for my needs, I will try to use it, thanks!

If I have any patches should I send them your way or just create a fork?

@dmjio
Copy link
Owner

dmjio commented Jun 14, 2020 via email

@DoctorRyner
Copy link

If I have any patches should I send them your way or just create a fork?

I guess creating a fork would be a better option

@niteria
Copy link
Contributor Author

niteria commented Jun 15, 2020

I went with https://github.com/haskell-servant/servant-jsaddle because it integrates nicely with servant.
There's one little thing I had to fix to get it working haskell-servant/servant-jsaddle#4.

If anyone is going this route https://github.com/DarinM223/miso-fullstack is worth checking out. It bypasses CORS issues that arise because jsaddle runs on a different port than your server. It does that by running a proxy to the server on the same port as jsaddle. It doesn't work with https, but that's a minor isssue because it's a development tool anyways.

I've tried a similar approach before with running the server on the same port as jsaddle, but run into issues because you effectively need 2 different versions of miso: one for the GHC on the server and one for GHC + jsaddle for the client.

With servant-jsaddle I see no need for direct XHR support in miso, so I'm closing this issue.

@niteria niteria closed this as completed Jun 15, 2020
@Rizary
Copy link

Rizary commented Nov 14, 2020

@niteria do you have any problem integrate servant-jsaddle with miso? I tried it but when I run cabal new-build --allow-newer I got the following error:

Warning: The package list for 'hackage.haskell.org' does not exist. Run 'cabal
update' to download it.
Resolving dependencies...
cabal: Could not resolve dependencies:
[__0] trying: todo-miso-0.1.0.0 (user goal)
[__1] trying: servant-jsaddle-0.16/installed-IDf... (dependency of todo-miso)
[__2] trying: servant-client-core-0.16/installed-6JI... (dependency of
servant-jsaddle)
[__3] next goal: miso (dependency of todo-miso)
[__3] rejecting: miso-1.7.1.0/installed-DDR... (conflict: servant-client-core
=> servant==0.16/installed-82I..., miso => servant==0.15/installed-IXd...)
[__3] fail (backjumping, conflict set: miso, servant-client-core, todo-miso)
After searching the rest of the dependency tree exhaustively, these were the
goals I've had most trouble fulfilling: todo-miso, miso, servant-client-core,
servant-jsaddle

I don't understand why miso need servant==0.15

@niteria
Copy link
Contributor Author

niteria commented Nov 14, 2020

@niteria do you have any problem integrate servant-jsaddle with miso? I tried it but when I run cabal new-build --allow-newer I got the following error:

Yeah, it took a bit of wrestling with Nix at a time. I wrote up what I learned here http://niteria.github.io/posts/nix-notes-overriding-haskell-packages/. I think you might find my nixpkgs.nix useful:

let

  bootstrap = import <nixpkgs> {};

  misoTarball = bootstrap.fetchFromGitHub {
    owner = "dmjio";
    repo = "miso";
    rev = "ea25964565074e73d4052b56b60b6e101fa08bc5";
    sha256 = "1yb9yvc0ln4yn1jk2k5kwwa1s32310abawz40yd8cqqkm1z7w6wg";
  };

  servant-jsaddle = bootstrap.fetchFromGitHub {
    owner = "haskell-servant";
    repo = "servant-jsaddle";
    rev = "2ccf13d185e26d4cb4a51622e748ec64336435f4";
    sha256 = "066vr1rfq6bjn3xx9g52z2vgp1ibyz50z3hzwaqq3fzxnr2srpjs";
  };


  ghc865 = (pkgs.haskell.packages.ghc865.override {
    all-cabal-hashes = pkgs.fetchurl {
      url = "https://github.com/commercialhaskell/all-cabal-hashes/archive/8c7bdd9ad4bc3671b4214e32766873d443af2622.tar.gz";
      sha256 = "0q9qdpvn3c64rwnafcqkzzyi4z72mvvwmvn06d89fnzfpqjxvwx2";
    };
  }).extend (self: super: {
      haxl = self.callHackage "haxl" "2.1.2.0" {};
      clay = self.callHackage "clay" "0.13.3" {};
      http-proxy = pkgs.haskell.lib.dontCheck (pkgs.haskell.lib.doJailbreak (self.callHackage "http-proxy" "0.1.1.0" {}));
      servant-client-core = self.callHackage "servant-client-core" "0.16" {};
      servant = self.callHackage "servant" "0.16" {};
      servant-server = self.callHackage "servant-server" "0.16" {};
      servant-lucid = self.callHackage "servant-lucid" "0.9" {};
      servant-jsaddle = pkgs.haskell.lib.dontCheck (self.callCabal2nix "servant-jsaddle" servant-jsaddle {});
    }
  );

  ghcjs86 = (pkgs.haskell.packages.ghcjs86.override {
    all-cabal-hashes = pkgs.fetchurl {
      url = "https://github.com/commercialhaskell/all-cabal-hashes/archive/8c7bdd9ad4bc3671b4214e32766873d443af2622.tar.gz";
      sha256 = "0q9qdpvn3c64rwnafcqkzzyi4z72mvvwmvn06d89fnzfpqjxvwx2";
    };
  }).extend (self: super: {
      servant-client-core = self.callHackage "servant-client-core" "0.16" {};
      servant = self.callHackage "servant" "0.16" {};
      servant-jsaddle = pkgs.haskell.lib.dontCheck (ghcjs86.callCabal2nix "servant-jsaddle" servant-jsaddle {});
    }
  );

  miso = import "${misoTarball}" { nixpkgsConfig = { allowBroken = true; } ; } ;

  inherit (miso) pkgs;

  pkgsWithGHC = pkgs // {
    haskell = pkgs.haskell // {
      packages = pkgs.haskell.packages // {
        ghc865 = ghc865;
        ghcjs86 = ghcjs86;
      };
    };
  };

in pkgsWithGHC

Note that it points to unmerged haskell-servant/servant-jsaddle@2ccf13d, for me the package was unusable without that patch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants