In .NET 8 we plan to add a new project template, Blazor Web Application, that coโฆvers all combinations of server-hosted projects (traditional Blazor Server apps, Blazor WebAssembly hosted, and the new unified architecture that allows use of Server, WebAssembly, and SSR in a single project). It will work by multitargeting over `net8.0` and `net8.0-browser`.
However we still have to decide on the conventions for how such a project should be structured. The biggest question is **what determines which files/references are included in which compilation**?
### Goals
* **Make it obvious what ends up in which compilation.** In particular, avoid unintended inclusion in the WebAssembly compilation, because (1) it bloats the app size, and (2) in the worst case, a developer might include sensitive business logic/secrets without realising it.
* **Stay compatible with existing ASP.NET Core conventions**. We don't want to break all existing docs/tutorials/etc for MVC, gRPC, auth, EF, and so on. Nor do we want people upgrading an existing nontrivial ASP.NET Core app to have to make a lot of changes to their existing code.
* **Maximize clarity; minimize the concept count**. Try to make the structure intuitively obvious and pleasant for people who don't know why all this stuff works as it does. In particular, be very careful about terminology given the amount of ambiguity (e.g., client vs browser vs WebAssembly all might seem to mean the same thing here, but all of them also seem wrong in some cases).
* **Work without tying people to particular project structures**. We're not designing just for the default templates; we're looking for a system that will make sense even when people change their project structures a lot, or are upgrading existing real-world projects that involve a lot of unrelated concepts they might not even fully understand.
### Possible designs
I think there are ~~two~~ three main approaches to pick from, as depicted here (click to expand):

#### Benefits of approach A ("single project, exclude by default")
* Does not break existing ASP.NET Core server apps. Upgrading is easy, because nothing goes into your WebAssembly compilation by default, so it's not going to give you hundreds of build errors and force you to rename files or add `#if` or special exclusions to your `.csproj`.
* As you add more components/classes to the project, you're forced to make an explicit choice if you want to make it available to WebAssembly. There is minimal risk of accidental disclosure, and the trimmed wasm bundle will be as minimal as possible.
Its main drawbacks are that the concept of `ClientShared` is nonobvious (and I spent ages coming up with that name, as almost everything else fails to communicate the idea that you're *making stuff available to both client and server whereas otherwise it's server only* - better name suggestions are welcome, but don't just say "client" or similar).
#### Benefits of approach B ("single project, include by default")
* Most similar to MAUI
* We could even have `Platforms/Browser` but that's largely pointless since for almost everything you include in browser, you also want it to be available in server (otherwise, for example, you can't even route to `@page` components that aren't in the server build and would get 404s).
* We could have `Platforms/Server` but again that's quite bad because people don't want to restructure their ASP.NET Core projects to move everything for the server into that subdir.
* Looks simpler, because there are fewer folders
* More obvious that what determines each component's render mode is `@rendermode` and not which folder it is in
Its main drawback is that it is incompatible with typical ASP.NET Core projects, at least until developers manually exclude everything that can't work in WebAssembly, and then as you work on the project you have to keep excluding more things or unintentionally include them in the WebAssembly build. In the above example, *all* the `.razor` components end up in the wasm build pointlessly, increasing its size just because it's painful to keep excluding things.
#### Benefits of approach C ("two projects")
* No need for multitargeting
* No need for any new naming or folder conventions that include/exclude things
* No need for new rules about annotating project/package references with `ClientOnly`/`ServerOnly`/`ServerAndClient`/etc
* Potentially an easier approach for people adding WebAssembly support to an existing ASP.NET Core server app (the `.Client` project could be a template in itself)
Its main drawback is that it gives up the multitargeting-based way to call server-only code from components that are shared with WebAssembly. For example, with approaches A and B, you could use `#if SERVER` inside a component to have a block of code that calls `AppDbContext` directly, with an `#else` block that runs on WebAssembly and maybe does an `HttpClient` call. That wouldn't work with option C because the `.Client` project couldn't reference types that live in the server project (there's no project reference in that direction). It means developers have to go back to traditional interfaces+DI, e.g. `IMyRepository` with different implementations for server and WebAssembly, since they can't just use `#if SERVER` etc.
In terms of whether the two-project system is harder to understand for total .NET newcomers, I honestly don't know. An extra project is an extra concept, however multitargeting and filename conventions are probably even thornier extra concepts still.
### Proposal
As you can probably tell, between options A and B I'm currently leaning towards option A, however I'm still undecided on a preference between A and C. In the long term, having a single project will probably be an essential element of https://github.com/dotnet/aspnetcore/issues/46400, which may be a major feature for Blazor in .NET 9. So I suspect that's a likely direction eventually, however it doesn't mean that developers necessarily benefit in .NET 8 - there's an argument for keeping a simpler project system in .NET 8 and giving the single-project-multitargeting-conventions system more bake time. But perhaps I'm missing something about why we need to do a particular thing now in .NET 8.
If you have any feedback on what is wrong or missing from this analysis, please comment below!
cc @dotnet/aspnet-blazor-eng