From 5915cb5ccef2e312485a7e52e0154813a32d1fb7 Mon Sep 17 00:00:00 2001 From: Sridhar Ratnakumar Date: Wed, 31 Mar 2021 00:33:50 -0400 Subject: [PATCH 1/4] Resolve paket warning --- src/Feather/paket.references | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Feather/paket.references b/src/Feather/paket.references index e69de29..640cf91 100644 --- a/src/Feather/paket.references +++ b/src/Feather/paket.references @@ -0,0 +1 @@ +FSharp.Core \ No newline at end of file From 94a1708589a3434604c4ee09c8e900baa45d89a0 Mon Sep 17 00:00:00 2001 From: Sridhar Ratnakumar Date: Wed, 31 Mar 2021 00:34:04 -0400 Subject: [PATCH 2/4] Rough working version of live-reload server --- README.md | 8 +++--- paket.dependencies | 3 ++- paket.lock | 1 + src/Feather.Build/Library.fs | 39 ++++++++++++++++++++++++++++-- src/Feather.Build/paket.references | 3 ++- 5 files changed, 45 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 938561f..e2c9100 100644 --- a/README.md +++ b/README.md @@ -35,13 +35,11 @@ The first priority is to get a non-pipeline based (i.e one-off) static site gene dotnet tool install dotnet paket restore -# Terminal 1 dotnet run -p ./src/Feather -- -w -C example - -# Terminal 2 -dotnet LiveReloadServer ./example/output ``` +The above command will launch a live server that reloads the browser view as your source files change. + You can use `dotnet watch` (instead of `dotnet run`) to recompile and restart the tool on source change. ``` @@ -81,6 +79,6 @@ $FEATHER -w . - [x] Primitive file watcher that regenerates on source change - [x] Tailwind CSS support in .liquid files (via `twind/shim`) - [x] Finalize on a HTML template library ([#1](https://github.com/srid/Feather/issues/1)) +- [x] Add a dev server with live-reload - [ ] static/ files - [ ] Deploy something useful -- [ ] Add a dev server with live-reload diff --git a/paket.dependencies b/paket.dependencies index fba93c8..4066cf5 100644 --- a/paket.dependencies +++ b/paket.dependencies @@ -7,4 +7,5 @@ nuget Fluid.Core 2.0.0-beta-1013 nuget Fluid.ViewEngine 2.0.0-beta-1013 nuget Microsoft.Extensions.FileProviders.Physical nuget SJP.FsNotify -nuget FSharp.Control.Reactive \ No newline at end of file +nuget FSharp.Control.Reactive +nuget Westwind.AspnetCore.LiveReload \ No newline at end of file diff --git a/paket.lock b/paket.lock index 59cb4e8..03c86d4 100644 --- a/paket.lock +++ b/paket.lock @@ -137,3 +137,4 @@ NUGET System.Threading.Thread (4.3) System.Runtime (>= 4.3) TimeZoneConverter (3.4) + Westwind.AspNetCore.LiveReload (0.3.1) diff --git a/src/Feather.Build/Library.fs b/src/Feather.Build/Library.fs index 1bfce60..56ad502 100644 --- a/src/Feather.Build/Library.fs +++ b/src/Feather.Build/Library.fs @@ -4,10 +4,42 @@ open System.IO open Fluid open Fluid.ViewEngine open Microsoft.Extensions.FileProviders -open System.Threading open CommandLine open SJP.FsNotify open FSharp.Control.Reactive +open Microsoft.Extensions.DependencyInjection +open Microsoft.AspNetCore.Builder +open Microsoft.AspNetCore.Hosting +open Microsoft.Extensions.Hosting +open Westwind.AspNetCore.LiveReload + +module Web = + // TODO: do it functional way + let configureServices (services: IServiceCollection) (fp: PhysicalFileProvider) = + services + .AddLiveReload(System.Action(fun cfg -> + cfg.FolderToMonitor <- fp.Root + )) + |> ignore + let configureApp (app : IApplicationBuilder) (fp: IFileProvider) = + let opts = StaticFileOptions() + opts.FileProvider <-fp + app + .UseLiveReload() + .UseStaticFiles(opts) + |> ignore + + let run (fp: PhysicalFileProvider) = + Host.CreateDefaultBuilder() + .ConfigureWebHostDefaults( + fun webHostBuilder -> + webHostBuilder + .UseWebRoot(fp.Root) + .Configure(fun app -> configureApp app fp) + .ConfigureServices(fun srv -> configureServices srv fp) + |> ignore) + .Build() + .RunAsync() module Liquid = let private mkEngineOpts(fp: IFileProvider) = @@ -68,7 +100,10 @@ module CLI = printfn "! %s" evt.Name generateOnce(Liquid.Engine fp, x, outputPath)) watcher.Start() - Thread.Sleep(Timeout.Infinite) + use outputFp = new PhysicalFileProvider(outputPath) + async { + return! Web.run outputFp |> Async.AwaitTask + } |> Async.RunSynchronously obs.Dispose() 0 // return an integer exit code | _ -> diff --git a/src/Feather.Build/paket.references b/src/Feather.Build/paket.references index 9892f83..3f648e6 100644 --- a/src/Feather.Build/paket.references +++ b/src/Feather.Build/paket.references @@ -4,4 +4,5 @@ Fluid.ViewEngine Microsoft.Extensions.FileProviders.Physical CommandLineParser SJP.FsNotify -FSharp.Control.Reactive \ No newline at end of file +FSharp.Control.Reactive +Westwind.AspnetCore.LiveReload \ No newline at end of file From 18866e9652fbf89b597a9ecb1b8d61d74b855e10 Mon Sep 17 00:00:00 2001 From: Sridhar Ratnakumar Date: Wed, 31 Mar 2021 00:47:51 -0400 Subject: [PATCH 3/4] Refactor --- src/Feather.Build/Library.fs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Feather.Build/Library.fs b/src/Feather.Build/Library.fs index 56ad502..d23cd5c 100644 --- a/src/Feather.Build/Library.fs +++ b/src/Feather.Build/Library.fs @@ -14,30 +14,30 @@ open Microsoft.Extensions.Hosting open Westwind.AspNetCore.LiveReload module Web = - // TODO: do it functional way - let configureServices (services: IServiceCollection) (fp: PhysicalFileProvider) = + let private configureServices (fp: PhysicalFileProvider) (services: IServiceCollection) = services .AddLiveReload(System.Action(fun cfg -> cfg.FolderToMonitor <- fp.Root )) - |> ignore - let configureApp (app : IApplicationBuilder) (fp: IFileProvider) = + let private mkStaticFileOptions(fp) = let opts = StaticFileOptions() - opts.FileProvider <-fp + opts.FileProvider <- fp + opts + let private configureApp (fp: IFileProvider) (app : IApplicationBuilder) = app .UseLiveReload() - .UseStaticFiles(opts) - |> ignore - + .UseStaticFiles(mkStaticFileOptions fp) + let private configureBuilder + (fp: PhysicalFileProvider) + (builder: IWebHostBuilder) : IWebHostBuilder = + builder + .UseWebRoot(fp.Root) + .Configure(configureApp fp >> ignore) + .ConfigureServices(configureServices fp >> ignore) let run (fp: PhysicalFileProvider) = Host.CreateDefaultBuilder() .ConfigureWebHostDefaults( - fun webHostBuilder -> - webHostBuilder - .UseWebRoot(fp.Root) - .Configure(fun app -> configureApp app fp) - .ConfigureServices(fun srv -> configureServices srv fp) - |> ignore) + System.Action(configureBuilder fp >> ignore)) .Build() .RunAsync() From a9cef44738cace620a2d25f51938342518540371 Mon Sep 17 00:00:00 2001 From: Sridhar Ratnakumar Date: Wed, 31 Mar 2021 01:04:38 -0400 Subject: [PATCH 4/4] Configure logging --- src/Feather.Build/Library.fs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/Feather.Build/Library.fs b/src/Feather.Build/Library.fs index d23cd5c..943a037 100644 --- a/src/Feather.Build/Library.fs +++ b/src/Feather.Build/Library.fs @@ -12,8 +12,10 @@ open Microsoft.AspNetCore.Builder open Microsoft.AspNetCore.Hosting open Microsoft.Extensions.Hosting open Westwind.AspNetCore.LiveReload +open Microsoft.Extensions.Logging -module Web = +/// A simple live reloading server +module LiveReload = let private configureServices (fp: PhysicalFileProvider) (services: IServiceCollection) = services .AddLiveReload(System.Action(fun cfg -> @@ -27,6 +29,16 @@ module Web = app .UseLiveReload() .UseStaticFiles(mkStaticFileOptions fp) + let private configureLogging (builder: ILoggingBuilder) = + let filter (_provider: string) (category: string) (l : LogLevel) = + not ( + // Suppress verbose requesting logging from asp.net + category.Contains "Diagnostics" + || l < LogLevel.Information + ) + builder + .AddFilter(filter) + .AddConsole() let private configureBuilder (fp: PhysicalFileProvider) (builder: IWebHostBuilder) : IWebHostBuilder = @@ -34,6 +46,7 @@ module Web = .UseWebRoot(fp.Root) .Configure(configureApp fp >> ignore) .ConfigureServices(configureServices fp >> ignore) + .ConfigureLogging(System.Action(configureLogging >> ignore)) let run (fp: PhysicalFileProvider) = Host.CreateDefaultBuilder() .ConfigureWebHostDefaults( @@ -102,7 +115,7 @@ module CLI = watcher.Start() use outputFp = new PhysicalFileProvider(outputPath) async { - return! Web.run outputFp |> Async.AwaitTask + return! LiveReload.run outputFp |> Async.AwaitTask } |> Async.RunSynchronously obs.Dispose() 0 // return an integer exit code