miso
Copyright(C) 2016-2026 David M. Johnson (@dmjio)
LicenseBSD3-style (see the file LICENSE)
MaintainerDavid M. Johnson <code@dmj.io>
Stabilityexperimental
Portabilitynon-portable
Safe HaskellNone
LanguageHaskell2010

Miso

Description

Miso 🍜

miso is a library for building web and native user interface applications in Haskell. See the GitHub group.

It provides a React-like programming experience for a simple Haskell dialect that emphasizes

  • performance
  • purity
  • simplicity
  • extensibility
  • composability

miso supports common areas that arise naturally in web development:

  • DOM manipulation: miso uses a Virtual DOM with diffing algorithm that is responsible for all DOM modification and Component lifecycle hooks.
  • Event delegation: All event listeners are attached to a top-level element (typically <body>). When raised, events are routed through the virtual DOM to Haskell event handlers which cause application state changes. Internally miso virtualizes both the capture and bubble phases of the browser when it performs event routing.
  • Prerendering: Prerendering is a process where the server delivers HTML to the client before the JavaScript (or Web Assembly) application bootstraps. Instead of performing an initial draw, the application will create and populate the virtual DOM from the actual DOM. This is a process known as "hydration". This avoids unnecessary page draws on initial page load and enhances search engine optimization. miso provides its own HTML rendering (Miso.Html.Render) to render HTML on the server and the miso function exists on the client to "hydrate" the virtual DOM with the DOM.
  • Components: A Component can be considered an instance of a miso application. A Component contains user-defined state, logic for updating this state, and a function for creating UI templates from this user-defined state. Component can nest other Component because miso is defined recursively.
  • Custom renderers: The underlying DOM operations are able to be abstracted. This allows a custom rendering engine to be used. This is seen in the miso-lynx project (which allows miso to target mobile phone devices).
  • Lifecycle hooks: Component expose mount and unmount lifecycle hooks. This allow users to define custom logic that will execute when a Component mounts or unmounts. onCreated and onDestroyed are VNode specific lifecycle hooks. These hooks are commonly used for Component communication and for third-party integration with JavaScript libraries.
  • State management: Component model state can be manipulated using Miso.Lens or Miso.State in response to application events.

The Model-View-Update pattern

The core type of miso is Component. The Component API adheres to the Elm MVU (model-view-update) interface. This is similar to a left-fold, where the Component model will be updated via a list of action given a specific update function, and rendered via view.

  • model: This can be any user-defined type in Haskell. An Eq constraint is required. We recommend using the default derived Eq instance.
  • view: view :: model -> View model action This is the templating function that is used to construct a new virtual DOM (or HTML if rendering on the server).
  • update: update :: action -> Effect parent model action The update function handles how the model evolves over time in response to events that are raised by the application. This function takes any action, updating the model and optionally introducing IO into the system.

Your first Component

To define a Component the component smart constructor can be used. Below is an example of a simple counter Component.

-----------------------------------------------------------------------------
module Main where
-----------------------------------------------------------------------------
import Miso
import Miso.Lens
import qualified Miso.Html.Element as H
import qualified Miso.Html.Event as HE
import qualified Miso.Html.Property as HP
-----------------------------------------------------------------------------
                       * - The type of the parent Component model
                       |     * - The type of the current Component's model
                       |     |    * - The type of the action that updates the model
                       |     |    |
counter :: Component parent Int Action
counter = component m u v
  where
    m :: Int
    m = 0

    u :: Action -> Effect parent Int Action
    u = \case
      Add -> this += 1
      Subtract -> this -= 1

    v :: Int -> View Int Action
    v x = H.div_
      [ H.button_ [ HE.onClick Add, HP.id_ "add" ] [ "+" ]
      , text (ms x)
      , H.button_ [ HE.onClick Subtract, HP.id_ "subtract" ] [ "-" ]
      ]
-----------------------------------------------------------------------------
main :: IO ()
main = startApp defaultEvents counter
-----------------------------------------------------------------------------
data Action
  = Add
  | Subtract
  deriving (Eq, Show)
-----------------------------------------------------------------------------

Running your first Component

The startApp (or miso) functions are used to run the above Component.

main :: IO ()
main = startApp defaultEvents counter

