Reload Suave App on File Save
Asked Answered
E

2

6

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?

Electrocautery answered 22/4, 2016 at 19:44 Comment(1)
FsReveal's build script does this: github.com/fsprojects/FsReveal/blob/master/build.fsxAdelric
B
4

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!

Breathless answered 22/4, 2016 at 23:26 Comment(2)
As I understand it, an alternative is to use script files (.fsx). Is there a "best practice" migration path from a scripted suave app to a compiled one?Electrocautery
You can setup the project to work both ways. See github.com/fssnippets/fssnip-website for example.Breathless
C
1

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()
)
Cellini answered 10/5, 2016 at 15:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.