Be default, Umbraco 16+ disables runtime compilation for razor views in “Production” mode and instead wants you to precompile razor views at build time. We are wondering, is there a noticeable performance benefit to precompiling razor views? The downside to doing this means making hotfixes to razor views isn’t an option in production environments. Is this a standard best practice thing or is there a noticeable performance boost?
Here is the code in the Umbraco source code that now enforces the razor runtime compilation feature:
if (builder.Config.GetRuntimeMode() != RuntimeMode.Production)
{
mvcBuilder.AddRazorRuntimeCompilation();
}
Speaking only from my personal experience, yes, there’s quite a bit of impact on performance when not pre-compiling.
I usually notice it pretty quickly when a site has this disabled, as many pages will load exceptionally slow for the first hit and then pick up for consecutive requests.
Usually the impact is mostly felt after a deployment or recycle/restart but larger sites tend to be hit a fair bit harder then smaller ones.
If you have a well established CI/CD pipeline then pushing a hotfix to a view could be done pretty quickly.
Don’t get me wrong, I get that not having this functionality can be a bit of bummer, but it can also be blessing when someone forgets to push the hotfix to code and it later gets silently overwritten.
If you want, then you could do some benchmarking and post the results, might prove me wrong on my perceived “improvement”.
Regarding this:
Yes it is, and pre-compiling has, to my knowledge, been a way to improve performance of asp.net sites, since early days of .NET Framework.
At least I’ve worked on a fair amount of project on V7 that were using pre-compiling to greatly improve the performance of the platform.
It also enables compilation checks on build instead of runtime, making it potentially less error-prone.
I agree with Saeve that a good CI/CD would cause no issues with hotfixes. Just quickly changing a razor view on the server or just quickly manually uploading a razor file as a hotfix is a no-go in my opinion and should not be the reason for not precompiling razor views.
The first hits after a deploy are indeed the moments where you notice the biggest difference. After the first hit, the razor views are compiled, so the next hit is faster. But if you have a lot of views and a lot of visitors, you are taxing the server, and especially the cpu, a lot more when it needs to compile a lot af the same time. This can cause a slow site for some time after a reboot.
It looks like the big performance benefit is realized on the first load of each view. Whether in the long term, after they have been compiled, there is a benefit I don’t know. Regardless, it seems the best course of action is to follow current best practices and precompile production sites.
When Razor views are configured to be compiled at runtime, it means that they get compiled the first time when they are needed. But once they are compiled, they stay compiled (unless the file changes). This is speculation on my part, but I expect that once the initial hit has passed and the views are all compiled, the performance difference with pre-compiling is negligable.
We’ve compiled our views for the same reasons above ever since it was possible in Umbraco and it has had several benefits. I would say that it is most noticeable on Azure since application startup resource usage for Umbraco can be considerable. Precompiling the views on a busy site makes a significant difference.
Also:
Being unable to make changes to views directly on live improved our processes and delivery to clients.
Having views compiled meant that we could fail a pull request before being tested. This led to a reduction in how much logic was left in the views,
There are a couple of gotchas though. We have noticed that certain plugins that contain their own views don’t play nicely and need a little extra config. The one that springs to mind is the HubSpot integration package which always seems to through a duplicate view error. I think this is because of the way the views are included in the project and if you have the plugin referenced from supporting libraries.