Stable | Prerelease |
---|---|
MacOS/Linux | Windows |
---|---|
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)
- Install fake5
- Replace build.fsx with below codes
#r "paket:
source https://api.nuget.org/v3/index.json
nuget Fake.Core.Target = 5.12.0
nuget FcsWatch.Binary //"
#load "./.fake/build.fsx/intellisense.fsx"
// start build
open Fake.Core
open Fake.IO
open FSharp.Compiler.SourceCodeServices
open FcsWatch.Binary
Target.create "FcsWatch" (fun _ ->
/// replace it to your entry project file
let projectFile = Path.getFullName "./FcsWatchMiniSample/FcsWatchMiniSample.fsproj"
runFcsWatcher Config.DefaultValue projectFile
)
Target.runOrDefault "FcsWatch"
fake build -t "FcsWatch"
Change fs files in YourProject
and save it
- .paket/paket.exe install
- dotnet build FCSWatch.sln
The core library (Include a lots of common logic
e.g project cracker
, file watcher
, mailbox group for concurrrent, and so on )
It compile fsharp codes to .dll and .pdb
And then stop the whole application and replace the .dll
and .pdb
and then rerun application
It is ported from FSharp.Compiler.PortaCode It sends a webhook to the host program And then, the host program can replace its logic
- 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
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
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
open FcsWatch.Binary
let app =
Process.GetProcesses()
|> Array.tryFind (fun proc -> proc.ProcessName = "EXCEL")
|> function
| Some proc -> Marshal.GetActiveObject("Excel.Application")
| None ->
failwithf "Please manual open excel" projectName
:?> Application
let procId = User32.getPidFromHwnd app.Hwnd
/// trigger when file changed was detected
/// and (re)load debugger (after emit cache)
let installPlugin() =
addIn.Installed <- true
Trace.trace "installed plugin"
/// trigger when file changed was detected
/// and (re)load debugger (before emit cache)
let unInstall() =
addIn.Installed <- false
Trace.trace "unInstalled plugin"
/// trigger when (re)load debugger (after installPlugin())
let calculate() =
Trace.trace "calculate worksheet"
worksheet.Calculate()
let pluginDebugInfo: 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" }
let plugin : DebuggingServer.Plugin =
{ Load = install
Unload = unInstall
Calculate = calculate
TimeDelayAfterUninstallPlugin = 500
PluginDebugInfo = pluginDebugInfo }
let config =
{Config.DefaultValue with
DevelopmentTarget = DevelopmentTarget.autoReloadPlugin plugin }
runFcsWatcher config projectFile
why not use dotnet watch:
- dotnet watch reference all dlls every time (which will take at least 3000ms?) (while fcs hold dlls in runtime cache)
- not easy to debug when you are using dotnet watch