Skip to content

haskell-miso/miso-lynx

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

71 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

miso-lynx

A tasty Haskell mobile framework 🍜 🐈 πŸ“±

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

Miso Lynx 🍜 🐈 is a mobile framework that uses miso and LynxJS to facilitate drawing to native iOS UIView, Android View, and for interacting with APIs on the device. The Haskell miso project is excited to be an open-source technology partner with innovative companies like ByteDance πŸ‡¨πŸ‡³ 🦾 , creators of LynxJS, to advance native mobile app development in the functional programming space.

Why Lynx

Since 2017, miso has sought ways to run on mobile devices that take advantage of native drawing facilities. Flutter, SwiftUI produce stunning, performant user experiences but are not necessarily designed for integration with open standards, are effectively only usable with a specific IDE / choice languages, and can lack in cross-platform capability (SwiftUI specifically). React Native improves upon this situation by allowing open web standards for development and cross-platform capability, but wasn't designed for easy integration with any web framework (rather for use specifically with react). React Native also can regress in performance relative to SwiftUI in certain scenarios.

Lynx addresses the aforementioned issues with a new architectural approach.

  • Dual-threaded interpreter runtime

    The Lynx engine uses two embedded JavaScript interpreters to selectively schedule / offload computation to free up the render thread. This avoids drawing lag as commonly seen with scroll events in react native applications.

  • Element PAPI (PrimJS API)

    Exposing a DOM API for rendering allows any JavaScript (or compile-to-JavaScript 🍜) web framework to produce cross-platfom mobile applications. Seen here in miso-lynx.

  • Cross platform capability

    Lynx targets iOS, Android, Web by default, and has a roadmap that mentions Desktop UI as well (OSX, etc.)

  • Instant first-frame rendering - IFR

    The flagship isomorphic (server side rendering) feature in miso can be repurposed as IFR in miso-lynx (one of the flagship features of lynx).

For framework implementors, this is a dream come true, and we hope miso-lynx can be an ideal development environment for building Lynx applications with miso.

Table of Contents

React Summit

As seen @ React Summit by @huxpro !

Alt text

The Haskell miso portion is queued here.

Fireship

See Fireship πŸ”₯ video

Demo

Preview

To run the example locally execute the following command

$ git clone git@github.com:haskell-miso/miso-lynx.git
$ http-server ./miso-lynx/examples

This will host the main.lynx.bundle which can be loaded into the LynxExplorer for interactive development.

Note

You will need to have the LynxExplorer installed which works with the iOS simulator. Please see the LynxJS getting started guide for installation.

Quick Start

Warning

miso-lynx depends on the latest version of miso (version 1.9), this includes custom renderers (ala React Renderer) and Components as well. Currently all event handling and drawing are performed on the main thread. Selectively scheduling Haskell code on the Lynx MTS / BTS is ongoing research. This project is under heavy development and is considered experimental.

To start developing applications with miso-lynx you will need to acquire GHC and cabal. This can be done via GHCup or Nix.

Tip

For new Haskell users we recommend using GHCup to acquire both GHC and cabal

Setup

Main.hs

This file contains a simple miso-lynx counter application.

-----------------------------------------------------------------------------
{-# LANGUAGE RecordWildCards             #-}
{-# LANGUAGE OverloadedStrings           #-}
{-# LANGUAGE GeneralizedNewtypeDeriving  #-}
-----------------------------------------------------------------------------
module Main where
-----------------------------------------------------------------------------
import           Miso
import           Miso.Lynx
-----------------------------------------------------------------------------
import           Miso.Lens
import           Miso.String
import qualified Miso.Style as CSS
-----------------------------------------------------------------------------
-- | Type synonym for an application model
newtype Model = Model { _value :: Int }
  deriving (Show, Eq, ToMisoString)
-----------------------------------------------------------------------------
value :: Lens Model Int
value = lens _value $ \m v -> m { _value = v }
-----------------------------------------------------------------------------
data Action
  = AddOne
  | SubtractOne
  | SayHelloWorld
  | Tap Int
  deriving (Show, Eq)
-----------------------------------------------------------------------------
-- | Entry point for a miso application
main :: IO ()
main = run $ lynx counterComponent
  { events = lynxEvents
  , initialAction = Just SayHelloWorld
  }
-----------------------------------------------------------------------------
counterComponent :: Component Model Action
counterComponent = component (Model 0) updateModel viewModel
-----------------------------------------------------------------------------
updateModel
  :: Action
  -> Effect Model Action
updateModel SayHelloWorld =
  io_ (consoleLog "Hello World!")
updateModel AddOne =
  value += 1
updateModel SubtractOne =
  value -= 1
updateModel (Tap x) =
  io_ $ consoleLog ("Tapped: " <> ms (show x))
-----------------------------------------------------------------------------
-- | Constructs a virtual DOM from a model
viewModel :: Model -> View Action
viewModel m = view_
  [ CSS.style_
    [ CSS.height "200px"
    , CSS.display "flex"
    , CSS.alignItems "center"
    , CSS.justifyContent "center"
    ]
  ]
  [ view_
    [ onTap AddOne
    , id_ "plus"
    , CSS.style_
        [ CSS.backgroundColor CSS.yellow
        , CSS.width "100px"
        , CSS.height "100px"
        , CSS.margin "2px"
        , CSS.display "flex"
        , CSS.alignItems "center"
        , CSS.justifyContent "center"
        ]
    ]
    [ text_
      [ CSS.style_
        [ CSS.fontSize "48px"
        ]
      ]
      [ "🐈"
      ]
    ]
  , view_
    [ CSS.style_
        [ CSS.backgroundColor CSS.orange
        , CSS.width "100px"
        , CSS.height "100px"
        , CSS.display "flex"
        , CSS.alignItems "center"
        , CSS.justifyContent "center"
        ]
    ]
    [ text_
      [ CSS.style_
        [ CSS.fontSize "48px"
        ]
      ]
      [ text $ ms (m ^. value)
      ]
    ]
  , view_
    [ onTap SubtractOne
    , id_ "minus"
    , CSS.style_
        [ CSS.backgroundColor CSS.pink
        , CSS.width "100px"
        , CSS.height "100px"
        , CSS.margin "2px"
        , CSS.display "flex"
        , CSS.alignItems "center"
        , CSS.justifyContent "center"
        ]
    ]
    [ text_
      [ CSS.style_
        [ CSS.fontSize "48px"
        ]
      ]
      [ "🍜"
      ]
    ]
 ]
-----------------------------------------------------------------------------

Now that your project files are populated, development can begin.

Hot Reload

This entails creating a LynxExplorer application with the jsaddle-warp hot-reload package. This will require using rspack and the BTS to access WebSockets via the lynx object.

Examples

Binary cache

nix users on a Linux or OSX distros can take advantage of a binary cache for faster builds. To use the binary cache follow the instructions on cachix.

Tip

We highly recommend nix users consume the cachix cache. cachix use haskell-miso-cachix.

$ cachix use haskell-miso-cachix

Maintainers

@dmjio

Contributing

Feel free to dive in! Open an issue or a submit Pull Request.

See CONTRIBUTING for more info.

License

BSD3 Β© dmjio

Releases

No releases published

Sponsor this project

 

Packages

No packages published