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