Running a website in a language as obscure as Haskell can at times be challenging. Here are some code snippets I have found that help make Yesod, and Javascript easier to work with together.
Setting up a non-minified Scaffolded, development enviornment.
-- | Adding the (\bs -> Right bs) will fix up your dev enviornment to produce readable Javascript
addStaticContent
| development = addStaticContentExternal (\bs->Right bs) genFileName Settings.staticDir (StaticR . flip StaticRoute [])
| otherwise = addStaticContentExternal minifym genFileName Settings.staticDir (StaticR . flip StaticRoute [])
Make a Tests.hs file and put javascript tests in it
Make a wrapper for your getparams method to get data into haskell in less steps
{-# LANGUAGE TupleSections, OverloadedStrings, QuasiQuotes, TemplateHaskell, TypeFamilies, RecordWildCards,DeriveGeneric, MultiParamTypeClasses, FlexibleInstances #-}
module ContentCfgTypes
( module ContentCfgTypes
) where
import Prelude hiding (head, init, last
,readFile, tail, writeFile)
import GHC.Generics
import Control.Applicative ((<$>), (<*>))
import Yesod
--import Text.Julius
import qualified Data.Aeson as A
import Data.Text
--import Yesod
{-| Content Types are the configuration object and helpers for them
for all the different content widgets possible in onping2.0.
Because they are defined for use in a database context they have to be strictly
defined.
|-}
-- | Every ContentConfig type has to have a constructor here
-- This is what is put into the content array
type MaybeConfig a = Maybe (A.Result a)
data ContentConfig = TestConfig !TestConfigObj
deriving (Read,Show,Eq,Generic)
instance FromJSON ContentConfig
instance ToJSON ContentConfig
lookupContent ::(A.FromJSON a , MonadHandler m) => ( (Text,Text) -> (Text,Value) ) -> m (Maybe (A.Result a))
lookupContent objTransformer = do
req <- getRequest
case reqGetParams req of
[] -> return Nothing
lst -> return $ Just (A.fromJSON.object $ objTransformer <$> lst )
{-| Lookup content will take a list of values and parse them
with a transformer into the right values. Then will map them
into a JSON Object.
To do this the final Data type must be an Instance of FromJSON and
the transormer provided must convert (Text,Text) into a (Text,Val) type
according to whatever Transformation rule you want |-}
--Example stuff
data TestObj = TestObj { testWidth :: Int
,testTitle :: Text
,testStep :: Int
}
deriving (Read, Show,Eq)
instance FromJSON TestObj where
parseJSON (Object tObj) = TestObj <$>
tObj .: "width" <*>
tObj .: "title" <*>
tObj .: "step"
parseJSON _ = fail "Rule: Expecting Test Object Received, Other"
instance ToJSON TestObj where
toJSON (TestObj {..}) = object
[
"width" .= testWidth
,"step" .= testSte
,"title" .= testTitle
]
-- | An example transformer on a get parameter string
exTransformObj :: (Text,Text) -> (Text, Value)
exTransformObj (t,v)
| t == "width" = (t .= intVal v)
| t == "title" = (t .= textVal v)
| otherwise = (t .= toJSON v)
As you can see I make use of Data.Aeson in mine. Mostly because I wanted this to feel like the Yesod native: parseJsonBody
Another thing I would suggest is coming up with a way to duplicate the route ideas found in Yesod on the client route information contained in Angular. The way I did it was to define a type called ClientRoute then anywhere I am using it I mirror the Yesod convention for routes (i.e. @{MyRouteR}) with @{MyRouteCR}.
The combination of widgets, client routes, JSON parsed GET, JSON parsed POST and extensible directives (a la AngularJS) are very effective for speedy web development with high assurance.a few other ideas
- make a layout with no css or anything else for creating angularJS directives
- you can separate your directives into composable (serverside) pieces using the JavascriptUrl type
#{toJSON foo} can be used to create javascript objects statically based on the parameters you pulled out of your get string, this is killer!
Thoughts on Haskell and Javascript mixing
So obviously, I chose Haskell and am stuck with Javascript. However I don't mind Javascript all that much (except when I do). The beautiful thing about working with the two together is how well anchored Yesod can help you keep your client code. use Angular, use Directives, use Widgets and compose compose compose...
If anyone already has a great install of Karma or something like it that works with Yesod, please let me know!
No comments:
Post a Comment