Skip to content

Instantly share code, notes, and snippets.

@DarinM223
Last active December 5, 2023 22:06
Show Gist options
  • Save DarinM223/c2d48f1386e396dbd74225df6f9545e4 to your computer and use it in GitHub Desktop.
Save DarinM223/c2d48f1386e396dbd74225df6f9545e4 to your computer and use it in GitHub Desktop.
Setting up a simple Reflex GHCJS project

Setting up a Reflex GHCJS Project

This is a simple tutorial that doesn't go deep into nix.

Step 1. Create new project

Use mkdir to create a new folder and cabal init to initialize a new cabal project.

mkdir project
cd project
cabal init

Step 2. Configure cabal file

First download your file that includes the stanzas for default extensions and GHC options. Here is an example:

wget raw.githubusercontent.com/DarinM223/configs/master/defaults.cabal

Open your project.cabal file and copy the stanzas into it (before the executable section). Then move cabal-version to the top of the file, change the version to 2.2 and change the license to 2.2 style (BSD3 becomes BSD-3-Clause, etc). Then in the executable project section, add import: exts, opts where exts and opts are stanzas for the extensions and GHC options. Finally, delete the file you downloaded (so it doesn't conflict with your project.cabal).

Step 3. Set up reflex platform

In order to consistently use a modern GHC and GHCJS, we use reflex platform which uses nix to keep the environment reproducible. We have to add reflex platform as a git submodule to make it possible to run ./try-reflex from any clone of this repo.

git init
git submodule add https://github.com/reflex-frp/reflex-platform

Step 4. Set up tmux

Ghcid and Ghci require you to be in the reflex platform shell, but your editor most likely won't look good inside the reflex shell. In order to handle this we need tmux to split the terminal into panes. Then the Ghcid and Ghci panes can be inside the shell, and the editor can be in the normal environment.

First run tmux with tmux in your folder.

  • To split vertically, do C-b "
  • To change the vertical pane size, do C-b M-Up/Down
  • To split horizontally, do C-b %
  • To switch to next pane, do C-b o
  • To switch to previous pane, do C-b ;

You want at least three panes total. Inside two panes, run ./reflex-platform/try-reflex to get into the reflex shell first. Then run cabal new-repl in one pane and ghcid -c cabal new-repl in the other. If you have the editor in another pane, whenever you save a Haskell file, the Ghcid pane should update and show errors if they exist.

Step 5. Build JS in the REPL

Building the JS part takes a while, and it may be inefficient to have it run every time you save a file. However, it would be nice to have an easy way to build the project in GHCJS from the panes we already have. We can do this by running the command to build in GHCJS from Ghci.

The actual command to build in GHCJS is this:

cabal new-build --ghcjs

So we want to run this inside Ghci.

First we have to add the process library to our build-depends in project.cabal (and reload Ghcid after). Then we add the following after the module declaration in our main file:

import System.Process

buildJS :: IO String
buildJS = readProcess "cabal" ["new-build", "--ghcjs"] ""

Now reload the Ghci and now you can build to JS in the repl by typing buildJS.

Step 6. Opening the JS result

Now to see what we compiled, we go into the

./dist-newstyle/build/{platform}/ghcjs-{version}/{project}-{project-version}/x/{project}/build/{project}/{project}.jsexe/

path and there should be a index.html file inside there. If you double click it the browser should open the result in a new tab.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment