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

Port frontend to Haskell, using Miso and the GHC Wasm backend #56

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

georgefst
Copy link
Owner

@georgefst georgefst commented Jan 15, 2025

This is very much a proof of concept. Running nix shell gitlab:haskell-wasm/ghc-wasm-meta?rev=56dfe2478cae35ded335261c854bb8b2a5e7f4d2#all_9_10 -c ./run-wasm.sh will run a basic web server with a test playground copied from Scratch.elm. We have not yet hooked this up to the Monpad backend, or removed most of the redundant Elm stuff. The most important file, Frontend.hs is still a total mess, including some commented-out Elm code for things which haven't been ported yet, and there are also still some TODOs in monpad.cabal. We'll want to fix up the initial commit before merging, and maybe separate out some changes like creating the monpad-core library.

I'm pausing work on this for now while waiting for the Wasm backend and its ecosystem to mature further, e.g. we'll need network support for websockets. I imagine we'll also need to use the threaded runtime in order for Miso's subs field to be useful, which will be required for receiving ServerUpdates.

Monpad has no proper tests, so the best way to verify that behaviour is unchanged after the port will be to try the new version with Ewephoria, which utilises almost every feature of the frontend, having inspired many of them.

@georgefst
Copy link
Owner Author

georgefst commented Jan 15, 2025

Performance is an issue. Slider and stick movement is noticeably a little laggy on my phone, even with wasm-opt.

This isn't really surprising. The current simple declarative approach results in a lot of repeated work. For example, when a slider is moving, we recompute the whole diagram on every frame, then Miso diffs the whole resulting SVG before seeing that only a tiny part of it has actually changed. What we should really do is cache the base layer for each layout, and only redraw what's necessary. For sliders, when moving, all that should change are the foreground element's x and y values1, so we should do this outside of the diagrams library. Indicator elements will be a bit different, since the shapes can change based on events like SetIndicatorArcEnd, but we should at least only redraw the element rather than the whole diagram.

Another option would be to have elements be properly-encapsulated components, in that they'd have a local rendering function, which isn't run if its state hasn't changed. I'm not certain on any of this, but I think this is one of the benefits of React functional components, and Miso "components" don't do this, but Halogen does. So I'd seriously consider using the Haskell version of Halogen, but I'm reluctant to pick JS over Wasm: Swordlash/haskell-halogen#2.

As for why we didn't have noticeable performance issues previously, elm-collage is heavily inspired by diagrams and I don't think it did anything particularly clever performance-wise, so it's probably just that it's a much simpler library without anywhere near the same level of generality and abstraction2. I'd expect the actual geometric calculations to be faster with GHC-generated WASM than with Elm-generated JS, though I haven't benchmarked this.

Compressed output size is up to 788KB, from 23KB for Elm. This is the one thing that's pretty much guaranteed to remain worse in the long term, but it's really not big in this day and age. And if users have terrible connection speeds then we've got other problems, since the frontend will be constantly sending events to the server, and significant latency would make it unusable.

Footnotes

  1. We could instead use CSS transforms if this is likely to be more performant, or even the drag and drop API.

  2. Another result of this is that the generated SVG is now quite a lot more complex, since for example it uses path where rect would suffice, as diagrams throws away too much info before reaching the backend. I wouldn't expect this to matter much in practice.

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

Successfully merging this pull request may close these issues.

1 participant