The startApp function is what we recommend using first. It sets up event listeners and performs the initial page draw. The startApp function assumes that <body> is empty, and it will begin drawing the Component View from <body>.

The miso function (and also the prerender function) assume that <body> has already been populated by the results of the view function. Instead of drawing, miso will perform hydration. If the structures do not match miso will fallback to drawing the page from scratch (clearing the contents of <body> first).

It is possible to execute an initial action when a Component is first mounted. See the mount (and similarly unmount) hooks.

data Action = Init

main :: IO ()
main = startApp defaultEvents counter { mount = Just Init }

update :: App model Action
update = \case
  Init -> io_ (consoleLog "hello world!")

Component composition

miso Component can contain other Component. This is accomplished through the Component mounting combinator (+>). This combinator is responsible for encoding a typed Component hierarchy, allowing Component type-safe read-only access to their parent model state.

This combinator unifies the parent model with the child parent, and subsequently the grandchild parent unifies with the child model. This gives us a correct-by-construction Component hierarchy.

(+>)
  :: forall child model action a . Eq child
  => MisoString
  -> Component model child action
  -> View model a
key +> vcomp = VComp [ Property "key" (toJSON key) ] (SomeComponent vcomp)

Practically, using this combinator looks like:

view :: Int -> View Int action
view x = div_ [ id_ "container" ] [ "counter" +> counter ]

You'll notice the "counter" string was specified. This is a unique Key to identify a Component at runtime. These keys are very important when diffing two Component together. When intentionally replacing Component it is important to specify a new Key, otherwise the Component will not be unmounted.

It is possible to mount a component using the mount_ function, which avoids specifying a key_, but this should only be used when the user is certain they will not be diffing their Component with another Component. When in doubt, use the (+>) combinator and key_ your Component.

Lastly, note also the signature of startApp.

startApp :: Eq model => Events -> App model action -> IO ()

The App type signature is a synonym for Component ROOT

type App model action = Component ROOT model action

ROOT is a type tag that encodes a Component as top-level. Which means it has no parent, hence we mark parent as ROOT.

data ROOT

startApp and miso will always infer parent as ROOT.

VComp lifecycle hooks

Component are mounted on the fly during diffing. All Component are equipped with mount and unmount hooks. This allows the defining of custom actions that will be processed in response to lifecycle events.

VNode lifecycle hooks

Similar to Component lifecycle hooks, all VNode also expose lifecycle hooks.

This is convenient for initializing and deinitializing third-party libraries (as seen below with highlight.js)

