Skip to content

dmjio/miso

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

1,823 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

miso

A Haskell library for building web and mobile applications

Matrix #haskell-miso:matrix.org Cachix Build Status Hackage

miso is a component-oriented Haskell library for building web and mobile applications. It is pure by default; side effects are introduced explicitly through the Effect type. The library is designed in the spirit of Elm and draws inspiration from React including Component, Fragment and Props.

Key features

  • Virtual DOM with a recursive diffing and patching algorithm
  • Attribute and property normalization, event delegation, and event batching
  • SVG, 2D Canvas, and WebGL (via three.js) rendering
  • Fetch, Server-Sent Events, and WebSocket support
  • Type-safe client-side routing
  • An extensible subscription-based subsystem for long-running effects
  • Reactive extensions for fine-grained reactivity

It makes heavy use of the GHC JavaScript FFI and maintains minimal dependencies, and can be considered a shallow embedded domain-specific language for modern web programming. Compilation targets include JavaScript and WebAssembly via GHC. Hot reload is provided through WASM browser mode integrated with ghciwatch.

Tip

See the Haskell miso organization on GitHub for the full ecosystem of packages and examples 🍜

Table of Contents

Playground πŸ›

An interactive playground is available at try.haskell-miso.org. It allows editing and running applications directly in the browser without any local toolchain setup, and is useful for experimentation and sharing minimal reproducible examples.

Quick Start (Nix) ⚑

Tip

The miso-sampler template repository includes a counter application with build scripts for WebAssembly, JavaScript, and native GHC targets.

The following requires Nix Flakes. See also Binary cache to avoid rebuilding dependencies.

# Install nix 
curl -L https://nixos.org/nix/install | sh

# Enable flakes
echo 'experimental-features = nix-command flakes' >> ~/.config/nix/nix.conf

# Clone, build and serve
git clone https://github.com/haskell-miso/miso-sampler && cd miso-sampler
nix develop .#wasm --command bash -c 'make && make serve'

Manual Setup (GHCup / Cabal)

To develop applications without Nix, acquire GHC and cabal via GHCup.

Tip

For users new to Haskell tooling, GHCup is the recommended way to install both GHC and cabal.

A minimal application requires three files:

  • cabal.project
  • app.cabal
  • Main.hs

cabal.project

packages:
  .

source-repository-package
  type: git
  location: https://github.com/dmjio/miso
  branch: master

Note

Pinning to a specific tag: or commit: rather than branch: master is recommended for reproducible builds.

app.cabal

Using cabal-version: 2.2 or later enables common stanzas, which allow a single .cabal file to target both the WASM and JS backends.

cabal-version: 2.2
name: app
version: 0.1.0.0
synopsis: Sample miso app
category: Web

common options
  if arch(wasm32)
    ghc-options:
      -no-hs-main
      -optl-mexec-model=reactor
      "-optl-Wl,--export=hs_start"
    cpp-options:
      -DWASM

  if arch(javascript)
     ld-options:
       -sEXPORTED_RUNTIME_METHODS=HEAP8

executable app
  import:
    options
  main-is:
    Main.hs
  build-depends:
    base, miso
  default-language:
    Haskell2010

Main.hs

A counter application demonstrating the Model-View-Update pattern:

