Update 08 Sep 2019: since Microsoft has officially announce the deprecation of aspnet-webpack package in .NET Core 3.0, you might not want to use the code in this blog post directly in production. However, you might still be able to learn a thing or two from it. I will write a new blog post on restoring all the following feature on the new React template in Visual Studio.
React is getting very popular for building rich web interface, and is one of the supported project template in ASP.NET Core. In .NET Core, you can quickly create a new React project by running the command (or using the new project dialog):
dotnet new react
The template immediately gives you a working project with both React and ASP.NET Core. However, I don’t feel very happy with the latest template in .NET Core 2.2 and 3.0, so I created a new one based on the template from older version of .NET Core for my own projects.
What is in the React project template in ASP.NET Core
In .NET Core 2.2 and 3.0 (in preview at the moment), the React template leverages react-scripts (from
create-react-app) to hide all the complicated details of the build process while still provide you with useful features:
- Hot reload: components are reloaded automatically when you save the change.
- Optimized build result: you get minified js, css with hash in filename for cache busting and also a minified index.html.
- Quickly and easily update your build tools and configuration: updating to new build tools and configuration is simply updating react-scripts package.
On the ASP.NET side, during development, one single line of code handle all the magic:
This starts a new Node server and handles proxying back and forth between the Node and ASP.NET servers. For production, the current template would call
npm run build, which creates the optimized version of the whole React application in
ClientApp\build folder where ASP.NET can simply server as static files.
This setup is very nice and undoubtedly being used by so many. However, there is some drawback:
- As any kinds of abstraction, you cannot it is not easy to go in and change the underlying details, for this case, the build process. One solution from
create-react-appsite is to run
npm run eject(https://facebook.github.io/create-react-app/docs/available-scripts#npm-run-eject). This command is a one-way extraction of all hidden codes inside
react-scriptsinto your own project, which adds a bunch of package dependencies, scripts and configuration files into your projects. This also removes
react-scriptsfrom your package.json. Some reasons why you might want to eject:
- Add typescript support.
create-react-apphas a guide to add Typescript support (https://facebook.github.io/create-react-app/docs/adding-typescript). However, I cannot make it work properly with Visual Studio and the template from ASP.NET Core.
- Customize your code splitting strategy.
react-scriptshas supports for code splitting out of the box via import() and some other strategy but does not allow you to go further than that to customize your own bundle.
- Add typescript support.
- This setup completely isolates the React UI and the ASP.NET server. This is nice since your don’t have to worry about Node and ASP.NET not playing nice with each other. However, it kind of defeats the purpose of using ASP.NET here. You might just use minimal NodeJS for your UI with a static index.html and ASP.NET separately for your APIs.
My React & ASP.NET Core template
What I am trying to achieve with this template:
- Hot reload: your components automatically refresh once you save the change. It is magical when you have the IDE on one monitor and the browser on another monitor.
- First class Typescript support in Visual Studio and Visual Studio Code: errors should be detected quickly in Visual Studio, and .ts and .tsx file should be built and hot reloaded.
- Exposing webpack configs: this means you get more control on the build process, but with great power comes great responsibility. For me, it is totally worth doing so as to leverage the full power of webpack.
- Support useful ASP.NET features such as
asp-append-versionfor cache busting.
- Runtime application setting. For my projects, not every parameter can be known at build time. Some integration between ASP.NET and the build result would allow injecting some runtime settings into the React app.
- Allow the use of CDN for certain libraries. This allow me to remove popular libraries such as JQuery or Bootstrap from my production bundle and use a public CDN to reduce the load of my server.
- Support build/rebuild/publish action of Visual Studio. This is actually not much different from what is already there in Visual Studio template.
- Server side rendering.
To be clear, I have thought of some cons of using my template:
- You have to manage more stuffs. This template is more or less a more compact version of what you get after
npm run eject, so you will have to manage more package versions and your webpack config.
- Microsoft normally supports APIs that they have released. However, with the breakneck speed of React development, I can’t be sure if the way I presented here would be available anymore in .NET Core after 3.0. However, you can still always go back to the
npm run ejectmethod by copying and pasting your .ts and .tsx files into a new project template.
- I am not an expert on React and definitely not as good on React as the people of
create-react-appis awesome, so my goal would be to learn and incorporate more from their template. There are some items that I am still working on and still learning from
- Automatic code splitting for dynamic
- Automatic code splitting for dynamic
Below are some highlights of the differences between my template and the one from ASP.NET Core:
- I use MVC for this although the ASP.NET Core template use Razor Page. I don’t actually need much MVC features other than displaying the Index page and some tag helpers; however, the new template utilizes
UseSpa()(see more) in
Startup.csto handle routing to the Index page, which unfortunately does not work very well with my setup.
UseSpa()enforces a static index page for production build, which I don’t like very much. I prefer to have my index page generated by ASP.NET, so I use
Startup.cs. I might change my mind about this later if I figure out a better way to allow ASP.NET and the React app interact.
- Typescript!! I don’t understand why ASP.NET Core template does not use Typescript, probably because they want to stick as close as possible to
create-react-app, and maybe expect that you will add Typescript support on your own. Typescript is awesome; you should use it, and my template uses it!
- The ASP.NET Core template serves file directly in
ClientApp/buildfor production build. I prefer the old way of isolating every public file in
wwwroot, so my template put the build output in
wwwroot/distinstead. You can find this in
- Build output in ASP.NET Core template does not leverage CDN. My template use ASP.NET tag helpers to use CDN with fallback and hash for libraries and even your main bundle. You can find this in
Index.cshtml. This give you more flexibility but since the Index page is not completely static, it might reduce the site performance. A small layer of output caching should solve this though.
Startup.cs(where I read the configuration),
Index.cshtml(where the setting is being used).
- InProcess hosting model does not work very well with hot module reload, so I disabled it for development.
- There is no server prerendering in the new ASP.NET Core template; however, from the Git repository, there is the new extension function
UseSpa()to get the HTML template, which requires a static html file. My template leverages the tag helper
asp-prerender-modulein Index.cshtml to trigger server prerendering.
Dive into the code
You can get the project from
https://github.com/nguyenquyhy/ReactAspNetCore. I tried to be as clean as possible in each commit, so hopefully you can go through each of them and understand the change. You might not want to clone the repository and build up your project from there though because I will keep rebasing and overwriting existing commits to make sure every commit best represent a feature that I want to add.
Future posts on this topic
- Things I’ve learn using React with ASP.NET
I you think this post is useful to you or having any questions or suggestions, please leave a comment below!