How I write purescript apps

On Thu, 25 Jan 2024, by @lucasdicioccio, 314 words, 0 code snippets, 0 links, 0images.

This article is still considered unfinished and content may change significantly.

  • apps

    • main that corresponds to a JS inclusion in html
    • copy-to-clipboard actions
    • console-logging
    • analytics
  • pages

    • tracer
    • state management
      • discussed later, but key is to split ui, core, and other
    • action
      • traced-wrapper handler
      • handler
        • handling
      • handler-modules
        • how ui updates influence core-model updates
    • render
      • huge pile of rendering functions
      • render-modules
        • basically copy-pastable chunks of render-function (can refer to actions, state, but not slots)
  • components

    • for annoying state (echarts)
    • for one-off non-trivial states reducible to few business-wide events (e.g., configuration wizards)
  • bricks

    • typical UI mostly concerns (a button, a search-bar)
    • state is passed in
    • consume a brick handler by passing directly (i.e., you import the brick more than you adapt the brick)
  • widgets

    • bricks that start to get tuned to your domain (e.g., a postgrest-endpoint-search bar)
    • can define some Action to reduce amount of onFoo handlers and incitate contramapping handling
      • if instantiable/higher-level widget: consider giving an Action -> action rather than defining onAction
    • consume a widget with a mapping function
  • state management

    • ui-state vs. core-state vs. storable state
    • ECS-flavored style
      • seqnums entities
      • use List.Cons (updatedItem) (List.filter (not oldItem) state.entities)
  • code style

    • be monotonous
      • almost always pass params for nesting, even if redundant
        • render_section_item state section item
      • rely on qualified imports
      • bricks should take a Props in, should have a render
    • exception can happen to split non-trivial logic (e.g. render vs render_box_content)
    • use contramapping in Action poppups
      • Action tree nesting should reflect the pages/rendering/widgets/bricks nesting
    • use utility functor wrapper, really useful in a web-environment to speak about
      • a Remote value (could be loading, carry api errors)
      • some Historical value (could be current or old value)
      • an Historized value (snapshotted history of values to got back in time)
    • do not tie these wrappers to some api-fetching (i.e., it’s normal to build your own Remote value)
  • example in postgrest-table

    • ui state
    • core state
      • datasets List { value :: Remote Json, seqnum :: Seqnum "dataset", perspective :: Seqnum "perspective" }
      • ajax calls List { value :: Historical Blob, seqnum :: Seqnum "ajax-call", perspective ...}
    • storable state
      • endpoints
      • perspectives
      • projections
  • things that are natural

    • noop action type, somewhat double use for unimplemented, but also to suppress a handler (alas needed when we want a brick to pick only valid-values but the enclosed html allows invalid events, e.g., parsing a decimal)
    • comap comap comap