fable-compiler / Fable

F# to JavaScript, TypeScript, Python, Rust and Dart Compiler
http://fable.io/
MIT License
2.93k stars 301 forks source link

Question about compile time file ordering of dependent fable nuget packages #3833

Open ThisFunctionalTom opened 5 months ago

ThisFunctionalTom commented 5 months ago

Description

I have a fable compatible nuget packages Constants and Library where Library depends on Constants. When I add package reference to Library in our SPA app and compile it with fable I get F# compiler error while compiling sources of Library that the namespace of Constants is not known.

I executed fable compiler with --verbose flag and have seen that the source files of Library come before the source files of Constants. Both of the package sources can be found in fable_modules so I guess the dependencies resolved correctly.

Can I somehow influence the compile time ordering of files from fable_modules? Am I doing something wrong? How does the Fable order the files from referenced fable nuget packages?

Expected and actual results

I would expect the fable compiler to respect the nuget package dependencies order and sort the files when compiling accordingly. In my case first all the files from Constants should be compiled before the files of Library and at the and the files from the SPA app.

Related information

ThisFunctionalTom commented 5 months ago

I just found that there is a project_cracked.json file. In this file the files are in the correct order but in the --verbose log the files are in different order.

MangelMaxime commented 5 months ago

Hello @ThisFunctionalTom,

Are you trying to consume the packages via NuGet or using ProjectReference.

If this is the former, you need to make sure to release a Fable compatible package. The main things being you need to include the F# source files in a fable folder.

In order to do so, you can use the all new shiny Fable.Package.SDK which automate a lot of things for you and guide you.

Or you can do it the manual way by using Fable documentation (in the future it will be updated to use Fable.Package.SDK as it more friendly to use).

ThisFunctionalTom commented 5 months ago

Hi Maxime,

Yes both nuget packages Constants and Library are fable compatible with sources in fable folder. I also find this sources in fable_modules of the SPA app. As I said, I guess it is the order of the files on the command line of F# compiler that is wrong. Here the files of the Constants come after the files of the Library and F# compiler fails because in Library we use Constants.

What's strange is that in the project_cracked.json file the order of the files is correct.

Maybe if you could navigate me where the F# compiler is called in Fable I could maybe find the error myself or maybe find what am I doing wrong.

I could try to reproduce it with some small projects but I am not sure if it will happen again. I would first like to find out how the files on the command line of F# compiler are sorted.

MangelMaxime commented 5 months ago

Could try compiling using --test:MSBuildCracker flag ? This is using MSBuild to resolve the dependencies instead of Buildanlyzer.

Resolution of the project is done by https://github.com/fable-compiler/Fable/blob/main/src/Fable.Cli/BuildalyzerCrackerResolver.fs

Or the new when the flag --test:MSBuildCracker is set https://github.com/fable-compiler/Fable/blob/main/src/Fable.Compiler/MSBuildCrackerResolver.fs

The full projects options should be build here: https://github.com/fable-compiler/Fable/blob/1a1854acfff1cc72dabdda3e946d007e93948755/src/Fable.Compiler/ProjectCracker.fs#L809C5-L809C23

ncave commented 5 months ago

Perhaps a repro can help figure out what's happening.

Here the the source file logic for Fable-compatible nuget packages. But that doesn't use MSBuild, just parses project XML, so that might explain the difference in package order in project_cracked.json.

My guess is that the dependency order provided by MSBuild might be different than what you expect from just looking at the project. As @MangelMaxime suggested, try using --test:MSBuildCracker to see if that changes anything.

Also, is the package dependency order that you get when compiling with .NET F# (using --verbose) same, or different?

ThisFunctionalTom commented 5 months ago

I just debuged the Fable Compiler while compiling our SPA app and I think I found the problem.

I think the problem is in sortFablePackages function because it compares package dependencies case sensitive and does not sort dependencies if the casing is different in fsproj file and in nuspec files of fable packages.

match List.tryFindIndexBack (fun (x: FablePackage) -> 
    pkg.Dependencies.Contains(x.Id)) acc with
...

Instead it should probably be

match List.tryFindIndexBack (fun (x: FablePackage) -> 
    pkg.Dependencies |> Set.exists (fun dep -> dep.ToLowerInvariant() = x.Id.ToLowerInvariant())) acc with

I will try to make a pull request if it is OK.

MangelMaxime commented 5 months ago

I think it makes sense, because in the fsproj we can use Fable.Core or fable.core for the name of the dependency and it resolve to the same package. At least, it doesn't seems to break.

ThisFunctionalTom commented 5 months ago

I think I fixed it. The pull request link is above.