Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reload Suave App on File Save

Tags:

.net

f#

suave

I've recently started with Suave; I setup a project using yeoman and the F# generator. To run the app, I build an executable using Fake and then run it. Whenever I change any of the app files, i.e. *.fs files, I have to repeat the process of building and running an executable.

Is there a better process for development, wherein the app rebuilds or reloads/restarts on file save?

like image 452
Ari Avatar asked Apr 22 '16 19:04

Ari


2 Answers

The build script for the F# Snippets project does exactly this.

The idea is that you have app.fsx file that defines a top-level WebPart named app. You can see the example for F# Snippets here. The app.fsx script file can also load other files, so you can structure your application in any way you need.

The build.fsx build script then starts a server, monitors file system changes for your source code and app.fsx and reloads it using F# Compiler Service in the background and replaces the "currently loaded" server with the one obtained from the new app value.

The only limitation of the current build script is that it does not correctly relcaim memory (it should probably be fixed by recreating F# Interactive Session in the build script) and so it runs out of memory after a larger number of reloads. But still, it makes the workflow much nicer!

like image 149
Tomas Petricek Avatar answered Nov 12 '22 05:11

Tomas Petricek


I use a similar approach to Tomas but run the server in a child process of the build script. This makes the restart a little bit slower to restart but doesn't leak any memory or ports. This also lets me easily use a different working directory for my build scripts vs my app scripts (in this case ./app).

Here's a cut down version of my FAKE script.

#r "packages/FAKE/tools/FakeLib.dll"
open Fake

let wait() = System.Console.Read() |> ignore

let runServer () =
    fireAndForget (fun startInfo ->
        startInfo.WorkingDirectory <- "./app"
        startInfo.FileName <- FSIHelper.fsiPath
        startInfo.Arguments <- "--define:RELOAD server.fsx")


Target "Watch" (fun _ ->
  use watcher = !! "app/*.fsx" |> WatchChanges (fun changes ->
      tracefn "%A" changes
      killAllCreatedProcesses()
      runServer()
  )
  runServer()
  wait()
)
like image 45
Eric Avatar answered Nov 12 '22 05:11

Eric