## yesod-bin: the Yesod executable This executable is almost exclusively used for its `yesod devel` capabilities, providing a development server for web apps. It also provides some legacy functionality, almost all of which has been superceded by functionality in the [Haskell Stack build tool](http://haskellstack.org/). This README will speak exclusively about `yesod devel`. __CAVEAT__ There may be some issues using `yesod devel` in Docker-enabled projects. See [comment on Github](https://github.com/yesodweb/yesod/pull/1305#issuecomment-263204471). ### Development server The development server will automatically recompile your application whenever you make source code changes. It will then launch your app, and reverse-proxy to it. The reverse proxying ensures that you can connect to your application on a dedicated port, always get the latest version available, and won't get dropped connections when the app isn't yet ready. Instead, you'll get some very motivating messages: ![Motivation](https://i.sli.mg/nO6DvN.png) ## Common workflows The standard Yesod scaffoldings are configured to work with `yesod devel` out of the box (though see below for non-Yesod development). For the most part, from within your application directory, you'll just want to run: * `stack build yesod-bin` * `stack exec -- yesod devel` This will install the corresponding version of the `yesod` executable into your currently selected snapshot, and then use that executable. (Starting with version 1.5.0, you can be more lax and use a `yesod` executable compiled for a different snapshot. Once 1.5.0 is more widespread we'll probably update these instructions.) Some other common questions: * If you want to control which port you can access your application on, use the `--port` command line option, e.g. `stack exec -- yesod devel --port 4000`. Changing your port inside your source code _will not work_, because you need to change the reverse proxying port. * If you want to run a command after each successful build, you can use `stack exec -- yesod devel --success-hook "echo Yay!"` * If for some reason you want to disable the reverse proxy capabilities, use `stack exec -- yesod devel --disable-reverse-proxy` ## How it works The workflow of the devel server is pretty simple: * Launch a reverse proxy server * Use Stack file-watch capability to run a build loop on your code, rebuilding each time a file is modified * Have Stack call `yesod devel-signal` to write to a specific file (`yesod-devel/rebuild`) each time a rebuild is successful * Each time `yesod-devel/rebuild` is modified: * Kill the current child process * Get a new random port * Tell the reverse proxy server about the new port to forward to * Run the application's devel script with two environment variables set: * `PORT` gives the newly generated random port. The application needs to listen on that port. * `DISPLAY_PORT` gives the port that the reverse proxy is listening on, used for display purposes or generating URLs. Now some weird notes: * The devel script can be one of the following three files. `yesod devel` will search for them in the given order. That script must provide a `main` function. * `app/devel.hs` * `devel.hs` * `src/devel.hs` * Unfortunately, directly killing the `ghc` interpreter has never worked reliably, so we have an extra hack: when killing the process, `yesod devel` also writes to a file `yesod-devel/devel-terminate`. Your devel script should respect this file and shutdown whenever it exists. * If your .cabal file defines them, `yesod devel` will tell Stack to build with the flags `dev` and `library-only`. You can use this to speed up compile times (biggest win: skip building executables, thus the name `library-only`). If that all seems a little complicated, remember that the Yesod scaffolding handles all of this for you. But if you want to implement it yourself... ## Non-Yesod development If you'd like to use the `yesod devel` server for your non-Yesod application, or even for a Yesod application not based on the scaffolding, this section is for you! We've got a [sample application in the repository](https://github.com/yesodweb/yesod/tree/master/yesod-bin/devel-example) that demonstrates how to get this set up. It demonstrates a good way to jump through the hoops implied above. One important note: I highly recommend putting _all_ of the logic in your library, and then providing a `develMain :: IO ()` function which yoru `app/devel.hs` script reexports as `main`. I've found this to greatly simplify things overall, since you can ensure all of your dependencies are specified correctly in your `.cabal` file. Also, I recommend using `PackageImports` in that file, as the example app shows.