----------------------------------------------------------------------------
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE LambdaCase        #-}
{-# LANGUAGE CPP               #-}
----------------------------------------------------------------------------
module Main where
----------------------------------------------------------------------------
import           Miso
import qualified Miso.Html as H
import           Miso.Lens
----------------------------------------------------------------------------
-- | Sum type for App events
data Action
  = AddOne
  | SubtractOne
  | SayHelloWorld
  deriving (Show, Eq)
----------------------------------------------------------------------------
-- | Entry point for a miso application
main :: IO ()
main = startApp defaultEvents app
----------------------------------------------------------------------------
-- | WASM export, required when compiling w/ the WASM backend.
#ifdef WASM
foreign export javascript "hs_start" main :: IO ()
#endif
----------------------------------------------------------------------------
-- | `vcomp` takes as arguments the initial model, update function, view function
app :: App Int Action
app = vcomp 0 updateModel viewModel
----------------------------------------------------------------------------
-- | Updates model, optionally introduces side effects
updateModel :: Action -> Effect parent props Int Action
updateModel = \case
  AddOne -> this += 1
  SubtractOne -> this -= 1
  SayHelloWorld -> io_ $ do
    alert "Hello World"
    consoleLog "Hello World"
----------------------------------------------------------------------------
-- | Constructs a virtual DOM from a model
viewModel :: () -> Int -> View Int Action
viewModel _props x = vfrag
    [ H.button_ [ H.onClick AddOne ] [ text "+" ]
    , text (ms x)
    , H.button_ [ H.onClick SubtractOne ] [ text "-" ]
    , H.br_ []
    , H.button_ [ H.onClick SayHelloWorld ] [ text "Alert Hello World!" ]
    ]
----------------------------------------------------------------------------

Hot Reload πŸ”₯

Hot reload is supported via WASM browser mode and ghciwatch. This provides incremental recompilation with automatic browser refresh on file changes. See the miso-sampler browser mode documentation for setup instructions.

Installation

See Installation for platform-specific installation instructions.

Haddocks

Official API reference. See also the Miso module for a guided entry point into the library.

Platform URL
GHCJS Link
GHC Link

Wiki

See the DeepWiki entry for an AI-assisted exploration of the source code.

Ask DeepWiki

Architecture

miso follows the Model-View-Update (MVU) pattern. A Component is parameterized by a model type and an action type. The update function maps actions to Effect values β€” a monad over the Reader/Writer/State stack β€” which can both modify the model and schedule IO operations. Long-running effects are expressed as Subscriptions that push actions into the component via a Sink.

For (client/server) applications, the recommended layout is a single .cabal file with separate executable stanzas conditioned on the compiler target. An example of this structure is the haskell-miso.org source.

Tip

For a worked example of a Nix-based client/server deployment, see the nix scripts for haskell-miso.org.

Examples

Examples are hosted under the haskell-miso GitHub organization. Each repository contains its own build instructions. The recommended approach is to build via nix.

Tip

Use cachix to avoid rebuilding shared dependencies: cachix use haskell-miso-cachix

Name Description Source Demo Author
TodoMVC TodoMVC reference implementation Source Demo @dmjio
2048 Clone of the 2048 sliding-tile game Source Demo @ptigwe
Flatris Tetris variant Source Demo @ptigwe
Plane Flappy-bird-style game Source Demo @Lermex
Snake Classic Snake game Source Demo @lbonn
SVG SVG rendering Source Demo @dmjio
Fetch HTTP API interaction via Fetch Source Demo @dmjio
File Reader FileReader API Source Demo @dmjio
Mario Physics-based platformer Source Demo @dmjio
WebSocket WebSocket communication Source Demo @dmjio
Router Client-side routing Source Demo @dmjio
Canvas 2D 2D Canvas rendering Source Demo @dmjio
MathML MathML rendering Source Demo @dmjio
Simple Counter (minimal example) Source Demo @dmjio
SSE Server-Sent Events Source Demo @dmjio
Three.js 3D rendering via Three.js Source Demo @juliendehos
Space Invaders Space Invaders clone Source Demo @juliendehos
Audio Audio playback Source Demo @juliendehos
Video Video playback Source Demo @juliendehos
WebVR WebVR via A-Frame Source Demo @dmjio
Reactivity Fine-grained reactive updates Source Demo @dmjio
Chess Chess game Source Demo @dmjio

Interacting with HTTP APIs πŸ”Œ

Two approaches are supported:

  1. For simple JSON-based APIs, use the Fetch module directly.

  2. For more complex cases, define a Servant API and derive client functions via servant-miso-client.

    The Fetch example (Demo) demonstrates the required setup. Add the following to cabal.project to use servant-miso-client:

    source-repository-package
      type: git
      location: https://github.com/haskell-miso/servant-miso-client
      tag: master
    

Testing βœ…

The test suite spans three layers:

  • Unit tests β€” the TypeScript runtime (virtual DOM, diffing, event delegation) is tested with bun, covering the core diff engine and supporting utilities.
  • Integration tests β€” Haskell internals are exercised via a WASM test suite that runs the runtime in a headless browser environment, verifying component lifecycle, subscriptions, and state transitions.
  • End-to-end tests β€” selected applications such as TodoMVC are tested end-to-end against a live browser to validate full-stack rendering and event handling.

A full coverage report for the TypeScript layer is available at coverage.haskell-miso.org.

Note

To run the TypeScript tests, install bun first.

$ curl -fsSL https://bun.sh/install | bash

or

$ nix-env -iA bun -f '<nixpkgs>'

and

$ bun install && bun run test

Native πŸ“±

iOS and Android applications are supported via LynxJS. See the miso-lynx repository for details.

Benchmarks 🏎️

According to benchmarks, miso performs competitively relative to other frameworks.

Nix nixos-snowflake

Nix provides a reproducible environment for building, configuring, and deploying applications. The haskell-miso.org source serves as a reference for this workflow.

Pinning nixpkgs πŸ“Œ

By default, miso uses a pinned version of nixpkgs known as pkgs.

Note

miso also maintains a legacyPkgs nixpkgs pin for tools such as nixops and for builds using the original GHCJS 8.6 backend.

Binary cache

Linux and macOS users can use a binary cache to avoid rebuilding dependencies. Follow the setup instructions on cachix.

$ cachix use haskell-miso-cachix

For CI pipelines using GitHub Actions:

- name: Install cachix
  uses: cachix/cachix-action@v16
  with:
    name: haskell-miso-cachix

Community :octocat:

Maintainers

@dmjio

Commercial πŸš€

Since its launch, miso has been deployed across a range of domains, including quantitative finance, network security, defense research, academia, SaaS, the public sector, and non-profit organizations. The largest known deployment consisted of approximately 200,000 LOC serving over 10,000 users.

Contributing

Contributions are welcome. Open an issue or submit a pull request.

See CONTRIBUTING for guidelines.

Contributors 🦾

Note

This project exists thanks to all the people who contribute.

Partnerships 🀝

For inquiries regarding feature sponsorship or corporate partnerships, contact support@haskell-miso.org.

Backers

Become a financial contributor to help sustain the project.

organizations

Support this project with your organization. Your logo will appear here with a link to your website.

History πŸ“œ

miso is a portmanteau of micro and isomorphic.

miso was initiated in 2016 as a research project exploring two directions:

The project addresses the JavaScript problem in Haskell by providing component abstractions and rendering primitives familiar to practitioners of frameworks such as React and Vue.js. The library has since expanded to include multiple rendering backends and native mobile support for iOS, Android, and HarmonyOS via LynxJS.

License

BSD3 Β© dmjio