README.md
1## yesod-bin: the Yesod executable
2
3This executable is almost exclusively used for its `yesod devel`
4capabilities, providing a development server for web apps. It also
5provides some legacy functionality, almost all of which has been
6superceded by functionality in the
7[Haskell Stack build tool](http://haskellstack.org/). This README will
8speak exclusively about `yesod devel`.
9
10__CAVEAT__ There may be some issues using `yesod devel` in Docker-enabled
11projects. See [comment on
12Github](https://github.com/yesodweb/yesod/pull/1305#issuecomment-263204471).
13
14### Development server
15
16The development server will automatically recompile your application
17whenever you make source code changes. It will then launch your app,
18and reverse-proxy to it. The reverse proxying ensures that you can
19connect to your application on a dedicated port, always get the latest
20version available, and won't get dropped connections when the app
21isn't yet ready. Instead, you'll get some very motivating messages:
22
23![Motivation](https://i.sli.mg/nO6DvN.png)
24
25## Common workflows
26
27The standard Yesod scaffoldings are configured to work with `yesod
28devel` out of the box (though see below for non-Yesod
29development). For the most part, from within your application
30directory, you'll just want to run:
31
32* `stack build yesod-bin`
33* `stack exec -- yesod devel`
34
35This will install the corresponding version of the `yesod` executable
36into your currently selected snapshot, and then use that
37executable. (Starting with version 1.5.0, you can be more lax and use
38a `yesod` executable compiled for a different snapshot. Once 1.5.0 is
39more widespread we'll probably update these instructions.)
40
41Some other common questions:
42
43* If you want to control which port you can access your application
44 on, use the `--port` command line option, e.g. `stack exec -- yesod
45 devel --port 4000`. Changing your port inside your source code _will
46 not work_, because you need to change the reverse proxying port.
47* If you want to run a command after each successful build, you can
48 use `stack exec -- yesod devel --success-hook "echo Yay!"`
49* If for some reason you want to disable the reverse proxy
50 capabilities, use `stack exec -- yesod devel
51 --disable-reverse-proxy`
52
53## How it works
54
55The workflow of the devel server is pretty simple:
56
57* Launch a reverse proxy server
58* Use Stack file-watch capability to run a build loop on your code,
59 rebuilding each time a file is modified
60* Have Stack call `yesod devel-signal` to write to a specific file
61 (`yesod-devel/rebuild`) each time a rebuild is successful
62* Each time `yesod-devel/rebuild` is modified:
63 * Kill the current child process
64 * Get a new random port
65 * Tell the reverse proxy server about the new port to forward to
66 * Run the application's devel script with two environment variables
67 set:
68 * `PORT` gives the newly generated random port. The application
69 needs to listen on that port.
70 * `DISPLAY_PORT` gives the port that the reverse proxy is
71 listening on, used for display purposes or generating URLs.
72
73Now some weird notes:
74
75* The devel script can be one of the following three files. `yesod
76 devel` will search for them in the given order. That script must
77 provide a `main` function.
78 * `app/devel.hs`
79 * `devel.hs`
80 * `src/devel.hs`
81* Unfortunately, directly killing the `ghc` interpreter has never
82 worked reliably, so we have an extra hack: when killing the process,
83 `yesod devel` also writes to a file
84 `yesod-devel/devel-terminate`. Your devel script should respect this
85 file and shutdown whenever it exists.
86 (It may be fixed in 1.6.0.5.)
87* If your .cabal file defines them, `yesod devel` will tell Stack to
88 build with the flags `dev` and `library-only`. You can use this to
89 speed up compile times (biggest win: skip building executables, thus
90 the name `library-only`).
91
92If that all seems a little complicated, remember that the Yesod
93scaffolding handles all of this for you. But if you want to implement
94it yourself...
95
96## Non-Yesod development
97
98If you'd like to use the `yesod devel` server for your non-Yesod
99application, or even for a Yesod application not based on the
100scaffolding, this section is for you! We've got a
101[sample application in the repository](https://github.com/yesodweb/yesod/tree/master/yesod-bin/devel-example)
102that demonstrates how to get this set up. It demonstrates a good way
103to jump through the hoops implied above.
104
105One important note: I highly recommend putting _all_ of the logic in
106your library, and then providing a `develMain :: IO ()` function which
107your `app/devel.hs` script reexports as `main`. I've found this to
108greatly simplify things overall, since you can ensure all of your
109dependencies are specified correctly in your `.cabal` file. Also, I
110recommend using `PackageImports` in that file, as the example app
111shows.
112