The question of code-splitting in Elm comes up fairly routinely.
The apparent low-hanging-fruit of code-splitting with Elm's pure/immutable philosophy has led me to explore this a few times with my compiler work on Lamdera.
Here are some of the challenges I've found:
It's a little trickier than it looks because Elm's DCE is actually not DCE (dead code elimination) at all, it's LCI (live code inclusion).
At the JS output stage, the compiler recursively pulls in defs and subdefs for only the things that are actually part of the project as it writes out everything used by
While crying "this is not DCE" might seem a little pedantic, it has a practical impact on code-splitting for which saying "DCE" wouldn't make any sense, so I'll call it "LCI" for the purpose of explaining further.
Elm's LCI has two practical impacts:
The symbol obfuscation algorithm, which replaces things unnecessary for runtime, like
myMeaningfulFunctionName with something like
aP (starting at
a and going upwards to
ZZZ), happens alongside the live-code-including output process.
Because functions can depend on other functions, knowing the obfuscated name of those functions, especially the commonly re-used ones from core, is important – otherwise, how do you know what to call?
Thus, due to the prior point, if you have a code-split segment, you now can't re-use that with any other project without also retaining some knowledge of what the symbol obfuscation mapping was. Any sub-segments cannot do so either, all the way down.
So each code split segment would have a unique "fingerprint" of obfuscation making it's "just re-use it" utility problematic.
Perhaps with some effort these problems could be overcome (I've been thinking about whether it's possible to have some sort of more stable obfuscation algorithm), but this is what prevents code-splitting being low-hanging fruit as things stand today, AFAIK!