React & ASP.NET Core

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):

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-app site 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-scripts into your own project, which adds a bunch of package dependencies, scripts and configuration files into your projects. This also removes react-scripts from your package.json. Some reasons why you might want to eject:
    • Add typescript support. create-react-app has 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-scripts has 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.
  • 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-version for 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 eject method 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-app. create-react-app is 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 create-react-app itself:
    • Automatic code splitting for dynamic import()
    • [TBA]

Below are some highlights of the differences between my template and the one from ASP.NET Core:

  1. 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.cs to 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 MapSpaFallbackRoute() in 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.
  2. 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!
  3. The ASP.NET Core template serves file directly in ClientApp/build for production build. I prefer the old way of isolating every public file in wwwroot, so my template put the build output in wwwroot/dist instead. You can find this in webpack.config.js and webpack.vendor.config.js.
  4. 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 _Layout.cshtml and 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.
  5. In my template, application setting is loaded (particularly the CDN URL) and injected into both the HTML page and Javascript. This allows me to disable CDN on my computer and enable different CDN URL for staging and production. ASP.NET Core template generates completely static HTML and JS, so you have to know the CDN URL (or similar dynamic parameters) at build time. You can see my implementation in Startup.cs (where I read the configuration), _Layout.cshtml and Index.cshtml (where the setting is being used).
  6. InProcess hosting model does not work very well with hot module reload, so I disabled it for development.
  7. There is no server prerendering in the new ASP.NET Core template; however, from the Git repository, there is the new extension function UseSpaPrerendering(). Unfortunately, UseSpaPrerendering() utilizes UseSpa() to get the HTML template, which requires a static html file. My template leverages the tag helper asp-prerender-module in 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
  • Styled-components

I you think this post is useful to you or having any questions or suggestions, please leave a comment below!

One thought to “React & ASP.NET Core”

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.