Skip to content

Instantly share code, notes, and snippets.

@asufana
Last active December 23, 2015 05:35
Show Gist options
  • Save asufana/e93a0a64f0495c532db0 to your computer and use it in GitHub Desktop.
Save asufana/e93a0a64f0495c532db0 to your computer and use it in GitHub Desktop.
F# (FSharp) Suave.io HotDeployコード

F# (FSharp) Suave.io HotDeployコード

対象スクリプトの修正を検知して再ロードする

参考://https://github.com/tpetricek/suave-xplat-gettingstarted/blob/master/build.fsx

環境整備

下記を参考にFSharp環境を整備する

https://gist.github.com/asufana/b64f280fe5e442a45253

依存性解決

$ paket init
$ vim paket.dependencies
source https://www.nuget.org/api/v2
nuget FAKE
nuget Suave
nuget FSharp.Compiler.Service

$ paket install

アプリケーションコード

App.fsx
#r "packages/Suave/lib/net40/Suave.dll"

open Suave
open Suave.Web
open Suave.Http.Successful

let app = OK "Welcome"
suave.fsx
#r "packages/Suave/lib/net40/Suave.dll"
#r "packages/FAKE/tools/FakeLib.dll"
#r "packages/FSharp.Compiler.Service/lib/net45/FSharp.Compiler.Service.dll"

#load "App.fsx"
open App

open Fake
open System
open System.IO
open Suave
open Suave.Web
open Suave.Types
open Microsoft.FSharp.Compiler.Interactive.Shell

let sbOut = new Text.StringBuilder()
let sbErr = new Text.StringBuilder()

let fsiSession =
  let inStream = new StringReader("")
  let outStream = new StringWriter(sbOut)
  let errStream = new StringWriter(sbErr)
  let fsiConfig = FsiEvaluationSession.GetDefaultConfiguration()
  let argv = Array.append [|"/fake/fsi.exe"; "--quiet"; "--noninteractive"; "-d:DO_NOT_START_SERVER"|] [||]
  FsiEvaluationSession.Create(fsiConfig, argv, inStream, outStream, errStream)

let reportFsiError (e:exn) =
  traceError "Reloading fsx script failed."
  traceError (sprintf "Message: %s\nError: %s" e.Message (sbErr.ToString().Trim()))
  sbErr.Clear() |> ignore

let reloadScript () =
  try
    //traceImportant "Reloading fsx scripts..."
    let appFsx = __SOURCE_DIRECTORY__ @@ "App.fsx"
    fsiSession.EvalInteraction(sprintf "#load @\"%s\"" appFsx)
    fsiSession.EvalInteraction("open App")

    match fsiSession.EvalExpression("app") with
    | Some app -> Some(app.ReflectionValue :?> WebPart)
    | None -> failwith "Couldn't get 'app' value"
  with e -> reportFsiError e; None

let serverConfig =
  { defaultConfig with
      homeFolder = Some __SOURCE_DIRECTORY__
      logger = Logging.Loggers.saneDefaultsFor Logging.LogLevel.Warn
      bindings = [ Types.HttpBinding.mk' Types.HTTP "127.0.0.1" 8083 ] }

let currentApp =
  ref (fun _ -> async { return None })

let reloadAppServer () =
  reloadScript()
  |> Option.iter (fun app ->
    currentApp.Value <- app
    traceImportant "fsx scripts reloaded.")

//-------------------

Target "run" (fun _ ->
  let app ctx = currentApp.Value ctx
  let _, server = startWebServerAsync serverConfig app

  // Start Suave to host it on localhost
  reloadAppServer()
  Async.Start(server)

  // Watch for changes & reload when app.fsx changes
  use watcher =
    !! (__SOURCE_DIRECTORY__ @@ "*.*")
    |> WatchChanges (fun _ -> reloadAppServer())
  traceImportant "Waiting for fsx scripts edits. Press any key to stop."
  System.Console.ReadLine() |> ignore
)

RunTargetOrDefault "run"

起動する

$ fakerun suave.fsx

Paket version 2.38.0.0
0 seconds - ready.
FakePath: /Users/hana/Dropbox/Develop/FSharp/LightningTalks/packages/FAKE/tools/FakeLib.dll
FAKE - F# Make "4.11.3"
Running Buildscript: suave.fsx
Cache doesn't exist
Building project with version: LocalBuild
Shortened DependencyGraph for Target run:
<== run

The resulting target order is:
 - run
Starting Target: run
fsx scripts reloaded.
dirs to watch: ["/Users/hana/Dropbox/Develop/FSharp/LightningTalks"]
watching dir: /Users/hana/Dropbox/Develop/FSharp/LightningTalks
Waiting for fsx scripts edits. Press any key to stop.

App.fsx を修正保存すると、自動リロードされ fsx scripts reloaded. とコンソール出力される

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