# plzwrk [](https://gitter.im/meeshkan/community) A Haskell front-end framework. Available as a Hackage package: [`plzwrk`](https://hackage.haskell.org/package/plzwrk) 📖 Looking for an overview? [Read our announcement blog post](https://meeshkan.com/blog/introducing-plzwrk/). ## In this document: * [When to use `plzwrk`](#when-to-use-plzwrk) * [Examples using `plzwrk`](examples-using-plzwrk) * [Hello world](#hello-world) * [Aphorism machine](#aphorism-machine) * [Making a webpage](#making-a-webpage) * [Documentation](#documentation) * [Design of `plzwrk`](#design-of-plzwrk) * [PWX](#pwx) * [Hydrating with a state](#hydrating-with-a-state) * [Event handlers](#event-handlers) * [Server-side rendering](#server-side-rendering) * [Testing your code](#testing-your-code) * [Contributing](#contributing) * [Local development](#local-development) ## When to use `plzwrk` `plzwrk` may be a good fit if you enjoy the benefits of programming in Haskell and you'd like to create a web app. ⚠️ Warning: `plzwrk` is experimental. It is unfit for production and the syntax will change frequently, often in non-backward-compatible ways. We will try to document all of these changes in the [changelog](ChangeLog.md). Some alternatives to `plzwrk`: - [Elm](https://elm-lang.org/), a delightful language for reliable web apps. - [Purescript react basic](https://github.com/lumihq/purescript-react-basic), an opinionated set of bindings to the React library, optimizing for the most basic use cases. ## Examples using `plzwrk` ### Hello world An example web page that says 'Hello world!' ```haskell {-# LANGUAGE QuasiQuotes #-} import Web.Framework.Plzwrk import Web.Framework.Plzwrk.Asterius main :: IO () main = do browser <- asteriusBrowser plzwrk'_ [pwx|
Hello world!
|] browser ``` [See the Hello World example live](https://plzwrk-hello-world.surge.sh). ### Aphorism machine An Aphorism Machine that spits out and hides universal truths on demand. [Check out the source code in the `kitchen-sink` directory](./kitchen-sink/Main.hs). Or [see the Aphorism Machine live](https://plzwrk-kitchen-sink.surge.sh). ## Making a webpage `plzwrk` uses [Asterius](https://github.com/tweag/asterius) as its backend for web development. A minimal flow is shown below. It assumes that you have a file called `Main.hs` in the present working directory with a function `main :: IO ()` inside of it, not unlike in our [hello world example](#hello-world). ```bash username@hostname:~/my-dir$ docker run --rm -it -v $(pwd):/project -w /project meeshkan/plzwrk asterius@hostname:/project$ ahc-link --input-hs Main.hs --browser --bundle ``` If you're using `ahc-cabal`, compiling an application using `plzwrk` is no different than compiling an application as described in the [Asterius documentation](https://asterius.netlify.app) with **one caveat**. You **must** use `--constraint "plzwrk +plzwrk-enable-asterius"` when running `ahc-cabal`. ## Documentation The main documentation for `plzwrk` is on [Hackage](https://hackage.haskell.org/package/plzwrk). The four importable modules are: - [`Web.Frameworks.Plzwrk`](https://hackage.haskell.org/package/plzwrk-0.0.0.9/docs/Web-Framework-Plzwrk.html) for the basic functions - [`Web.Frameworks.Plzwrk.Tag`](https://hackage.haskell.org/package/plzwrk-0.0.0.9/docs/Web-Framework-Plzwrk-Tag.html) for helper functions to make takes like `input` or `br` if you are not using `pwx`. - [`Web.Frameworks.Plzwrk.MockJSVal`](https://hackage.haskell.org/package/plzwrk-0.0.0.9/docs/Web-Framework-Plzwrk-MockJSVal.html) to use a mock browser. - [`Web.Frameworks.Plzwrk.Asterius`](https://hackage.haskell.org/package/plzwrk-0.0.0.9/docs/Web-Framework-Plzwrk-Asterius.html) to use a bindings for a real browser courtesy of [Asterius](https://github.com/tweag/asterius). ## Design of `plzwrk` `plzwrk` is inspired by [Redux](https://redux.js.org/) for its state management. The main idea is that you have an HTML-creation function that is composed, via `<*>`, with getters from a state. ```haskell -- State data MyState = MkMyState { _name :: Text, age :: Int, _tags :: [Text] } -- Function hydrating a DOM with elementse from the state makeP = (\name age -> [pwx'|#t{concat [name, " is the name and ", show age, " is my age."]}#
|]) <$> _name <*> _age -- The same function using functional tags instead of pwx makeP = (\name age -> p'__ concat [name, " is the name and ", show age, " is my age."]) <$> _name <*> _age ``` HTML-creation functions can be nested, allowing for powerful abstractions: ```haskell nested = div_ (take 10 $ repeat makeP) ``` ### PWX `pwx` is similar to [`jsx`](https://reactjs.org/docs/introducing-jsx.html). The main difference is that instead of only using `{}`, `pwx` uses four different varieties of `#{}#`: - `#e{}#` for a single element. - `#el{}#` for a list of elements. - `#t{}#` for a single piece of text, either as a node in the body of an element or as a text attribute. - `#c{}#` for a callback attribute. ### Hydrating with a state HTML-creation functions use an apostrophe after the tag name (ie `div'`) if they accept arguments from a state and no apostrophe (ie `div`) if they don't. The same is true of `pwx`, ie `[pwx|