Download Latest Version 1.14.0 source code.zip (1.5 MB) Google Add to Preferred Sources
Home / 1.14.0
Name Modified Size InfoDownloads / Week
Parent folder
1.14.0 source code.tar.gz 2026-09-11 1.3 MB
1.14.0 source code.zip 2026-09-11 1.5 MB
README.md 2026-09-11 10.9 kB
Totals: 3 Items   2.8 MB 0

🍜 1.14.0

This release introduces the VContext, VProps and VModel DSL terms, along with their smart constructors vcontext, vprops and vmodel, for ambient access to the context, props and model from anywhere in a View.

It also introduces two breaking changes: the view function now takes fewer arguments (only the model), and the View type takes more type parameters (View context props model action) — View now has type parameter symmetry with Component context props model action and Effect context props model action. See the migration notes below.

✨ Special thanks

✨ Highlights

  • Ambient accessors: vcontext / vprops / vmodel (synonyms withContext / withProps / withModel). Any part of a view tree can read the app-global context, the enclosing component's props, or its model without an extra argument. They are not nodes: each wraps a function that is applied — and the wrapper discarded — when the tree is built or rendered, so they never appear in the virtual DOM the runtime diffs. props and model are resolved through the type system (a mismatch is a compile error); context against the app's single cell.
  • ⚠️ view takes only the model. view :: model -> View context props model action. Read context/props with the accessors instead. Migration below.
  • ⚠️ View gained a props type parameter. View context model actionView context props model action, matching Component context props model action.
  • toHtmlWithtoHtmlWith :: context -> props -> model -> View context props model action -> ByteString renders a component's view on the server; it supplies the values the accessors resolve against. Plain toHtml is for bare static markup (context/props/model all ()). ⚠️ setContext is gone with it.
  • One context cell per app. The globalContext top-level IORef is gone; the app owns the cell, every component holds a reference to it, and modifyContext is a single atomic update rather than a rewrite of every component.
  • Static mounts. SomeStaticComponent now holds the Component itself (plus its dictionaries); mountStatic works for components with or without props (mountStaticWithProps is a deprecated alias until 1.15). A static mount now uses its StaticKey as the diff key, so swapping vcomp_ (static (mountStatic A)) for …B replaces the child instead of running B's diffProps against A.
  • Lifecycle hooks. New onDestroyedWith, and onDestroyedWith / onBeforeDestroyedWith now actually receive the element's DOMRef (it was always undefined).
  • Miso.Lens fixes. preview / preuse no longer loop forever; _Nothing is now Prism (Maybe a) ().
  • Hydration. Events raised before the vtree is mounted are dropped instead of dispatched against nothing (a startup race); toHtml collapses adjacent text nodes inside fragments, across a [View], and through the ambient accessors, so the server's markup matches the client's hydration walk instead of silently falling back to a full re-render.
  • Native (Lynx). svgWith_ — inline SVG content that reads context / props / model ambiently; content_ takes all three ahead of the content View.
  • Nix / CI. A real, callCabal2nix-capable wasm32-wasi Haskell package set (pkgs.wasmPkgs, pkgs.wasmWebBundle; nix-build -A miso-wasm-ghc9141, sample-app-wasm-ghc9141, …) built on ghc-wasm-meta, pinned to flake.lock; the WASM integration tests are nix-native; overlays.default is exported for downstream flakes; everything moved to GHC 9.14.1; stale GitHub Actions bumped; cabal check-clean upper bounds.

⚠️ Breaking changes & migration

1. view takes only the model. Drop the context and props arguments; a view that ignored them just loses two wildcards:

:::haskell
-- 1.13
viewModel :: () -> () -> Model -> View () Model Action
viewModel _ _ (Model x) = …

-- 1.14
viewModel :: Model -> View () () Model Action
viewModel (Model x) = …

A view that used them reads them at the point of use instead (see the snippets below). component / startApp / startAppWithContext / misoWithContext / prerenderWithContext are otherwise unchanged.

2. View has a props parameter. Insert a props variable after context in your signatures; code that leaves it polymorphic needs nothing else:

:::haskell
header :: View context model action          -- 1.13
header :: View context props model action    -- 1.14

Mount combinators (mount_, mountWithProps, (+>), vcomp, …) forget the child's props at the boundary exactly as they forget its model and action.

3. Server-side rendering. ToHtml (View …) and ToHtml [View …] now require context ~ (), props ~ () and model ~ () — a bare View is static markup. A component's view is rendered with toHtmlWith, which replaces the removed setContext:

:::haskell
toHtml (div_ [] [ "static markup" ])              -- bare View
toHtmlWith ctx props model (view comp model)      -- a component's view

4. SomeStaticComponent. Its payload is a Component, not a props -> SomeComponent function; mountStatic now accepts components with props, mountStaticWithProps is deprecated (removed in 1.15). Call sites like vcomp_ (static (mountStatic comp)) are unchanged. On Lynx, Miso.Native.X.Element.Svg.Property.content_ takes context, props and model ahead of the content View (or use svgWith_).

5. _Nothing :: Prism (Maybe a) () (was Prism (Maybe a) a, which could never match).

📖 Using vcontext, vprops and vmodel

All three are drop-in Views: put them anywhere a node goes. The function you pass is applied when the tree is built or rendered.

:::haskell
data Theme = Light | Dark deriving Eq
data Props = Props { title :: MisoString } deriving Eq
data Model = Model { count :: Int } deriving Eq

view :: Model -> View Theme Props Model Action
view Model { count } =
  div_ []
    [ -- the app-global context, read where it is needed
      vcontext $ \theme ->
        span_ [ class_ (themeClass theme) ] [ "Counter" ]
      -- the props this component was mounted with
    , vprops $ \Props { title } ->
        h1_ [] [ text title ]
      -- the model — also available ambiently, for helpers it isn't passed to
    , vmodel $ \Model { count = c } ->
        span_ [] [ text (ms c) ]
    , button_ [ onClick AddOne ] [ "+" ]
    , text (ms count)
    ]

Because props and model are type parameters of View, vprops sees the props of the component whose view contains it and vmodel its model — statically. A child mounted with mountWithProps / vcomp sees its own props and model, never its parent's.

The model is still handed to view purely for convenience; view _ = withModel $ \m -> … is equivalent. Where the accessors earn their keep is a helper deep in the tree that would otherwise need the value threaded down through every call:

:::haskell
-- Themed button usable from any component in the app, no `theme` argument.
themedButton :: MisoString -> action -> View Theme props model action
themedButton label act =
  withContext $ \theme ->
    button_ [ class_ (buttonClass theme), onClick act ] [ text label ]

Redraw semantics are unchanged — the accessors add no redraw logic of their own:

  • vcontext does not opt a component into context-driven redraws; that is still governed by useContext = True. It sees a fresh context whenever the surrounding view is rebuilt for any reason.
  • vprops is re-resolved when the parent passes different props; vmodel when the model changes after update.

On the server, toHtmlWith ctx props model is what they resolve against; a vmodel nested inside a mounted child component sees that child's initial (or hydrated) model.

What's Changed

Full Changelog: https://github.com/dmjio/miso/compare/1.13.0...1.14.0

Source: README.md, updated 2026-09-11