Suave in view mode (during development)

I am working on a Suave 1.0 + Angular 2.0 sample application and it is very interesting to launch a Suave server in view mode, so the server observes (js, css, html) in the root folder and subfolders and automatically send the refresh command to all open browser tabs with my application when changing any file.

lite-server from Angular 2 5min Quckstark can do this, and it is very convenient.

I think that most parts of the watch can be found in the last post by Steffen Forkman , but it’s not very clear how to send refresh to open browser tabs.

Please provide the complete code for a similar implementation using Suave .

+8
f # suave
source share
1 answer

The Suave server code should look something like this:

 #r "packages/Suave/lib/net40/suave.dll" #r "packages/FAKE/tools/FakeLib.dll" open Fake open Suave open Suave.Operators open Suave.Sockets.Control open Suave.WebSocket open Suave.Utils open Suave.Files open Suave.RequestErrors open Suave.Filters open System open System.Net let port = let rec findPort port = let portIsTaken = System.Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners() |> Seq.exists (fun x -> x.Port = int(port)) if portIsTaken then findPort (port + 1us) else port findPort 8083us let logger = Logging.Loggers.ConsoleWindowLogger Logging.LogLevel.Verbose let refreshEvent = new Event<_>() let handleWatcherEvents (events:FileChange seq) = for e in events do let fi = fileInfo e.FullPath traceImportant <| sprintf "%s was changed." fi.Name refreshEvent.Trigger() let socketHandler (webSocket : WebSocket) = fun cx -> socket { while true do let! refreshed = Control.Async.AwaitEvent(refreshEvent.Publish) |> Suave.Sockets.SocketOp.ofAsync do! webSocket.send Text (ASCII.bytes "refreshed") true } let cfg = { defaultConfig with homeFolder = Some (__SOURCE_DIRECTORY__) bindings = [ HttpBinding.mk HTTP IPAddress.Loopback port ] listenTimeout = TimeSpan.FromMilliseconds 3000. } let app : WebPart = choose [ Filters.log logger logFormat >=> never Filters.path "/websocket" >=> handShake socketHandler Filters.GET >=> Filters.path "/" >=> file "index.html" Writers.setHeader "Cache-Control" "no-cache, no-store, must-revalidate" >=> Writers.setHeader "Pragma" "no-cache" >=> Writers.setHeader "Expires" "0" >=> browseHome NOT_FOUND "Found no handlers." ] let watcher = !! ("app/*.js") ++ ("*.html") |> WatchChanges handleWatcherEvents try System.Diagnostics.Process.Start(sprintf "http://localhost:%d/index.html" port) |> ignore startWebServer cfg app finally watcher.Dispose() 

So, we configure observers who process the changes in js (generated by TypeScript) and html files and send the refresh command to the client, but at the same time we need to add the following code to the head of the index.html section to process refresh on the client side

 <!-- 3. Listen on refresh events from the server --> <script language="javascript" type="text/javascript"> function init() { websocket = new WebSocket("ws://"+window.location.host+"/websocket"); websocket.onmessage = function(evt) { location.reload(); }; } window.addEventListener("load", init, false); </script> 

In the full demo application you can find here

+11
source share

All Articles