git clone https://gitlab.com/platonic/shpadoinkle.git
cd Shpadoinkle
Extend an example
This article will show you how to build an example project, and how to load the development environment to suit your needs. First, however, you’ll need to fetch the source code:
Building Examples
Building from source can take a long time. If you run with nix-build it’s highly recommended you use Cachix.
|
GHCjs
When built with GHCjs, Shpadoinkle Haskell code is compiled to JavaScript. This is, for the majority of use cases, the recommended path for running code in production.
nix-build --arg isJS true -A Shpadoinkle-examples
This will generate a folder called result
. This contains the output of GHCjs, which you can serve to browsers. Here we use warp
, which is a static file server written in Haskell. However, you can serve the output in any way you’d like.
nix-shell -p haskellPackages.wai-app-static --command "warp --docroot result/bin/counter.jsexe --port 8080"
Open localhost:8080
in your browser, and you should see the counter example.
GHC
When built with GHC, Shpadoinkle runs via JSaddle Warp. This allows frontend Haskell code to be compiled and executed as a backend binary. IO effects are sent to the browser over a websocket, where they are executed by a minimal client written in JavaScript.
nix-build --arg isJS false -A Shpadoinkle-examples
This will generate a folder called result
. This contains the output of GHC. You can now serve an example.
./result/bin/counter
Open localhost:8080
in your browser, and you should see the counter example.
Live development
For live development, building a fully optimized build from scratch with nix-build
can be too slow. When writing code, we need rapid feedback to be productive.
GHCID
Either "GHCi as a daemon" or "GHC + a bit of an IDE". To a first approximation, it opens GHCi and runs :reload whenever your source code changes, formatting the output to fit a fixed-height console.
GHCID is supplied out-of-the-box by the nix-shell
in Shpadoinkle. You can use GHCID to get rapid feedback as follows:
nix-shell
ghcid --command "cabal repl examples:counter"
Or, as a one-liner:
nix-shell --command "ghcid --command 'cabal repl examples:counter'"
Repl Serving
The easiest way to get changes into your browser as fast as possible is to reload main
in a REPL. There are two ways to do this — with cabal repl
, or automatically with ghcid
.
Manually
First, load the REPL:
nix-shell
cabal repl examples:counter
Then, run the application by executing main
. This will serve the application on localhost:8080
. When you make changes to the code, simply interrupt the process by pressing btn:[Ctrl + C], then reload and run main
once again:
:reload
main
Refresh your browser to view updates.
Unfortunately, JSaddle’s websocket frontend code doesn’t yet support FireFox due to this issue. Work is underway to remediate this. |
With GHCID
This will execute :reload
and main
every time the source code changes, because we’re using GHCID:
nix-shell --command "ghcid --command 'cabal repl examples:counter' --run"
Live reloading on the client is also possible:
nix-shell --command "ghcid --command 'cabal repl examples:counter' --run='Main.dev'"
Incremental Builds
Incremental builds also work just fine. To build the specific example, you can run nix-build
for the examples attribute:
nix-build -A Shpadoinkle-examples
And likewise for GHCjs:
nix-build -A Shpadoinkle-examples --arg isJS true
If you run nix-build or nix-build --arg isJS true without specifying a specific attribute, there will be multiple result-<n> symlinked folders. However, if you do specify an attribute, then ./result/ (without a number suffix) will point to the most recent attribute built. However, if you’re ever confused as to which result points to where, just run ls -l . All symlinks point to an attribute name, so just look for Shpadoinkle-examples !
|
If you want to build only the counter example, though, that’s best done with a nix-shell:
nix-shell
cabal build examples:counter
Using cabal build
directly will use the standard Haskell incremental builds. Results can be found in the ./dist-newstyle/
folder, instead of the result symlink elaborated on earlier.
Lastly, to build with GHCjs, just predicate the nix-shell
with the associated argument:
nix-shell --arg isJS true
cabal build examples:counter