obsidiansystems / obelisk

Functional reactive web and mobile applications, with batteries included.
https://reflex-frp.org
BSD 3-Clause "New" or "Revised" License
956 stars 105 forks source link

Any docs for new users? #292

Closed locallycompact closed 2 years ago

locallycompact commented 5 years ago

Hi I'm struggling to get the basic tutorial applications in reflex working in obelisk.

I have the following in frontend

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE GADTs #-}
module Frontend where

import qualified Data.Text as T
import Obelisk.Frontend
import Obelisk.Route
import Reflex.Dom.Core

import Common.Api
import Common.Route
import Obelisk.Generated.Static

foo :: DomBuilder t m => m ()
foo = el "div" $ do
  t <- textInput def
  dynText $ _textInput_value t

frontend :: Frontend (R FrontendRoute)
frontend = Frontend
  { _frontend_head = el "title" $ text "Obelisk Minimal Example"
  , _frontend_body = foo
  }

fails with the error

frontend/src/Frontend.hs:18:8: error:
    • Couldn't match type ‘DomBuilderSpace m’ with ‘GhcjsDomSpace’
        arising from a use of ‘textInput’
    • In a stmt of a 'do' block: t <- textInput def
      In the second argument of ‘($)’, namely
        ‘do t <- textInput def
            dynText $ _textInput_value t’
      In the expression:
        el "div"
          $ do t <- textInput def
               dynText $ _textInput_value t
    • Relevant bindings include
        foo :: m () (bound at frontend/src/Frontend.hs:17:1)
   |
18 |   t <- textInput def
   |        ^^^^^^^^^^^^^
tomsmalley commented 5 years ago

Hi! In this particular example you can use inputElement instead of textInput, and value instead of _textInput_value.

The error is because you have only a DomBuilder t m constraint on foo, but textInput needs to know DomBuilderSpace m ~ GhcjsDomSpace. Even if you provided this constraint, obelisk's Frontend type is set up to do server side rendering which isn't performed in GhcjsDomSpace - so foo would compile, but the use in _frontend_body wouldn't.

I guess we need some better solution to this problem in general, though.

locallycompact commented 5 years ago

Ok, I guess I'm not familiar enough with reflex to know what this means. I'd assumed that obelisk was just a quicker nicer way of spinning up a reflex app, but if it can't consume the reflex tutorials directly then I can't really bridge that gap myself.

3noch commented 5 years ago

The reflex tutorials must be out of date.

locallycompact commented 5 years ago

I don't think so, they seem to work fine outside obelisk. https://github.com/reflex-frp/reflex-platform#dynamics-and-events

tomsmalley commented 5 years ago

@locallycompact the intention is for textInput to be deprecated in favour of inputElement. Obelisk is somewhat ahead of the reflex documentation in this regard.

ryantrinkle commented 5 years ago

@locallycompact The specific issue going on here is that obelisk pre-renders your pages, server-side, so all the widgets you use need to work both with and without javascript. If you have any widgets that require javascript, you can invoke them as prerender somePlaceholder someJsWidget, which will cause a placeholder to be rendered on the server side, which will then be replaced when the app loads client-side.

However, in this particular case, the JS dependence for textInput exists purely for historical reasons, so @tomsmalley's solution (using inputElement instead) should get the job done.

chengzh2008 commented 5 years ago

Same asking. A simple documentation about how Obelisk works would be nice. I am a little bit confused about the project structures and some directories.

After reading this, I understand that Obelisk does server side rendering for the index.html. Is there a switch or something that obelisk can output a static directory with index.html in it?

Not sure what the directory frontendJs under backend directory does? it seems to be empty.

Is it possible to convert an existing reflex-dom project into an Obelisk project? How to add servant into the mix?

jrodriguesimg commented 5 years ago

I also can't find any documentation about how the obelisk router works.

benkolera commented 5 years ago

@jrodriguesimg : I've started a more fully featured (compared to the reflex-examples project) demo that may be useful figuring out how routing works. You may be able to cargo cult that with following the types.

@chengzh2008 I hope to also have in that demo app an embedded servant server (it's definitely possible to run servant on top of snap for this kind of thing, but I've got to figure it out).

jrodriguesimg commented 5 years ago

Thanks @benkolera. Where can I find that demo of yours?

srid commented 5 years ago

@jrodriguesimg Probably here: https://github.com/qfpl/reflex-realworld-example/blob/master/common/src/Common/Route.hs

chengzh2008 commented 5 years ago

Thanks @benkolera @srid the reflex-realdworld-example is really a great playground for learning fullstack Haskell!

madeline-os commented 2 years ago

I am closing this ticket, not because I hate documentation (in fact, i love it a great deal), but because its scope crosses multiple projects beyond obelisk. Even within obelisk, there are a great many moving parts that would each be their own serious project to document. Please feel free to ask any specific questions as their own issues, and trust that we feel the need for comprehensive documentation as sorely as you do. Over the coming weeks, I hope to organize the documentation effort in a systematic, and transparent way.

Take this as a token of my sincerity #913