I have a type provider (as do others) for use with Fable. It erases to strings, and works great for the most part.
However, there is one problem: during the Fable compilation process, the type provider's ResolutionFolder configuration property, which is supposed to be the .fsproj directory, does not get set.
Type providers are somehow instantiated with a TypeProviderConfig object like so: type MyTypeProvider (config:TypeProviderConfig) as this = ...
When compiled by Fable (or F# compiler services, or however they are interacting), the config object has the other properties set but not the ResolutionFolder. Consequently, at compilation time we have no way to find source data files with paths relative to project root, we can only find absolute paths.
Here is some debug logging from my type provider to illustrate this further.
At design time in VS Code it sets the ResolutionFolder:
Creating TypeProviderForNamespaces Zanaptak.TypedCssClasses.TypeProvider+CssClassesTypeProvider [0]
TypeProviderConfig.IsHostedExecution = false
TypeProviderConfig.IsInvalidationSupported = true
TypeProviderConfig.TemporaryFolder = C:\Users\zaphod\AppData\Local\Temp\
TypeProviderConfig.ResolutionFolder = c:\src\testTypedCss\src
TypeProviderConfig.RuntimeAssembly = c:\src\TypedCssClasses\src\bin\Debug\netstandard2.0\Zanaptak.TypedCssClasses.dll
TypeProviderConfig.ReferencedAssemblies count = 123
C:\Users\zaphod\.nuget\packages\fsharp.core\4.6.2\lib\netstandard1.6\FSharp.Core.dll
C:\Users\zaphod\.nuget\packages\netstandard.library\2.0.3\build\netstandard2.0\ref\Microsoft.Win32.Primitives.dll
C:\Users\zaphod\.nuget\packages\netstandard.library\2.0.3\build\netstandard2.0\ref\mscorlib.dll
C:\Users\zaphod\.nuget\packages\netstandard.library\2.0.3\build\netstandard2.0\ref\netstandard.dll
C:\Users\zaphod\.nuget\packages\netstandard.library\2.0.3\build\netstandard2.0\ref\System.AppContext.dll
...
Environment.CommandLine = C:\Users\zaphod\.vscode\extensions\ionide.ionide-fsharp-4.0.6\bin_netcore\fsautocomplete.backgroundservices.dll 23332
Environment.CurrentDirectory = c:\src\testTypedCss
If I build with dotnet build .\src\App.fsproj, it sets the ResolutionFolder (also changing current working dir):
Creating TypeProviderForNamespaces Zanaptak.TypedCssClasses.TypeProvider+CssClassesTypeProvider [0]
TypeProviderConfig.IsHostedExecution = false
TypeProviderConfig.IsInvalidationSupported = false
TypeProviderConfig.TemporaryFolder = C:\Users\zaphod\AppData\Local\Temp\
TypeProviderConfig.ResolutionFolder = C:\src\testTypedCss\src
TypeProviderConfig.RuntimeAssembly = C:\src\TypedCssClasses\src\bin\Debug\netstandard2.0\Zanaptak.TypedCssClasses.dll
TypeProviderConfig.ReferencedAssemblies count = 123
C:\Users\zaphod\.nuget\packages\netstandard.library\2.0.3\build\netstandard2.0\ref\netstandard.dll
C:\Users\zaphod\.nuget\packages\fsharp.core\4.6.2\lib\netstandard1.6\FSharp.Core.dll
C:\Users\zaphod\.nuget\packages\netstandard.library\2.0.3\build\netstandard2.0\ref\Microsoft.Win32.Primitives.dll
C:\Users\zaphod\.nuget\packages\netstandard.library\2.0.3\build\netstandard2.0\ref\mscorlib.dll
C:\Users\zaphod\.nuget\packages\netstandard.library\2.0.3\build\netstandard2.0\ref\System.AppContext.dll
...
Environment.CommandLine = "C:\Program Files\dotnet\sdk\3.0.100-preview5-011568\FSharp\fsc.exe" @C:\Users\zaphod\AppData\Local\Temp\tmp748d72f3b53a4861ad2f55279ffa7343.rsp
Environment.CurrentDirectory = C:\src\testTypedCss\src
If I build with webpack which runs Fable.Cli.dll, the folder is empty string (not null, in case it matters):
Creating TypeProviderForNamespaces Zanaptak.TypedCssClasses.TypeProvider+CssClassesTypeProvider [0]
TypeProviderConfig.IsHostedExecution = false
TypeProviderConfig.IsInvalidationSupported = false
TypeProviderConfig.TemporaryFolder = C:\Users\zaphod\AppData\Local\Temp\
TypeProviderConfig.ResolutionFolder is empty string
TypeProviderConfig.RuntimeAssembly = C:/src/TypedCssClasses/src/bin/Debug/netstandard2.0/Zanaptak.TypedCssClasses.dll
TypeProviderConfig.ReferencedAssemblies count = 120
C:/Users/zaphod/.nuget/packages/netstandard.library/2.0.3/build/netstandard2.0/ref/netstandard.dll
C:/Users/zaphod/.nuget/packages/fsharp.core/4.6.2/lib/netstandard1.6/FSharp.Core.dll
C:/Users/zaphod/.nuget/packages/netstandard.library/2.0.3/build/netstandard2.0/ref/System.Xml.XPath.XDocument.dll
C:/Users/zaphod/.nuget/packages/netstandard.library/2.0.3/build/netstandard2.0/ref/System.Xml.XPath.dll
C:/Users/zaphod/.nuget/packages/netstandard.library/2.0.3/build/netstandard2.0/ref/System.Xml.XmlSerializer.dll
...
Environment.CommandLine = C:\src\testTypedCss\node_modules\fable-compiler\bin\fable-cli\Fable.Cli.dll start-stdin --silent undefined
Environment.CurrentDirectory = C:\src\testTypedCss
I started to poke around the Fable codebase but quickly got lost so I'm asking here. Do you think it might be possible to figure out how to set this property correctly? I can also provide a test project if necessary if someone is willing and able to dig further.
Interesting, didn't know about that property. Fable contains almost no code specific for type providers, as they're basically resolved by the FSharp.Compiler.Service. If it works with VS Code it should work with Fable too. Maybe we're using an older version but I cannot see any recent fix related to this in dotnet/fsharp repo.
Maybe it has do with the options we're passing to the F# compiler?
@zanaptak Yes, a test project would help, if you have one.
@ncave @alfonsogarciacaro I have added a test project, clone my repo and check the TestWithFable instructions.
@zanaptak @alfonsogarciacaro
Looks like the ResolutionFolder property is set from the TcConfigBuilder.implicitIncludeDir property. Currently we're not setting this property, and the initial value is empty string.
Looks like FSI sets it to the current folder:
tcConfigB.implicitIncludeDir <- Directory.GetCurrentDirectory()
but FCS sets it to the project folder:
tcConfigB.implicitIncludeDir <- projectOptions.ProjectDirectory
Let me know which one you think is better, current dir or project path, and I'll make the change.
Can Fable run a standalone fsx script outside of a project? If so, then possibly it should be conditional based on script vs. project context.
But at least for a structured project it should be the project dir like FCS. That will be consistent with:
dotnet build behavior (if I have a .NET Giraffe project and a Fable project, a TP in either should resolve paths consistently as project-relative)Accessing Project-Local or Script-Local Resources
Each instance of a type provider can be given a TypeProviderConfig value during construction. This value contains the "resolution folder" for the provider (that is, the project folder for the compilation or the directory that contains a script), the list of referenced assemblies, and other information.
According to above, it is understood that project context and script context receive different configuration, with script context being the script directory. I have confirmed this by running dotnet fsi dir1/dir2/file.fsx, and my TP in file.fsx received the dir1/dir2 path, not the original current directory of the FSI launch. I suspect your example of FSI using current directory is either launching without a script, or if with a script, then it has probably previously chdir'd to the script dir.
In summary:
Works great after the update, thanks. 馃憤
Most helpful comment
Can Fable run a standalone fsx script outside of a project? If so, then possibly it should be conditional based on script vs. project context.
But at least for a structured project it should be the project dir like FCS. That will be consistent with:
dotnet buildbehavior (if I have a .NET Giraffe project and a Fable project, a TP in either should resolve paths consistently as project-relative)According to above, it is understood that project context and script context receive different configuration, with script context being the script directory. I have confirmed this by running
dotnet fsi dir1/dir2/file.fsx, and my TP in file.fsx received the dir1/dir2 path, not the original current directory of the FSI launch. I suspect your example of FSI using current directory is either launching without a script, or if with a script, then it has probably previously chdir'd to the script dir.In summary: