diff --git a/CHANGELOG.md b/CHANGELOG.md
index e338037..d6a5e5f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html) from version [0.1.0] moving forward.
+## [0.2.1] - 2025-06-28
+### Fixed
+- Bug fix targeting issue ([#53](https://github.com/fable-compiler/vite-plugin-fable/issues/53)) as log warn and no crash, for protocol error in json rpc serialization when there is id count mismatch
+- removed Nojaf.React bindings nuget package and using Feliz instead for sample-project, as it is what is most used in community projects and suggested by official fable docs for React.
+- pr ([#55](https://github.com/fable-compiler/vite-plugin-fable/pull/55))
+
## [0.2.0] - 2025-06-24
### Changed
- Upgrade to Vite 7.0.0 as peer dependency and adjust transform hook to use latest filter property, pr ([#49](https://github.com/fable-compiler/vite-plugin-fable/pull/49)), targets issue ([#39]([#39](https://github.com/fable-compiler/vite-plugin-fable/issues/39))
diff --git a/index.js b/index.js
index 3f2dffd..1be94d8 100644
--- a/index.js
+++ b/index.js
@@ -414,6 +414,30 @@ export default function fablePlugin(userConfig) {
state.dotnetProcess.stdout,
);
+ if (process.env.VITE_PLUGIN_FABLE_DEBUG) {
+ state.endpoint.on("error", (...args) => {
+ logDebug("protocol", `[fable] error event args: ${args.map(a => typeof a + ': ' + JSON.stringify(a)).join(" | ")}`);
+ });
+ }
+
+ // Attach protocol-level error handler
+ state.endpoint.on("error", async (err) => {
+ if (err && /id mismatch/.test(err)) {
+ // this error is recoverable, the plugin will just reload all files.
+ logWarn(
+ "protocol",
+ `error from JSONRPCEndpoint: ${
+ err && err.message ? err.message : err
+ }`
+ );
+ }
+ else {
+ logError("protocol",
+ `unknown error: ${err}, ${err.code}, ${err.context ?? "no context"}`);
+ }
+ });
+
+
if (state.isBuild) {
await projectChanged(
this.addWatchFile.bind(this),
diff --git a/sample-project/App.fsproj b/sample-project/App.fsproj
index c4d42a3..22bbabe 100644
--- a/sample-project/App.fsproj
+++ b/sample-project/App.fsproj
@@ -10,14 +10,14 @@
-
+
-
-
+
+
diff --git a/sample-project/Component.fs b/sample-project/Component.fs
deleted file mode 100644
index 1bcbb08..0000000
--- a/sample-project/Component.fs
+++ /dev/null
@@ -1,17 +0,0 @@
-module Components.Component
-
-open Fable.Core
-open React
-open type React.DSL.DOMProps
-open type React.React
-
-JsInterop.importSideEffects "./app.css"
-
-[]
-let Component () : JSX.Element =
- let count, setCount = useStateByFunction (0)
-
- fragment [] [
- h1 [] [ str "React rocks!" ]
- button [ OnClick (fun _ -> setCount ((+) 1)) ] [ str $"Current state {count}" ]
- ]
diff --git a/sample-project/Component.fsi b/sample-project/Component.fsi
deleted file mode 100644
index bf9a9aa..0000000
--- a/sample-project/Component.fsi
+++ /dev/null
@@ -1,6 +0,0 @@
-module Components.Component
-
-open Fable.Core
-
-[]
-val Component : unit -> JSX.Element
diff --git a/sample-project/Library.fs b/sample-project/Library.fs
index 6266010..1474744 100644
--- a/sample-project/Library.fs
+++ b/sample-project/Library.fs
@@ -4,16 +4,15 @@ open Fable.Core
open Browser.Dom
open Math
open Thoth.Json
+open Fable.React
let r = sum 1 19
let someJsonString =
Encode.object [ "track", Encode.string "Changes" ] |> Encode.toString 4
-let h1Element = document.querySelector "h1"
+let h1Element = document.querySelector "#dyn"
h1Element.textContent <- $"Dynamic Fable text %i{r}! %s{someJsonString}"
-open React
-
-let app = document.querySelector "#app"
-ReactDom.createRoot(app).render (JSX.create Components.Component.Component [])
+let root = Feliz.ReactDOM.createRoot(document.getElementById "app")
+root.render(Components.RootComponent.El())
diff --git a/sample-project/RootComponent.fs b/sample-project/RootComponent.fs
new file mode 100644
index 0000000..d333435
--- /dev/null
+++ b/sample-project/RootComponent.fs
@@ -0,0 +1,19 @@
+module Components.RootComponent
+
+open Feliz
+open Fable.Core
+
+JsInterop.importSideEffects "./app.css"
+
+
+[]
+let El () =
+ let count, setCount = React.useState 0
+ React.fragment [
+ Test.El({| name = "Test" |})
+ Html.h1 "Vite fable plugin rocks!"
+ Html.button [
+ prop.onClick (fun _ -> setCount (count + 1))
+ prop.text $"Current state {count}"
+ ]
+ ]
diff --git a/sample-project/app.css b/sample-project/app.css
index f789872..492bd38 100644
--- a/sample-project/app.css
+++ b/sample-project/app.css
@@ -41,4 +41,9 @@ h1 {
box-shadow: 0px 3px 3px 0px rgba(0,0,0,0.25);
}
}
+}
+
+#test {
+ color: red;
+ background-color: yellow;
}
\ No newline at end of file
diff --git a/sample-project/components/TestComponent.fs b/sample-project/components/TestComponent.fs
new file mode 100644
index 0000000..e8d652f
--- /dev/null
+++ b/sample-project/components/TestComponent.fs
@@ -0,0 +1,27 @@
+module Components.Test
+
+open Feliz
+open Fable.Core
+
+// for editor highlight: alfonsogarciacaro.vscode-template-fsharp-highlight
+[]
+let inline css s = s
+
+[]
+let El (props: {| name: string |}) =
+ let spinCss = css "@keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }"
+ React.fragment [
+ Html.div [
+ prop.style [
+ style.backgroundColor "yellow"
+ style.animationName "spin"
+ style.animationDuration 3
+ style.animationIterationCount.initial
+ style.animationTimingFunction.linear
+ ]
+ prop.children [
+ Html.h1 $"My name is: {props.name}!"
+ ]
+ ]
+ Html.style spinCss
+ ]
diff --git a/sample-project/index.html b/sample-project/index.html
index e42428d..e44495b 100644
--- a/sample-project/index.html
+++ b/sample-project/index.html
@@ -8,7 +8,7 @@
-
Static text
+
Static text