The way Unity solves this is by creating their own C# dialect, compiler and minimal runtime (without GC etc). Sort of a brute-force approach, but until the standard .NET ecosystem solves the bloat problem it would have been better to build on a different language ecosystem.
To put it another way: Adobe can ship Photoshop using Emscripten, and big companies can probably eventually ship their internal C# business apps using Uno or Blazor, but you're not going to ship either of those using Unity's stock approach without building out all of the platform APIs they stripped out and adding back runtime features that were removed. The decisions they made were perfect for games, but people building general-purpose platforms can't cut all those corners.
However, they do not guarantee that the APIs in the .Net framework will work on all platforms, as some of them are still Windows specific.
https://docs.unity3d.com/2019.1/Documentation/Manual/dotnetP...
They do take the IL generated by Rosyln and convert it to executable code using their own custom transpiler.
I think this is a fine tradeoff for certain contexts and usages, but I don't think the general usecase for WASM is to build general web applications in C# and ship all of the CLR for things like gmail.
If anything, the BCL or common libraries are too "static", where some pieces of code reference statically all features available.
One great example is JSON.NET: That library has basically one big method that type-checks all possible inputs, making unconditionally reachable every dependency for all features of the library. In this case, JSON.NET pulls the XML reader, DataSets, and many huge libraries that are generally not needed. In Uno, we generally don't AOT those libraries and use the interpreter for that (otherwise the payload would explode).
Such libraries need to be changed to be configurable, and dynamically enable dependencies as per the user's needs.
Conversely, many pieces of code are excluded by configuration because of reflection uses, but the .NET team is improving that scenario (https://devblogs.microsoft.com/dotnet/performance-improvemen...) with attributes to tag dependencies and hint the linker.
Interestingly plain C libraries often do this better than C++ libraries (e.g. too generous use of virtual-method-interfaces in C++ libraries, or making heavy use of C++ stdlib containers when simple C-style arrays would do as well).
The Unity engine also suffered from a similar problem: If you used a simple physics feature like a stabbing collision check somewhere in your code, the entire physics module was pulled in, even though the code needed for stabbing checks is only a few percent of that physics module.
This is why I'm a bit sceptical that improvements in the .NET "machinery" alone can solve this problem. You also need to restrict language features and select the right dependencies. This is a general problem, not just web-specific, it's just that reducing the output binary size typically isn't a high-priority problem outside the web.