Skip to content

Repository files navigation

Run standard fsharp codes in watch mode

StablePrerelease
NuGet BadgeNuGet Badge
MacOS/LinuxWindows
CircleCIBuild status
Build HistoryBuild History

Get started

From Cli

dotnet tool install --global fcswatch-cli

fcswatch --project-file yourProjectFile

FcsWatch will load your project in autoReload mode by defalut

USAGE: fcswatch.exe [--help] [--working-dir <string>] [--project-file <string>] [--debuggable]
[--logger-level <minimal|normal|quiet|debug>] [--no-build] [--webhook <string>] [--send]
[--framework <string>] [--configuration <debug|release>]
OPTIONS:
--working-dir <string>
Specfic working directory, default is current directory
--project-file <string>
Entry project file, default is exact fsproj file in working dir
--debuggable Enable debuggable in vscode, This will disable auto Reload
--logger-level <minimal|normal|quiet|debug>
Default is Minimal
--no-build --no-build
--webhook <string> send a web hook when program (re)run
--send Equivalent to --webhook http://localhost:9867/update
--framework, -f <string>
The target framework to build for. The default to prefer netcore.
--configuration, -c <debug|release>
Has limitations; See #26 for detail
The configuration to use for building the project. The default is Debug.
--help display this list of options.
-- --your-custom-args value (pass Addtional args pass to application)

From Fake

  1. Install fake5
  2. Replace build.fsx with below codes
#r "paket:source https://api.nuget.org/v3/index.jsonnuget Fake.Core.Target = 5.12.0nuget FcsWatch.Binary //"
#load "./.fake/build.fsx/intellisense.fsx"// start buildopenFake.CoreopenFake.IOopenFSharp.Compiler.SourceCodeServicesopenFcsWatch.Binary
Target.create "FcsWatch"(fun _ ->/// replace it to your entry project fileletprojectFile= Path.getFullName "./FcsWatchMiniSample/FcsWatchMiniSample.fsproj"
runFcsWatcher Config.DefaultValue projectFile
)
Target.runOrDefault "FcsWatch"
  1. fake build -t "FcsWatch"
  2. Change fs files in YourProject and save it

Build From project

  • .paket/paket.exe install
  • dotnet build FCSWatch.sln

File structure

FcsWatch.Core

The core library (Include a lots of common logic e.g project cracker, file watcher, mailbox group for concurrrent, and so on )

FcsWatch.Binary (Ref FcsWatch.Core)

It compile fsharp codes to .dll and .pdb And then stop the whole application and replace the .dll and .pdb and then rerun application

FcsWatch-Porta (Ref FcsWatch.Core)

It is ported from FSharp.Compiler.PortaCode It sends a webhook to the host program And then, the host program can replace its logic

Debug in vscode(only when AutoReload is false)

Play around

From source code interaction test

  • git clone https://github.com/humhei/FCSWatch.git
  • fcswatch --project-file "fullPath to \FCSWatch\tests\datas\TestProject\TestProject.fsproj" --debuggable
  • modify fs files in any of TestProject,TestLib2,TestLib1
  • Set breakpoint in any of TestProject,TestLib2,TestLib1
  • F5 Debug Launch TestProject
  • modify fs files in any of TestProject,TestLib2,TestLib1
  • (Optional) add new fs file in any of TestProject,TestLib2,TestLib1
  • Relaunch Debugger

Launch debugging in vscode

You can also launch debugging when running in watch mode

 {
"name": "launch TestProject",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "emitCompilerTmp",
"program": "${workspaceFolder}/YourProject/bin/Debug/targetFramwork/YourProject.exe",
},
/// send a http request to copy dlls in obj to bin
{
"label": "emitCompilerTmp",
"command": "curl",
"args": [
"--config",
".fake/fcswatch/port.cache"
],
"presentation": {
"reveal": "silent"
}
},
},

When you are debugging files,watch mode still take effect

Plugin mode

e.g.: excelDna sample vscode launch.json setting

 {
"name": "Attach Excel",
"type": "clr",
"request": "attach",
"preLaunchTask": "emitCompilerTmp",
/// should be write automatically by script
"processId": 14876
},

build.fsx setting

openFcsWatch.Binaryletapp=
Process.GetProcesses()|> Array.tryFind (fun proc -> proc.ProcessName ="EXCEL")|>function| Some proc -> Marshal.GetActiveObject("Excel.Application")| None ->
failwithf "Please manual open excel" projectName
:?> Application
letprocId= User32.getPidFromHwnd app.Hwnd
/// trigger when file changed was detected/// and (re)load debugger (after emit cache)letinstallPlugin()=
addIn.Installed <-true
Trace.trace "installed plugin"/// trigger when file changed was detected/// and (re)load debugger (before emit cache)letunInstall()=
addIn.Installed <-false
Trace.trace "unInstalled plugin"/// trigger when (re)load debugger (after installPlugin())letcalculate()=
Trace.trace "calculate worksheet"
worksheet.Calculate()letpluginDebugInfo:PluginDebugInfo ={/// Thread sleed to wait debugger attached./// Trigger when file changed was not detected/// and reload debugger DebuggerAttachTimeDelay =2000// pid write to .vscode/launch.json
Pid = procId
VscodeLaunchConfigurationName ="Attach Excel"}letplugin:DebuggingServer.Plugin ={ Load = install
Unload = unInstall
Calculate = calculate
TimeDelayAfterUninstallPlugin =500
PluginDebugInfo = pluginDebugInfo }letconfig={Config.DefaultValue with
DevelopmentTarget = DevelopmentTarget.autoReloadPlugin plugin }
runFcsWatcher config projectFile

Why?

why not use dotnet watch:

  1. dotnet watch reference all dlls every time (which will take at least 3000ms?) (while fcs hold dlls in runtime cache)
  2. not easy to debug when you are using dotnet watch

About

Run standard fsharp codes in watch mode

Topics

Resources

Stars

61 stars

Watchers

6 watching

Forks

Releases

Packages

Used by

Contributors

Languages