Fable icon indicating copy to clipboard operation
Fable copied to clipboard

Oxpecker fable plugin not working with fable 4.25.0+

Open Lanayx opened this issue 5 months ago • 17 comments

When I'm trying to run command from any of the Oxpecker.Solid projects after updating from 4.24 to 4.25:

 dotnet fable --noCache

I get the error

Loaded Oxpecker.Solid.SolidComponentAttribute from ..\..\src\Oxpecker.Solid.FablePlugin\bin\Debug\net6.0\Oxpecker.Solid.FablePlugin.dll
Started Fable compilation...
Compiled 12/12: src\Components\TodoList.fs                    
Fable compilation finished in 4006ms

Unhandled exception. System.IO.FileNotFoundException: Could not load file or assembly 'FSharp.Core, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. The system cannot find the file specified.
File name: 'FSharp.Core, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
   at System.ModuleHandle.ResolveType(QCallModule module, Int32 typeToken, IntPtr* typeInstArgs, Int32 typeInstCount, IntPtr* methodInstArgs, Int32 methodInstCount, ObjectHandleOnStack type)
   at System.ModuleHandle.ResolveTypeHandle(Int32 typeToken, RuntimeTypeHandle[] typeInstantiationContext, RuntimeTypeHandle[] methodInstantiationContext)
   at System.Reflection.RuntimeModule.ResolveType(Int32 metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
   at System.Reflection.CustomAttribute.FilterCustomAttributeRecord(MetadataToken caCtorToken, MetadataImport& scope, RuntimeModule decoratedModule, MetadataToken decoratedToken, RuntimeType attributeFilterType, Boolean mustBeInheritable, ListBuilder`1& derivedAttributes, RuntimeType& attributeType, IRuntimeMethodInfo& ctorWithParameters, Boolean& isVarArg)
   at System.Reflection.CustomAttribute.IsCustomAttributeDefined(RuntimeModule decoratedModule, Int32 decoratedMetadataToken, RuntimeType attributeFilterType, Int32 attributeCtorToken, Boolean mustBeInheritable)
   at System.Reflection.CustomAttribute.IsDefined(RuntimeType type, RuntimeType caType, Boolean inherit)
   at System.RuntimeType.IsDefined(Type attributeType, Boolean inherit)
   at System.Diagnostics.StackTrace.ToString(TraceFormat traceFormat, StringBuilder sb)
   at System.Diagnostics.StackTrace.ToString(TraceFormat traceFormat)
   at System.Exception.get_StackTrace()
   at [email protected](FSharpResult`2 _arg3) in /home/mmangel/Workspaces/Github/fable-compiler/Fable/fable4/src/Fable.Cli/Main.fs:line 1128
   at [email protected](Tuple`2 _arg2) in /home/mmangel/Workspaces/Github/fable-compiler/Fable/fable4/src/Fable.Cli/Main.fs:line 1116
   at Microsoft.FSharp.Control.AsyncPrimitives.CallThenInvokeNoHijackCheck[a,b](AsyncActivation`1 ctxt, b result1, FSharpFunc`2 userCode) in /home/dev/Projects/fsharp/src/FSharp.Core/async.fs:line 528
   at Microsoft.FSharp.Control.AsyncPrimitives.PostOrQueueWithTrampoline@932.Invoke(Unit unitVar0) in /home/dev/Projects/fsharp/src/FSharp.Core/async.fs:line 932
   at Microsoft.FSharp.Control.Trampoline.Execute(FSharpFunc`2 firstAction) in /home/dev/Projects/fsharp/src/FSharp.Core/async.fs:line 112
--- End of stack trace from previous location ---
   at Microsoft.FSharp.Control.AsyncResult`1.Commit() in /home/dev/Projects/fsharp/src/FSharp.Core/async.fs:line 454
   at Microsoft.FSharp.Control.AsyncPrimitives.QueueAsyncAndWaitForResultSynchronously[a](CancellationToken token, FSharpAsync`1 computation, FSharpOption`1 timeout) in /home/dev/Projects/fsharp/src/FSharp.Core/async.fs:line 1139
   at Microsoft.FSharp.Control.AsyncPrimitives.RunSynchronously[T](CancellationToken cancellationToken, FSharpAsync`1 computation, FSharpOption`1 timeout) in /home/dev/Projects/fsharp/src/FSharp.Core/async.fs:line 1166
   at Microsoft.FSharp.Control.FSharpAsync.RunSynchronously[T](FSharpAsync`1 computation, FSharpOption`1 timeout, FSharpOption`1 cancellationToken) in /home/dev/Projects/fsharp/src/FSharp.Core/async.fs:line 1515
   at [email protected](Unit _arg5) in /home/mmangel/Workspaces/Github/fable-compiler/Fable/fable4/src/Fable.Cli/Entry.fs:line 391
   at [email protected](Tuple`2 _arg2) in /home/mmangel/Workspaces/Github/fable-compiler/Fable/fable4/src/Fable.Cli/Entry.fs:line 523
   at Fable.Cli.Entry.main(String[] argv) in /home/mmangel/Workspaces/Github/fable-compiler/Fable/fable4/src/Fable.Cli/Entry.fs:line 515

To reproduce - download Oxpecker repository

  1. Go to this folder https://github.com/Lanayx/Oxpecker/tree/main/examples/EmptySolid
  2. Run dotnet tool update fable
  3. Observe fable build fails

Basically just reiterating issue https://github.com/Lanayx/Oxpecker/issues/77

Lanayx avatar Jul 12 '25 07:07 Lanayx

I don't know where the problem can be coming from because the only impactful commits between the 2 version is:

https://github.com/fable-compiler/Fable/commit/ae2463bfa37a7a79d0ca90198eda619af7eacc6e

MangelMaxime avatar Jul 12 '25 14:07 MangelMaxime

Some crazy thoughts:

  1. Stacktrace starts from FSharpAsync.RunSynchronously which was removed in 4.25 that might or might not be an issue
  2. Next location has System.Exception.get_StackTrace() in the middle, so it might be that some exception occured and then another exception was thrown during stacktrace collection that overrode original one.
  3. Global json change is also suspicious

Lanayx avatar Jul 12 '25 15:07 Lanayx

We can eliminate the first one in theory because

  1. Stacktrace starts from FSharpAsync.RunSynchronously which was removed in 4.25 that might or might not be an issue

The changes regarding RunSynchronously are Fable related, if you use RunSynchronously in your F# code then at compilation Fable is going to generate an error at compilation instead of generating something like Async.runSynchronously in your JavaScript which would fails at runtime

Here what is failing is the Fable compiler running in .NET not its compilation result

MangelMaxime avatar Jul 12 '25 20:07 MangelMaxime

It seems that Fable 4.25.0 may have .NET 9 compatibility issues. It ships with FSharp.Core 8.0.200-dev but .NET 9 expects FSharp.Core 9.0.0.0, causing assembly loading failures.

The fix already exists in main branch (commit 418fb1fdc). Recommend fix is e.g. releasing Fable 4.26.0 with the F# 9.0 FCS updates backported.

I have tested this locally and can reproduce the build error with 4.25.0. The error is gone when cherry picking 418fb1fdc and making a new build.

What I did to test:

# In Fable
git checkout -b release/4.26.0 4.25.0
git cherry-pick 418fb1fdc
# Resolve conflicts (target framework, version)

dotnet pack src/Fable.Cli/Fable.Cli.fsproj -c Release -o ./local-packages
dotnet tool uninstall -g fable
dotnet tool install -g fable --version 4.25.0-fixed --add-source ./local-packages

# In Oxpecker
fable watch --exclude Oxpecker.Solid.FablePlugin --noCache --extension .jsx --run vite

# This works on my machine. Doing the same without the cherry-pick, fails

dbrattli avatar Jul 12 '25 22:07 dbrattli

Thanks for the investigation @dbrattli

I am working on making a PR to fix the issue, this is a bit tricky because I also need to revert some improvements which were also made in that commit for Fable 5 only. But that's should be do-able :)

MangelMaxime avatar Jul 13 '25 15:07 MangelMaxime

Tips: In case you want to use a local version of Fable you can also use ./build.sh package to a create a local package. It will give you a package that you can install on top of any existing Fable version no need for manual uninstall (because the version will always be higher)

Local packages created.

Use the following commands to install them:

- Fable.Cli: dotnet tool update fable --version 4.999.0-local-build-20250713-18613 --add-source /home/mmangel/Workspaces/Github/fable-compiler/Fable/fable4/temp/packages
- Fable.Core: dotnet add package Fable.Core --version 4.999.0-local-build-20250713-18613 --source /home/mmangel/Workspaces/Github/fable-compiler/Fable/fable4/temp/packages

MangelMaxime avatar Jul 13 '25 16:07 MangelMaxime

@Lanayx Fable 4.26.0 should fix the issue

MangelMaxime avatar Jul 14 '25 12:07 MangelMaxime

@MangelMaxime Unfortunately, is still doesn't work with Oxpecker.Solid plugin

Could not scan C:/Users/DavidFaivre/.nuget/packages/oxpecker.solid.fableplugin/0.7.0/lib/net6.0/Oxpecker.Solid.FablePlugin.dll for Fable plugins, skipping this assembly. Original error: The exception has been reported. This intern
al exception should now be caught at an error recovery point on the stack. Original message: The type 'AssemblyCompanyAttribute' is required here and is unavailable. You must add a reference to assembly 'System.Runtime, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.)

Lanayx avatar Jul 14 '25 17:07 Lanayx

@Lanayx Does it work with the EmptySolid from Oxpecker repo directly?

If yes, could it be that a new release of the plugin is needed to update its dependencies ?

MangelMaxime avatar Jul 14 '25 18:07 MangelMaxime

@MangelMaxime I reproduced the issue in clean folder downloaded from github as zip file, however didn't reproduce in a repo folder, which is pretty weird. I'll try to dig deeper tomorrow morning.

Lanayx avatar Jul 14 '25 19:07 Lanayx

@MangelMaxime Just verified several times in clean folders that EmptySolid doesn't work neither with plugin built from sources (develop branch) nor downloaded from nuget (main branch) because of the aforementioned error. In the repo is didn't reproduce first, but after git clean -xfd it reproduced there as well.

Lanayx avatar Jul 15 '25 06:07 Lanayx

Follow up of #4179, I decided to unlist Fable 4.26.0 because like @ncave pointed Fable 5 is the version that is made to work properly with F# 9 and .NET 9.0.

If Fable 4.24.0 works, it should means that something in #4106 broke it.

Outside of the changes in #4106 something that also changed compared to others release.

Is that instead of creating the release from the DevContainer because I was on a Mac, I am now using Linux directly on my machine which is probably why I needed to update the global.json as I had a different version of .NET installed on my machine.

I will see if using the dev container to create a local package fix the issue reported

MangelMaxime avatar Jul 16 '25 14:07 MangelMaxime

@MangelMaxime I've decided to try Fable 5 with .NET 10 and it still fails for me with a similar error

Fable compilation finished in 3740ms                                                                                                                                                                       
                                                                                                                                                                                                           
Unhandled exception. System.IO.FileNotFoundException: Could not load file or assembly 'FSharp.Core, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. The system cannot find the file specified.                                                                                                                                                                                                   
File name: 'FSharp.Core, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'                                                                                                               
   at System.ModuleHandle.ResolveType(QCallModule module, Int32 typeToken, IntPtr* typeInstArgs, Int32 typeInstCount, IntPtr* methodInstArgs, Int32 methodInstCount, ObjectHandleOnStack type)             
   at System.ModuleHandle.ResolveTypeHandle(Int32 typeToken, RuntimeTypeHandle[] typeInstantiationContext, RuntimeTypeHandle[] methodInstantiationContext)                                                 
   at System.Reflection.RuntimeModule.ResolveType(Int32 metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)                                                                         
   at System.Reflection.CustomAttribute.FilterCustomAttributeRecord(MetadataToken caCtorToken, MetadataImport& scope, RuntimeModule decoratedModule, MetadataToken decoratedToken, RuntimeType attributeFilterType, Boolean mustBeInheritable, ListBuilder`1& derivedAttributes, RuntimeType& attributeType, IRuntimeMethodInfo& ctorWithParameters, Boolean& isVarArg)                                               
   at System.Reflection.CustomAttribute.IsCustomAttributeDefined(RuntimeModule decoratedModule, Int32 decoratedMetadataToken, RuntimeType attributeFilterType, Int32 attributeCtorToken, Boolean mustBeInheritable)                                                                                                                                                                                                   
   at System.Reflection.CustomAttribute.IsDefined(RuntimeType type, RuntimeType caType, Boolean inherit)                                                                                                   
   at System.Diagnostics.StackTrace.ToString(TraceFormat traceFormat, StringBuilder sb)                                                                                                                    
   at System.Diagnostics.StackTrace.ToString(TraceFormat traceFormat)                                                                                                                                      
   at System.Exception.get_StackTrace()                                                                                                                                                                    
   at [email protected](FSharpResult`2 _arg3) in /home/mmangel/Workspaces/Github/fable-compiler/Fable/main/src/Fable.Cli/Main.fs:line 1139                                     
   at [email protected](Tuple`2 _arg2) in /home/mmangel/Workspaces/Github/fable-compiler/Fable/main/src/Fable.Cli/Main.fs:line 1127                                            
   at Microsoft.FSharp.Control.AsyncPrimitives.CallThenInvokeNoHijackCheck[a,b](AsyncActivation`1 ctxt, b result1, FSharpFunc`2 userCode) in /home/dev/Projects/fsharp/src/FSharp.Core/async.fs:line 528   
   at Microsoft.FSharp.Control.AsyncPrimitives.PostOrQueueWithTrampoline@932.Invoke(Unit unitVar0) in /home/dev/Projects/fsharp/src/FSharp.Core/async.fs:line 932                                          
   at Microsoft.FSharp.Control.Trampoline.Execute(FSharpFunc`2 firstAction) in /home/dev/Projects/fsharp/src/FSharp.Core/async.fs:line 112                                                                 
--- End of stack trace from previous location ---                                                                                                                                                          
   at Microsoft.FSharp.Control.AsyncResult`1.Commit() in /home/dev/Projects/fsharp/src/FSharp.Core/async.fs:line 454                                                                                       
   at Microsoft.FSharp.Control.AsyncPrimitives.QueueAsyncAndWaitForResultSynchronously[a](CancellationToken token, FSharpAsync`1 computation, FSharpOption`1 timeout) in /home/dev/Projects/fsharp/src/FSharp.Core/async.fs:line 1139                                                                                                                                                                                 
   at Microsoft.FSharp.Control.AsyncPrimitives.RunSynchronously[T](CancellationToken cancellationToken, FSharpAsync`1 computation, FSharpOption`1 timeout) in /home/dev/Projects/fsharp/src/FSharp.Core/async.fs:line 1166                                                                                                                                                                                            
   at Microsoft.FSharp.Control.FSharpAsync.RunSynchronously[T](FSharpAsync`1 computation, FSharpOption`1 timeout, FSharpOption`1 cancellationToken) in /home/dev/Projects/fsharp/src/FSharp.Core/async.fs:line 1515                                                                                                                                                                                                   
   at [email protected](Unit unitVar0) in /home/mmangel/Workspaces/Github/fable-compiler/Fable/main/src/Fable.Cli/Entry.fs:line 391                                       
   at [email protected](Unit _arg5) in /home/mmangel/Workspaces/Github/fable-compiler/Fable/main/src/Fable.Cli/Entry.fs:line 398                                                     
   at [email protected](Tuple`2 _arg2) in /home/mmangel/Workspaces/Github/fable-compiler/Fable/main/src/Fable.Cli/Entry.fs:line 540                                                        
   at Fable.Cli.Entry.main(String[] argv) in /home/mmangel/Workspaces/Github/fable-compiler/Fable/main/src/Fable.Cli/Entry.fs:line 532       

But this gave me the idea. It looks like the issue lies in combination of SDK and fable tool:

.NET SDK 8:

Fable 4.24 works Fable 4.25+ works Fable 5 works

.NET SDK 9:

Fable 4.24 works Fable 4.25+ errors! Fable 5 works

.NET SDK 10:

Fable 4.24 errors! Fable 4.25-4.27 errors! Fable 4.28 hangs! (this is the worst case) Fable 5 errors!

Hope this helps to understand the issue! I was running my tests on even simpler project by executing dotnet fable --noCache --exclude Oxpecker.Solid.FablePlugin --extension .jsx

Lanayx avatar Nov 30 '25 20:11 Lanayx

@Freymaurer Did you see a similar issue when working on Feliz plugins ?

MangelMaxime avatar Dec 01 '25 15:12 MangelMaxime

Hey! Feliz is still set to .net8.0 so i can confirm that fable5 works with .net8.0.

Freymaurer avatar Dec 01 '25 15:12 Freymaurer

I got the Empty Solid example working with the latest net10 and fable 5 .

<PackageReference Include="Oxpecker.Solid" Version="0.8.1" /> global.json:

{ 
    "sdk": {
        "version": "10.0.100",
        "rollForward": "latestMinor"
    }
}

dotnet-tools.json:

fable 4.24: ✅ fable 4.25: ❌ FileNotFoundException: Could not load file or assembly 'FSharp.Core, Version=9.0.0.0 fable 4.26: ✅ fable 4.27: ❌ FileNotFoundException: Could not load file or assembly 'FSharp.Core, Version=9.0.0.0 fable 4.28: ❌ just hangs after build succeded in 0.6s, Vite doesn't start. . . . fable 5.0.0-alpha.16: ✅ fable 5.0.0-alpha.17: ✅ fable 5.0.0-alpha.18: ✅ fable 5.0.0-alpha.19: ✅

@Lanayx does it work for you too with 5.0.0-alpha.19 ?

goswinr avatar Dec 05 '25 10:12 goswinr

@goswinr it does work with 5.0.0-alpha.19 and 5.0.0-alpha.18! It doesn't work with 5.0.0-alpha.17 and below. And actually I was hoping for it to work because of this change. So, it looks like there is an implicit dependency on the FSharp.Core version bundled in Fable.Cli - it should match the SDK version the end user has installed.

Lanayx avatar Dec 05 '25 18:12 Lanayx