{"id":13686678,"url":"https://github.com/humhei/FCSWatch","last_synced_at":"2025-05-01T09:32:23.355Z","repository":{"id":74051685,"uuid":"163389364","full_name":"humhei/FCSWatch","owner":"humhei","description":"Run standard fsharp codes in watch mode ","archived":false,"fork":false,"pushed_at":"2024-01-30T13:36:07.000Z","size":3194,"stargazers_count":62,"open_issues_count":17,"forks_count":4,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-04-10T02:12:09.574Z","etag":null,"topics":["fsharp","watch-mode"],"latest_commit_sha":null,"homepage":null,"language":"F#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/humhei.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-12-28T08:58:09.000Z","updated_at":"2024-01-26T08:40:30.000Z","dependencies_parsed_at":null,"dependency_job_id":"0bb5edae-c23f-42e3-8644-70778f7f35a6","html_url":"https://github.com/humhei/FCSWatch","commit_stats":null,"previous_names":[],"tags_count":28,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/humhei%2FFCSWatch","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/humhei%2FFCSWatch/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/humhei%2FFCSWatch/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/humhei%2FFCSWatch/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/humhei","download_url":"https://codeload.github.com/humhei/FCSWatch/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251852875,"owners_count":21654476,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fsharp","watch-mode"],"created_at":"2024-08-02T15:00:37.737Z","updated_at":"2025-05-01T09:32:22.941Z","avatar_url":"https://github.com/humhei.png","language":"F#","funding_links":[],"categories":["F# #"],"sub_categories":[],"readme":"# Run standard fsharp codes in watch mode\n\nStable | Prerelease\n--- | ---\n[![NuGet Badge](https://buildstats.info/nuget/FCSWatch.Binary)](https://www.nuget.org/packages/FCSWatch.Binary/) | [![NuGet Badge](https://buildstats.info/nuget/FCSWatch.Binary?includePreReleases=true)](https://www.nuget.org/packages/FCSWatch.Binary/)\n\n\nMacOS/Linux | Windows\n--- | ---\n[![CircleCI](https://circleci.com/gh/humhei/FCSWatch.svg?style=svg)](https://circleci.com/gh/humhei/FCSWatch) | [![Build status](https://ci.appveyor.com/api/projects/status/0qnls95ohaytucsi?svg=true)](https://ci.appveyor.com/project/ts2fable-imports/FCSWatch)\n[![Build History](https://buildstats.info/circleci/chart/humhei/FCSWatch)](https://circleci.com/gh/humhei/FCSWatch) | [![Build History](https://buildstats.info/appveyor/chart/ts2fable-imports/FCSWatch)](https://ci.appveyor.com/project/ts2fable-imports/FCSWatch)\n\n\n---\n\n\n## Get started\n### From Cli\n`dotnet tool install --global fcswatch-cli`\n\n`fcswatch --project-file yourProjectFile`\n\nFcsWatch will load your project in autoReload mode by defalut\n\n```\nUSAGE: fcswatch.exe [--help] [--working-dir \u003cstring\u003e] [--project-file \u003cstring\u003e] [--debuggable]\n                    [--logger-level \u003cminimal|normal|quiet|debug\u003e] [--no-build] [--webhook \u003cstring\u003e] [--send]\n                    [--framework \u003cstring\u003e] [--configuration \u003cdebug|release\u003e]\n\nOPTIONS:\n\n    --working-dir \u003cstring\u003e\n                          Specfic working directory, default is current directory\n    --project-file \u003cstring\u003e\n                          Entry project file, default is exact fsproj file in working dir\n    --debuggable          Enable debuggable in vscode, This will disable auto Reload\n    --logger-level \u003cminimal|normal|quiet|debug\u003e\n                          Default is Minimal\n    --no-build            --no-build\n    --webhook \u003cstring\u003e    send a web hook when program (re)run\n    --send                Equivalent to --webhook http://localhost:9867/update\n    --framework, -f \u003cstring\u003e\n                          The target framework to build for. The default to prefer netcore.\n    --configuration, -c \u003cdebug|release\u003e\n                          Has limitations; See #26 for detail\n                          The configuration to use for building the project. The default is Debug.\n    --help                display this list of options.\n\n    -- --your-custom-args value (pass Addtional args pass to application)\n```\n\n### From Fake\n1. Install [fake5](https://fake.build/fake-gettingstarted.html)\n2. Replace build.fsx with below codes\n```fsharp\n#r \"paket:\nsource https://api.nuget.org/v3/index.json\nnuget Fake.Core.Target = 5.12.0\nnuget FcsWatch.Binary //\"\n#load \"./.fake/build.fsx/intellisense.fsx\"\n\n// start build\nopen Fake.Core\nopen Fake.IO\nopen FSharp.Compiler.SourceCodeServices\nopen FcsWatch.Binary\n\nTarget.create \"FcsWatch\" (fun _ -\u003e\n    /// replace it to your entry project file\n    let projectFile = Path.getFullName \"./FcsWatchMiniSample/FcsWatchMiniSample.fsproj\"\n    runFcsWatcher Config.DefaultValue projectFile\n)\n\nTarget.runOrDefault \"FcsWatch\"\n\n```\n3. `fake build -t \"FcsWatch\"`\n4. `Change fs files in YourProject` and save it\n\n\n## Build From project\n* .paket/paket.exe install\n* dotnet build FCSWatch.sln\n\n## File structure\n### FcsWatch.Core\nThe core library (Include a lots of common logic\ne.g `project cracker`, `file watcher`, mailbox group for concurrrent, and so on )\n\n### FcsWatch.Binary (Ref FcsWatch.Core)\nIt compile fsharp codes to .dll and .pdb\nAnd then stop the whole application and replace the `.dll` and `.pdb` and then rerun application\n\n### FcsWatch-Porta (Ref FcsWatch.Core)\nIt is  ported from [FSharp.Compiler.PortaCode](https://github.com/fsprojects/FSharp.Compiler.PortaCode)\nIt sends a webhook to the host program\nAnd then, the host program can replace its logic\n\n\n## Debug in vscode(only when AutoReload is false)\n\n### Play around\n#### From source code interaction test\n* git clone https://github.com/humhei/FCSWatch.git\n* fcswatch --project-file \"fullPath to \\FCSWatch\\tests\\datas\\TestProject\\TestProject.fsproj\" --debuggable\n* modify fs files in any of TestProject,TestLib2,TestLib1\n* Set breakpoint in any of TestProject,TestLib2,TestLib1\n* F5 Debug `Launch TestProject`\n* modify fs files in any of TestProject,TestLib2,TestLib1\n* (Optional) add new fs file in any of TestProject,TestLib2,TestLib1\n* Relaunch Debugger\n\n\n### Launch debugging in vscode\nYou can also launch debugging when running in watch mode\n```\n    {\n        \"name\": \"launch TestProject\",\n        \"type\": \"coreclr\",\n        \"request\": \"launch\",\n        \"preLaunchTask\": \"emitCompilerTmp\",\n        \"program\": \"${workspaceFolder}/YourProject/bin/Debug/targetFramwork/YourProject.exe\",\n    },\n    /// send a http request to copy dlls in obj to bin\n    {\n        \"label\": \"emitCompilerTmp\",\n        \"command\": \"curl\",\n        \"args\": [\n            \"--config\",\n            \".fake/fcswatch/port.cache\"\n        ],\n        \"presentation\": {\n            \"reveal\": \"silent\"\n        }\n    },\n  },\n```\n\nWhen you are debugging files,watch mode still take effect\n\n\n## Plugin mode\ne.g.: excelDna sample\nvscode launch.json setting\n```\n    {\n      \"name\": \"Attach Excel\",\n      \"type\": \"clr\",\n      \"request\": \"attach\",\n      \"preLaunchTask\": \"emitCompilerTmp\",\n      /// should be write automatically by script\n      \"processId\": 14876\n    },\n```\n\nbuild.fsx setting\n```fsharp\n    open FcsWatch.Binary\n\n    let app =\n        Process.GetProcesses()\n        |\u003e Array.tryFind (fun proc -\u003e proc.ProcessName = \"EXCEL\")\n        |\u003e function\n            | Some proc -\u003e Marshal.GetActiveObject(\"Excel.Application\")\n            | None -\u003e\n                failwithf \"Please manual open excel\" projectName\n        :?\u003e Application\n\n    let procId = User32.getPidFromHwnd app.Hwnd\n\n    /// trigger when file changed was detected\n    /// and (re)load debugger (after emit cache)\n    let installPlugin() =\n        addIn.Installed \u003c- true\n        Trace.trace \"installed plugin\"\n\n    /// trigger when file changed was detected\n    /// and (re)load debugger (before emit cache)\n    let unInstall() =\n        addIn.Installed \u003c- false\n        Trace.trace \"unInstalled plugin\"\n\n    /// trigger when (re)load debugger (after installPlugin())\n    let calculate() =\n        Trace.trace \"calculate worksheet\"\n        worksheet.Calculate()\n\n\n    let pluginDebugInfo: PluginDebugInfo =\n        {\n          /// Thread sleed to wait debugger attached.\n          /// Trigger when file changed was not detected\n          /// and reload debugger\n          DebuggerAttachTimeDelay = 2000\n          // pid write to .vscode/launch.json\n          Pid = procId\n          VscodeLaunchConfigurationName = \"Attach Excel\" }\n\n    let plugin : DebuggingServer.Plugin =\n        { Load = install\n          Unload = unInstall\n          Calculate = calculate\n          TimeDelayAfterUninstallPlugin = 500\n          PluginDebugInfo = pluginDebugInfo }\n\n    let config =\n        {Config.DefaultValue with\n            DevelopmentTarget = DevelopmentTarget.autoReloadPlugin plugin }\n\n    runFcsWatcher config projectFile\n\n```\n\n## Why?\nwhy not use dotnet watch:\n1. dotnet watch reference all dlls every time (which will take at least 3000ms?) (while fcs hold dlls in runtime cache)\n2. not easy to debug when you are using dotnet watch\n\n\n![](https://github.com/humhei/Resources/blob/Resources/TestfsFCSWatchVisualStud.gif)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhumhei%2FFCSWatch","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhumhei%2FFCSWatch","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhumhei%2FFCSWatch/lists"}