utkarshkukreti / purescript-hedwig

Hedwig is a fast, type safe, declarative PureScript library for building web applications.
131 stars 10 forks source link

Routing #5

Open thalesrca opened 6 years ago

thalesrca commented 6 years ago

Hi, first of all I would like to thank you for the library, I have been playing with hedwig for a while and have been very fun.

I would like to know how to do routing with it though. And if you can show a example or some snippet of how to do.

Thanks.

utkarshkukreti commented 6 years ago

Hey @thalesrodolfo. Thanks for the comment! There really isn't any non-hacky way to do this right now. Elm has subscriptions which lets you do things like this which isn't implemented here yet.

Shortly before making this project public, I started working on an alternative, more powerful library. I've written about it a bit here. Here's the full Router example in the new library:

module Examples.Router where

import Prelude

import Data.Maybe (Maybe(..), maybe)
import Effect (Effect)
import Hertz as H
import Hertz.Router as Router

type State = { route :: Maybe Route, url :: Maybe Router.Url }

data Action = Navigate Router.Url

data Route
  = Index
  | PostIndex { sortBy :: Maybe String }
  | PostShow { id :: Int, hash :: Maybe String }
  | PostEdit { id :: Int }

fromUrl :: Router.Url -> Maybe Route
fromUrl url = case url.path of
  [] -> Just Index
  ["posts"] | sortBy <- Router.queryString "sort-by" url -> Just $ PostIndex { sortBy }
  ["posts", id'] | Just id <- Router.int id' -> Just $ PostShow { id, hash: url.hash }
  ["posts", id', "edit"] | Just id <- Router.int id' -> Just $ PostEdit { id }
  _ -> Nothing

toString :: Route -> String
toString = case _ of
  Index -> "/"
  PostIndex { sortBy } -> "/posts" <> maybe "" ("?sort-by=" <> _) sortBy
  PostShow { id, hash } -> "/posts/" <> show id <> maybe "" ("#" <> _) hash
  PostEdit { id } -> "/posts/" <> show id <> "/edit"

link :: Router.Link Route
link = Router.link Router.Hash <<< toString

component :: H.Component {} State Action
component = H.component "Router" { initialize, update, render, subscriptions }
  where
    initialize _ = { route: Nothing, url: Nothing }
    update self = case _ of
      Navigate url -> self.modify _ { route = fromUrl url, url = Just url }
    render self = case self.state.route of
      Just Index -> H.div [] [
        link (PostIndex { sortBy: Nothing }) [] [H.text "View Posts ->"]
      ]
      Just (PostIndex { sortBy }) ->
        let
          f id = link (PostShow { id, hash: Nothing }) [] [
            H.text $ "Post #" <> show id
          ]
        in
          H.div [] $ [
            H.text $ "Viewing Posts sorted by " <> show sortBy,
            H.div [] [
              H.text "Sort By: ",
              link (PostIndex { sortBy: Just "id" }) [] [H.text "Id"],
              link (PostIndex { sortBy: Just "title" }) [] [H.text "Title"]
            ],
            H.div [] $ f <$> [1, 2, 3, 4, 5]
          ]
      Just (PostShow { id, hash }) ->
        H.div [] [
          H.text $ "Viewing Post #" <> show id <> " | Section " <> show hash,
          link (PostShow { id, hash: Just "section-1" }) [] [H.text "Goto Section 1"],
          link (PostShow { id, hash: Just "section-2" }) [] [H.text "Goto Section 2"],
          link (PostShow { id, hash: Just "section-3" }) [] [H.text "Goto Section 3"],
          link (PostIndex { sortBy: Nothing }) [] [H.text "Goto Posts"],
          link Index [] [H.text "Goto Home"]
        ]
      Just (PostEdit { id }) ->
        H.div [] [
          H.text $ "Editing Post #" <> show id,
          link (PostShow { id, hash: Nothing }) [] [H.text "Goto Post"],
          link (PostIndex { sortBy: Nothing }) [] [H.text "Goto Posts"],
          link Index [] [H.text "Goto Home"]
        ]
      Nothing -> H.text "Not Found"
    subscriptions _ = [Router.subscribe Router.Hash Navigate]

main :: Effect Unit
main = do
  H.render "main" $ H.make component {}

The code part of the library is done. Writing documentation is hard :(. I'm hoping to release this by the end of the month. If you'd like, I'll be happy to add you to the private repo to get feedback.

thalesrca commented 6 years ago

Oh nice! And thank you for the example.

I see it's a little different (more like halogen), but I think I got the concept.

It would be nice if you add me, I'll try to help :)

roryc89 commented 5 years ago

Hi @utkarshkukreti. We're in a similar situation where we would like to use hedwig due to it's speed and simplicity but we need routing (and possibly other global subscriptions) for our app. Do you have any updates on when the new library may be made public? Or would it be possible to test it out? Thanks

utkarshkukreti commented 5 years ago

@thalesrodolfo @roryc89 sorry about all the delay, I have been iterating over the API for months. I've finally reached a stage where I'm happy about the functionality and put the new project online here: https://github.com/utkarshkukreti/purescript-hertz. I'll un-archive the repository once I have some documentation ready. There are 10 examples in the repo for various things including routing and other subscriptions. Until then, feel free to ask questions here.

To try it out, clone the repo, run bower install, yarn install, and yarn build. All the examples will be built into examples/dist.

utkarshkukreti commented 5 years ago

purescript-hertz is built on top of Inferno, an amazing piece of work. Hertz's performance is even better than hedwig thanks to Inferno. Unlike hedwig and Elm, Hertz has stateful components which for me turned out to be a big downside of the Elm Architecture in many places. You should be able to do anything you can do in React (which = anything you can do in pretty much any JS framework) with Hertz.

utkarshkukreti commented 5 years ago

And lastly, the compiled examples are available here for trying out: https://hertz-examples.netlify.com.

chekoopa commented 5 years ago

Bumping for Hedwig/Hertz progress. Are they alive?

А beginner PureScript programmer, switching from Elm. As this library looks like a neat alternative for Elm, I'm concerned about subscriptions (used them before) and lack of progress on them. Hertz project is neat too as it's closer to the real FRP (and Halogen). But it seems to be abandoned or frozen, however going to look through both. If it isn't so, would like to hear out something.

blankhart commented 4 years ago

It seems to me that Hedwig could be retrofitted to have an extensible subscription system with essentially no changes to the user-facing API as illustrated at the fork here: https://github.com/blankhart/purescript-hedwig/tree/subscriptions.

Hedwig's original examples continue to compile with only one change: Uses of :> as an operator synonym for a general Tuple rather than the specific tuple of a model and array of Affs must be replaced with the Tuple data constructor. This occurs only once, in the JS benchmarks example.

The extension just parameterizes the actions to be taken in a state transition by a sink of type msg -> Effect Unit rather than a simple msg, and redefines :> to lift the old "plain" async actions into the new type.

See the changes to the application mount by adding sink and subscription types and the changes to the operator, with a few additional convenience operators.

The proposed subscription system can be seen in action opening a web socket connection to the echo server at https://github.com/blankhart/purescript-hedwig/blob/subscriptions/examples/WebSocket.purs.

It should be relatively straightforward to use the same system to add a router, etc.