MyNixOS website logo
Description

A simple, fun way to build websites.

A simple, fun way to build websites with Haskell.

The main points:

  • It's server side rendered and uses websockets to communicate HTML updates and to receive events.

  • State can be broken up into small components.

  • Attributes flow down to concrete HTML, events bubble up to handlers.

  • Handlers can send further events to a parent handler or themselves

It's inspired by Phoenix LiveView, React, Redux, and Redux-Sagas.

Purview

A simple, fun way to build websites with Haskell. It's inspired by Phoenix LiveView, React, and Redux + Sagas.

The main points:

  • It's server side rendered and uses websockets to communicate HTML updates and to receive events.
  • State can be broken up into small components.
  • Attributes flow down to concrete HTML, events bubble up to state handlers.
  • Handlers can send further events to a parent handler or themselves

It's still in early development so expect things to break or be missing!

What it looks like

module Main where

import Prelude hiding (div)

import Purview 
import Purview.Server


data CountEvent = Increment | Decrement
  deriving (Show, Eq)

view :: Int -> Purview CountEvent m
view count = div
  [ h1 [ text (show count) ]
  , div [ onClick Increment $ button [ text "increment" ]
        , onClick Decrement $ button [ text "decrement" ]
        ]
  ]

-- passes state down to the child and maintains type safety of actions
countHandler :: (Int -> Purview CountEvent m) -> Purview () m
-- arguments are initial actions, initial state, and then the reducer
countHandler = handler' [] (0 :: Int) reducer
  where
    reducer Increment state = (state + 1, [])  -- new events can be added in the []
    reducer Decrement state = (state - 1, [])

-- url is passed in to the top level component by `serve`
component url = countHandler view

main = serve defaultConfiguration component

More detailed docs on the use and particulars of Purview are mainly on Hackage.

Overview of how it works

Using an imagined example of getting the time, here's how events flow when the user clicks "check time"

  1. The event is sent from the browser in a form like

    { event: click, value: undefined, location: [0], childLocation: [0,0] }

  2. The event is put onto the channel for the event loop to process

  3. It goes down the tree to find the event in Haskell by childLocation

  4. It takes that event and applies it to the handler found by location

  5. The handler does its work in a green thread, creating a new event that looks like

    { event: stateChange, fn: state -> state, location: [0] }

  6. The state change event is put onto the channel for the event loop to process

  7. By going down the tree it applies the state change fn to the latest state in the tree, returning a new tree

  8. Any HTML changes are sent to the browser, completing the loop

Contributing

Anything is welcome, including examples or patterns you found nice. There's still a lot to discover.

The roadmap is, loosely, determined by adding things required to build real websites. The first two site-based goals:

  1. The Purview website itself, which will have more in depth tutorials (so requiring at least navigation)
  2. A stripe-based checkout (requiring communication with javascript)

Installation

  1. Install stack
  2. stack build

Running Tests

  1. The same as above with stack and build
  2. stack test.
Metadata

Version

0.2.0.2

Platforms (75)

    Darwin
    FreeBSD
    Genode
    GHCJS
    Linux
    MMIXware
    NetBSD
    none
    OpenBSD
    Redox
    Solaris
    WASI
    Windows
Show all
  • aarch64-darwin
  • aarch64-genode
  • aarch64-linux
  • aarch64-netbsd
  • aarch64-none
  • aarch64_be-none
  • arm-none
  • armv5tel-linux
  • armv6l-linux
  • armv6l-netbsd
  • armv6l-none
  • armv7a-darwin
  • armv7a-linux
  • armv7a-netbsd
  • armv7l-linux
  • armv7l-netbsd
  • avr-none
  • i686-cygwin
  • i686-darwin
  • i686-freebsd
  • i686-genode
  • i686-linux
  • i686-netbsd
  • i686-none
  • i686-openbsd
  • i686-windows
  • javascript-ghcjs
  • loongarch64-linux
  • m68k-linux
  • m68k-netbsd
  • m68k-none
  • microblaze-linux
  • microblaze-none
  • microblazeel-linux
  • microblazeel-none
  • mips-linux
  • mips-none
  • mips64-linux
  • mips64-none
  • mips64el-linux
  • mipsel-linux
  • mipsel-netbsd
  • mmix-mmixware
  • msp430-none
  • or1k-none
  • powerpc-netbsd
  • powerpc-none
  • powerpc64-linux
  • powerpc64le-linux
  • powerpcle-none
  • riscv32-linux
  • riscv32-netbsd
  • riscv32-none
  • riscv64-linux
  • riscv64-netbsd
  • riscv64-none
  • rx-none
  • s390-linux
  • s390-none
  • s390x-linux
  • s390x-none
  • vc4-none
  • wasm32-wasi
  • wasm64-wasi
  • x86_64-cygwin
  • x86_64-darwin
  • x86_64-freebsd
  • x86_64-genode
  • x86_64-linux
  • x86_64-netbsd
  • x86_64-none
  • x86_64-openbsd
  • x86_64-redox
  • x86_64-solaris
  • x86_64-windows