-
Notifications
You must be signed in to change notification settings - Fork 833
Description
In a big Fable project, after a big refactoring to introduce a convenience computation expression, the project started to take much longer to compile. The overhead came from the type checking phase of FSharp.Compiler.Service (it also takes a long time when running dotnet build). The computation expression is a convenience to generate React fragments out of React elements. The CE accepts single React Elements as well as sequences and optional elements. The code is like this:
type ElementBuilder() =
member _.Zero () : ReactElements =
[]
member _.Yield (e: ReactElement) : ReactElements =
[e]
member _.Yield (maybeE: Option<ReactElement>) : ReactElements =
match maybeE with
| None -> []
| Some e -> [e]
member _.Yield (maybeEs: Option<List<ReactElement>>) : ReactElements =
match maybeEs with
| None -> []
| Some es -> es
member _.Yield (es: List<ReactElement>) : ReactElements =
es
member _.Yield (es: seq<ReactElement>) : ReactElements =
Seq.toList es
member _.Yield (ess: list<list<ReactElement>>) : ReactElements =
List.flatten ess
member _.Yield (ess: seq<list<ReactElement>>) : ReactElements =
ess |> Seq.collect id |> Seq.toList
member _.Combine (e: ReactElement, es: ReactElements) : ReactElements =
e :: es
member _.Combine (moreEs: List<ReactElement>, es: ReactElements) : ReactElements =
moreEs @ es
member _.Combine (moreEs: seq<ReactElement>, es: ReactElements) : ReactElements =
(Seq.toList moreEs) @ es
member _.Combine (moreEs: List<List<ReactElement>>, f: unit -> ReactElements) : ReactElements =
(List.flatten moreEs) @ (f())
member _.Combine (e: ReactElement, f: unit -> ReactElements) : ReactElements =
e :: (f())
member _.Combine (moreEs: List<ReactElement>, f: unit -> ReactElements) : ReactElements =
moreEs @ (f())
member _.Combine (moreEs: seq<ReactElement>, f: unit -> ReactElements) : ReactElements =
(Seq.toList moreEs) @ (f())
member _.Combine (moreEs: List<List<ReactElement>>, es: ReactElements) : ReactElements =
(List.flatten moreEs) @ es
member _.Delay (expr: unit -> ReactElements) : unit -> ReactElements = expr
member _.Run (f: unit -> ReactElements) : ReactElement =
let elements = f()
Fable.React.Helpers.fragment [] elements
let element = ElementBuilder()There's a similar CE ElementsBuilder that works the same but returns ReactElement list instead of the fragment.
Users tried changing the CE in different ways, but the only thing that worked was to remove the CE in most of the files. It is still used in some of them but compilation times are mostly back to normal.
The most interesting part is I tried profiling this, and the result is most of the time is spent in the function FSharp.Compiler.NameResolution.ResolveLongIdentAsModuleOrNamespaceThen. This makes me wonder if the CE is not responsible for the slow compilation but instead it causes a problematic name resolution directly. Both ElementBuilder and element are in the same module decorated with AutoOpen.
Any hints to improve the performance of the compilation?