{-# LANGUAGE QuasiQuotes -#}
{-# LANGUAGE MultilineStrings -#}

import Miso
import Miso.FFI.QQ (js)

data Action = Highlight DOMRef

update :: Action -> Effect parent model Action
update = \case
  Highlight domRef -> io_ $ do
    [js| hljs.highlight(${domRef}) |]

view :: model -> View model Action
view x =
  code_
  [ onCreatedWith Highlight
  ]
  [ """
    function addOne (x) { return x + 1; }
    """
  ]

Key

A Key is a unique identifier used to optimize diffing.

Virtual DOM nodes can be "keyed" (See key_). Keys have multiple meanings in miso (and react).

  • Keys are used to optimize child node list diffing.

When two lists of elements are being diffed, as long as they all have unique keys, diffing large child lists will be much faster. This optimization automatically occurs when all the elements in a VNode child list contain unique keys. Unless all View nodes in a child list are keyed, this optimization will not fire.

  • Keys are used to compare two identical nodes.

If two VNode are being compared (or two VComp) and their keys differ, the old node will be destroyed and a new one created. Otherwise, the underlying DOM node won't be removed, but its properties will be diffed. In the case of diffing two Component (the VComp case), if the keys differ, the unmount phase will be triggered for the old VComp and the mount phase will be triggered for the new Component. The underlying DOM reference will be replaced.

See the key_ property for usage (and smart constructors like textKey_ and (+>) as well).

ul_
  []
  [ li_ [ key_ "key-1" ] [ "a" ]
  , li_ [ key_ "key-2" ] [ "b" ]
  , "key-3" +> counter
  , textKey "key-4" "text here"
  ]

View DSL

The View type is the core type for templating a web page. It is similar to a Rose tree data structure. This is how the Virtual DOM is constructed. It is mutually recursive with the Component type (via the view function), which allows us to embed Component inside other Component.

data View model action
  = VNode Namespace Tag [Attribute action] [View model action]
  | VText (Maybe Key) MisoString
  | VComp [Attribute action] (SomeComponent model)

VNode and VText have a one-to-one mapping from the virtual DOM to the physical DOM. The VComp constructor is abstract and does not contain a reference to the physical DOM. The existential type of SomeComponent is defined recursively in terms of View and is what allows us to embed other polymorphic Component.

data SomeComponent parent
  = forall model action . Eq model
  => SomeComponent (Component parent model action)

The smart constructors:

are used to build VNode, VText and VComp respectively. A list of all the smart constructors defined in terms of node (e.g. div_) can be found in Miso.Html.Element.

Events

  • Event Delegation

By default all events are delegated through <body>. Miso supports both capture and bubble phases of browser events. Users can handle both phases in their applications.

  • Using events

Miso exposes a defaultEvents for convenience, these events are commonly used events and listened for on <body>. They get routed through the View to the virtual DOM node that raised the event. Other Events are exposed as conveniences (e.g. touchEvents). All events required by all Component must be combined together for use when running your application (e.g. keyboardEvents <> touchEvents).

touchEvents :: Events
touchEvents = M.fromList
  [ ("touchstart", BUBBLE)
  , ("touchcancel", BUBBLE)
  , ("touchmove", BUBBLE)
  , ("touchend", BUBBLE)
  ]
  • Defining event handlers

Users can define their own event handlers using the on combinator. By default this will define an event in the BUBBLE phase. See onCapture for handling events during the CAPTURE phase. See the the module Miso.Html.Event for many predefined events.

onChangeWith :: (MisoString -> DOMRef -> action) -> Attribute action
onChangeWith = on "change" valueDecoder
  • Decoding events

After an event has been raised, one can extract information from the event for use in their application. This is accomplished through a Decoder. Many common decoders are available for use in Miso.Event.Decoder.

data Decoder a
  = Decoder
  { decoder :: Value -> Parser a
  , decodeAt :: DecodeTarget
  }

-- | Example of a custom Decoder for the value property of an event target.
valueDecoder :: Decoder MisoString
valueDecoder = Decoder {..}
  where
    decodeAt = DecodeTarget ["target"]
    decoder = withObject "target" $ \o -> o .: "value"

Attributes / Properties

The Attribute type allows us to define web handlers that map browser events to Haskell data types (e.g. onClick), along with specifying properties on DOM elements (like className and id_). See Miso.Property and Miso.Html.Property for more information.

div_ [ id_ "some-id", className "some-class" ] [ ]

Effect

The Effect type is used to mutate the model over time in response to action. This allows IO to be scheduled for evaluation by the miso scheduler.

Note: IO is never evaluated inside of Effect, it is only scheduled. There is no MonadIO instance for Effect.

The Effect type is defined as a RWS.

type Effect parent model action = RWS (ComponentInfo parent) [Schedule action] model ()

IO can be performed either synchronoulsy or asynchronously. By default all IO is asynchronous

Asynchronous IO

  • io: Used to introduce asynchronous io into the system, see also the io_ variant.
  • withSink: The core function (from which most other combinators are defined) that gives users access to the underlying event Sink. This also allows us to introduce IO into the system. The miso scheduler attaches exception handlers to all IO actions.
  • For maximum flexibility, the MonadWriter instance (tell) can be used to schedule IO (see the withSink implementation).

Synchronous IO

  • sync: Forces the scheduler to evaluate IO synchronously. It is recommended to use the io function by default, sync *will* block the scheduler.

Sink

type Sink a => a -> IO ()

The Sink function allows one to write any action to the global event queue.

Managing model state.

Any MonadState function is allowed for use when manipulating model, get, put, etc. See Miso.State.

The MonadReader instances allows the retrieval of ComponentInfo within Effect. ComponentInfo provides the current ComponentId the parent ComponentId, and the DOMRef (_componentDOMRef) that the Component is mounted on.

Component communication

Asynchronous communication

Component are able to communicate asynchronously via a message-passing system. The miso runtime exposes a few primitives to allow Component communication.

All Component have a mailbox that can receive messages (as Value) from other Component. This is meant to be used with the checkMail function. The mail function allows a Component to send a specific message (as Value) to another Component via its ComponentId. The ComponentId can be found in the Effect monad. Using ask will return a ComponentInfo. The Component receiving the message will find it in its mailbox.

miso has support for the publisher / subscriber concurrency pattern. See the Miso.PubSub module for more information.

Synchronous communication

Experimental support for data bindings (where Component model can synchronize fields via a Lens in response to model differences along the parent-child relationship). See the Miso.Binding module for more information, and the miso-reactive example. *Warning*: This is still considered experimental.

While not direct communication, a Component can receive read-only access to its parent state via the parent function.

Subscriptions

A Sub is any long-running operation that is external to a Component, but that can write to a Component Sink. Sub come in two flavors, a dynamic Sub (via startSub / stopSub) and subs.

main :: IO ()
main = startApp defaultEvents app { subs = [ timerSub ] }

timerSub :: Sub Action
timerSub sink = forever $ (threadDelay 100000) >> sink Log

data Action = Log

The subs field of Component contains Sub that exist for the lifetime of that Component. When a Component unmounts, these Sub will be stopped, and their resources finalized.

onLineSub :: (Bool -> action) -> Sub action
onLineSub f sink = createSub acquire release sink
  where
    release (cb1, cb2) = do
      FFI.windowRemoveEventListener "online" cb1
      FFI.windowRemoveEventListener "offline" cb2
    acquire = do
      cb1 <- FFI.windowAddEventListener "online" (const $ sink (f True))
      cb2 <- FFI.windowAddEventListener "offline" (const $ sink (f False))
      pure (cb1, cb2)

At times its necessary to dynamically generate a Sub in reponse to an event (e.g. starting a Miso.WebSocket connection when a user logs in). The startSub and stopSub functions facilitate dynamic Sub creation / removal.

  update = \case
    StartTimer -> startSub ("timer" :: MisoString) timerSub
    StopTimer -> stopSub "timer"
    Log -> io_ (consoleLog "log")
      where
        timerSub :: Sub Action
        timerSub sink = forever $ (threadDelay 100000) >> sink Log

  data Action = Log

createSub is a helper function for creating a Sub using the bracket pattern. This ensures that event listeners can be unregistered when a Component unmounts. For example usage please see the Miso.Subscription sub modules. createSub is only meant to be used in scenarios where custom event listeners are required (shown below).

(2D/3D) Canvas support

Miso has full 2D and 3D canvas support. See the Miso.Canvas module, the miso-canvas example, along with the three-miso package.

State management (Lens)

A simple Lens implementation is included with miso, this was done for convenience, to minimize dependencies, reduce payload size, and provide a simpler interface. See Miso.Lens. This is a simple lens formulation that exposes many common MonadState lenses (e.g. +=) that work in the Effect monad. Miso.Lens is not required for use, any lens library will also work with miso.

HTML

Miso's virtual DOM DSL (View) type can be repurposed to render HTML. See the Miso.Html.Render module for more information. This uses the ToHtml class.

JavaScript EDSL

Miso provides a Javascript DSL (inspired by jsaddle) via Miso.DSL. See the ToJSVal / FromJSVal typeclasses when marshaling to and from Haskell to JavaScript. See also the jsg function for accessing JavaScript objects that exist in the global scope.

document :: JSVal <- jsg "document" :: IO JSVal
len :: Int <- fromJSValUnchecked =<< (document ! "body" ! "children" ! "length")

QuasiQuotation (inline-js)

Along with Miso.DSL, a JavaScript QuasiQuoter is now included (See Miso.FFI.QQ). This makes it easy to integrate miso with any third-party JavaScript library. This bindings in scope can be used inside the QuasiQuoter, which will utilize their ToJSVal instances. When returning values from the QuasiQuoter, the FromJSVal instance will be used Haskell.

{-# LANGUAGE QuasiQuotes #-}

import Miso.FFI.QQ (js)

update :: Action -> Effect parent model Action
update = \case
  Log msg -> io_ [js| console.log(${msg}) |]

data Action = Log MisoString

Routing

miso exposes its own internal router. See Miso.Router for more information. The router is inspired by both the servant and the web-routes package. The router has its own Sub called routerSub meant for easy integration with the History API.

MisoString

miso includes its own string type named MisoString. This is the preferred string type to use in order to maximize application performance. Since strings are ubiquitous in applications we want to minimize the copying of these strings between the JS and Haskell heaps. MisoString accomplishes this. MisoString is a synonym for JSString when using the JS / WASM backends. When using vanilla GHC it is Text. See Miso.String for more information.

MisoString is also used in the Miso.Util.Lexer and Miso.Util.Parser modules.

JSON

Miso.JSON is a microaeson implementation that uses MisoString. This is done for performance reasons and to minimize the dependency burden. Miso.JSON is used in Miso.Event.Decoder, Miso.Fetch, Miso.WebSocket modules respectively.

Styles

Miso prescribes no exact CSS style usage. It is up to the user's discretion on how best to handle styles in their application. Inline styles, external stylesheets and the Miso.CSS DSL can all be used. See also miso-ui for an example of what is possible.

Development

When developing miso applications interactively it is possible to append styles and scripts to the <head> portion of the page when the Component mounts. This is a convenience only meant to be used in development. We recommend guarding the usage behind a flag.

main :: IO ()
main = startApp defaultEvents counter
 where
   app = counter
#ifdef INTERACTIVE
     { scripts = [ Src "https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js" ]
     , styles = [ Href "https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" ]
     }
#endif

See the miso-sampler repository for more information.

Debugging

Sometimes things can go wrong. Common errors like using onClick but not listening for the the click event are common. These are errors that cannot be caught statically. These can be detected by enabling DebugAll. Currently, debugging event delegation and page hydration is supported.

counter { logLevel = DebugAll }

Internals

Internally miso uses a global event queue and a scheduler to process all events raised by Component throughout the lifetime of an application. Events are processed in FIFO order, batched by the Component that raised them.

Synopsis

API

Miso

miso Source #

Arguments

:: Eq model 
=> Events

Globally delegated Events

-> (URI -> App model action)

The Component application, with the current URI as an argument

-> IO () 

Runs an miso application.

Assumes the pre-rendered DOM is already present. Always mounts to <body>. Copies page into the virtual DOM.

main :: IO ()
main = miso defaultEvents (\uri -> app uri))

prerender Source #

Arguments

:: Eq model 
=> Events

Globally delegated Events

-> App model action

Component application

-> IO () 

Like miso, except discards the URI argument.

Use this function if you'd like to prerender, but not use navigation.

main :: IO ()
main = prerender defaultEvents app

(🍜) Source #

Arguments

:: Eq model 
=> Events

Globally delegated Events

-> (URI -> App model action)

Component application, with the current URI as an argument

-> IO () 

Alias for miso.

App

type App model action = Component ROOT model action Source #

A miso application is a top-level Component, which has no parent. This is enforced by specializing the parent type parameter to ROOT.

startApp Source #

Arguments

:: Eq model 
=> Events

Globally delegated Events

-> App model action

Component application

-> IO () 

Like miso, except it does not perform page hydration.

This function draws your application on an empty body

You will most likely want to use this function for your application unless you are using prerendering.

main :: IO ()
main = startApp defaultEvents app

renderApp Source #

Arguments

:: Eq model 
=> Events

Globally delegated Events

-> MisoString

Name of the JS object that contains the drawing context

-> App model action

Component application

-> IO () 

Runs a miso application, but with a custom rendering engine.

The MisoString specified here is the variable name of a globally-scoped JS object that implements the context interface per ts/miso/context/dom.ts This is necessary for native support.

It is expected to be run on an empty <body>

main :: IO ()
main = renderApp defaultEvents "my-context" app

Component

data Component parent model action Source #

Application entry point

Constructors

Component 

Fields

  • model :: model

    Initial model

  • hydrateModel :: Maybe (IO model)

    Action to load component state, such as reading data from page. The resulting model is only used during initial hydration, not on remounts.

  • update :: action -> Effect parent model action

    Updates model, optionally providing effects.

  • view :: model -> View model action

    Draws View

  • subs :: [Sub action]

    Subscriptions to run during application lifetime

  • styles :: [CSS]

    CSS styles expressed as either a URL (Href) or as Style text. These styles are appended dynamically to the <head> section of your HTML page before the initial draw on <body> occurs.

    Since: 1.9.0.0

  • scripts :: [JS]

    JavaScript scripts expressed as either a URL (Src) or raw JS text. These scripts are appended dynamically to the <head> section of your HTML page before the initial draw on <body> occurs.

    Since: 1.9.0.0

  • mountPoint :: Maybe MountPoint

    ID of the root element for DOM diff. If Nothing is provided, the entire document body is used as a mount point.

  • logLevel :: LogLevel

    Debugging configuration for prerendering and event delegation

  • mailbox :: Value -> Maybe action

    Receives mail from other components

    Since: 1.9.0.0

  • bindings :: [Binding parent model]

    Data bindings between parent and child Components

    Since: 1.9.0.0

  • eventPropagation :: Bool

    Should events bubble up past the Component barrier.

    Defaults to False

    Since: 1.9.0.0

  • mount :: Maybe action

    action to execute during Component mount phase.

    Since: 1.9.0.0

  • unmount :: Maybe action

    action to execute during Component unmount phase.

    Since: 1.9.0.0

component Source #

Arguments

:: model

model

-> (action -> Effect parent model action)

update

-> (model -> View model action)

view

-> Component parent model action 

Smart constructor for Component with sane defaults.

(+>) infixr 0 Source #

Arguments

:: Eq child 
=> MisoString

VComp key_

-> Component model child action

Component

-> View model a 

Component mounting combinator

Used in the view function to mount a Component on any VNode.

  "component-id" +> component model noop $ \m ->
    div_ [ id_ "foo" ] [ text (ms m) ]

Since: 1.9.0.0

mount_ Source #

Arguments

:: Eq child 
=> Component model child a

Component to mount

-> View model action 

Component mounting combinator.

Note: only use this if you're certain you won't be diffing two Component against each other. Otherwise, you will need a key to distinguish between the two Component, to ensure unmounting and mounting occurs.

  mount_ $ component model noop $ \m ->
    div_ [ id_ "foo" ] [ text (ms m) ]

Since: 1.9.0.0

Sink

withSink Source #

Arguments

:: (Sink action -> IO ())

Callback function that provides access to the underlying Sink.

-> Effect parent model action 

withSink allows users to write to the global event queue. This is useful for introducing IO into the system. A synonym for tell, specialized to Effect.

A use-case is scheduling an IO computation which creates a 3rd-party JS widget which has an associated callback. The callback can then call the sink to turn events into actions.

'update' FetchJSON = 'withSink' $ \sink -> getJSON (sink . ReceivedJSON) (sink . HandleError)

Since: 1.9.0.0

type Sink action = action -> IO () Source #

Function to write to the global event queue for processing by the scheduler.

Mail

mail Source #

Arguments

:: ToJSON message 
=> ComponentId

ComponentId to receive mail

-> message

The message to send

-> IO () 

Send any ToJSON message => message to a Component mailbox, by ComponentId

io_ $ mail componentId ("test message" :: MisoString) :: Effect parent model action

Since: 1.9.0.0

checkMail Source #

Arguments

:: FromJSON value 
=> (value -> action)

Successful callback

-> (MisoString -> action)

Errorful callback

-> Value

The message received to parse.

-> Maybe action 

Helper function for processing Mail from mail.

data Action
  = ParsedMail Message
  | ErrorMail MisoString

main :: IO ()
main = app { mailbox = checkMail ParsedMail ErrorMail }

Since: 1.9.0.0

parent Source #

Arguments

:: (parent -> action)

Successful callback

-> action

Errorful callback

-> Effect parent model action 

Fetches the parent model from the child (if parent exists).

N.B. this is a no-op for ROOT.

Since: 1.9.0.0

mailParent Source #

Arguments

:: ToJSON message 
=> message

Message to send

-> Effect parent model action 

Send any ToJSON message => message to the parent's Component mailbox

mailParent ("test message" :: MisoString) :: Effect parent model action

Since: 1.9.0.0

broadcast Source #

Arguments

:: (Eq model, ToJSON message) 
=> message

Message to broadcast to all other Component

-> Effect parent model action 

Sends a message to all Component mailbox, excluding oneself.

update :: action -> Effect parent model action
update _ = broadcast (String "public service announcement")

Since: 1.9.0.0

Subscriptions

startSub Source #

Arguments

:: ToMisoString subKey 
=> subKey

The key used to track the Sub

-> Sub action

The Sub

-> Effect parent model action 

Starts a named Sub dynamically, during the life of a Component. The Sub can be stopped by calling Ord subKey => stop subKey from the update function. All Sub started will be stopped if a Component is unmounted.

data SubType = LoggerSub | TimerSub
  deriving (Eq, Ord)

update Action =
  startSub LoggerSub $ \sink -> forever (threadDelay (secs 1) >> consoleLog "test")

Since: 1.9.0.0

stopSub Source #

Arguments

:: ToMisoString subKey 
=> subKey

The key used to stop the Sub

-> Effect parent model action 

Stops a named Sub dynamically, during the life of a Component. All Sub started will be stopped automatically if a Component is unmounted.

data SubType = LoggerSub | TimerSub
  deriving (Eq, Ord)

update Action = do
  stopSub LoggerSub

Since: 1.9.0.0

type Sub action = Sink action -> IO () Source #

Type synonym for constructing subscriptions.

For example usage see Miso.Subscription

The Sink function is used to write to the global event queue.

Effect

issue Source #

Arguments

:: action

action to raise

-> Effect parent model action 

Issue a new action to be processed by update.

data Action = HelloWorld
type Model  = Int

'update' :: Action -> 'Effect' parent Model Action
'update' = \\case
  Click -> 'issue' HelloWorld

Since: 1.9.0.0

batch Source #

Arguments

:: [IO action]

Batch of IO actions to execute

-> Effect parent model action 

Smart constructor for an Effect with multiple IO actions.

Since: 1.9.0.0

io Source #

Arguments

:: IO action

IO action to execute asynchronously

-> Effect parent model action 

Schedule a single IO action for later execution.

Note that multiple IO action can be scheduled using tell from the mtl library.

Since: 1.9.0.0

io_ Source #

Arguments

:: IO ()

IO action to execute asynchronously

-> Effect parent model action 

Like io but doesn't cause an action to be dispatched to the update function.

This is handy for scheduling IO computations where you don't care about their results or when they complete.

Note: The result of IO a is discarded.

Since: 1.9.0.0

sync Source #

Arguments

:: IO action

IO action to execute synchronously

-> Effect parent model action 

Schedule a single IO action, executed synchronously. For asynchronous execution, see io.

Please use this with caution because it will block the render thread.

Since: 1.9.0.0

sync_ Source #

Arguments

:: IO ()

IO action to execute synchronously

-> Effect parent model action 

Like sync, except discards the result.

Since: 1.9.0.0

for Source #

Arguments

:: Foldable f 
=> IO (f action)

actions executed in batch.

-> Effect parent model action 

Like io but generalized to any instance of Foldable

This is handy for scheduling IO computations that return a Maybe value

Since: 1.9.0.0

JS file embedding

withJS Source #

Arguments

:: IO a

IO action to execute in between evalFile

-> IO a 

Load miso's javascript.

You don't need to use this function if you're compiling w/ WASM and using miso or startApp. It's already invoked for you. This is a no-op w/ the JS backend.

If you need access to FFI to call functions from `miso.js`, but you're not using startApp or miso, you'll need to call this function (w/ WASM only).

Bindings

Primitives for synchronizing parent and child models.

DSL

A JavaScript DSL for easy FFI interoperability

module Miso.DSL

Effect

Effect, Sub, and Sink types for defining update functions and subscriptions.

Event

Functions for specifying component lifecycle events and event handlers.

module Miso.Event

Fetch

Interface to the Fetch API for making HTTP requests.

module Miso.Fetch

PubSub

Publish / Subscribe primitives for communication between components.

Property

Construct custom properties on DOM elements.

Reload

Support for clearing the page during live-reloading w/ WASM browser mode.

Subscriptions

Subscriptions for external events (mouse, keyboard, window, history, etc.).

Storage

Web Storage API (Local and Session storage) interface.

Types

Core types for Miso applications.

module Miso.Types

Util

Utility functions for views, parsing, and general purpose combinators.

module Miso.Util

FFI

Foreign Function Interface (FFI) utilities for interacting with JavaScript.

module Miso.FFI

State management

State management for Miso applications.

module Miso.State