DEV Community

Chris Sainty
Chris Sainty

Posted on • Originally published at chrissainty.com on

Prerendering a Client-side Blazor Application

Prerendering a Client-side Blazor Application

While prerendering is now the default for server-side Blazor applications, I only recently discovered (as in the last 48 hours) that client-side Blazor applications can take advantage of this as well. In this post, I'm going to show you how you can setup your client-side Blazor application for prerendering.

The example project for this post can be found on GitHub.

What is prerendering?

Prerendering is a process where all the elements of a web page are compiled on the server and static HTML is served to the client. This technique is used to help SPAs (Single Page Applications) improve their SEO (Search Engine Optimisation). Another benefit is that sites appear to load much faster.

What this means for a Blazor application is that the requested page will be built on the server and compiled to static HTML. This static HTML will include the blazor.webassembly.js file which is present in the standard client-side Blazor template. When the client receives this static HTML it will be processed and rendered as normal.

Prerendering a Client-side Blazor Application

When the blazor.webassembly.js file is executed the mono runtime will be downloaded along with the application dlls and your application will be run. At this point all of the static prerendered elements will be replaced with interactive components and the application will become interactive.

Prerendering a Client-side Blazor Application

Now, this may sound like a lot has to happen before your application becomes usable. But this all happens in a very short space of time and is imperceivable to most end users.

The Prerendering Trade-off

Before we look at how to enable prerendering I want to point out that there are some trade-offs with using it.

You will no longer be able to deploy your Blazor application as static files. As we'll see in a second, prerendering requires a razor page, and that means a .NET runtime is required. While this is probably not a big issue, I do want to make sure you're aware of it.

The other trade-off is that you must manage any JavaScript calls to account for prerendering. If you attempt to perform JavaScript interop in the OnInit or OnInitAsync method of a component which is being prerendered then you will get an exception. When using prerendering all JavaScript interop calls should be moved to the OnAfterRenderAsync lifecycle method. This method will only be called once the page is fully rendered.

Enabling Prerendering

We're going to start with a stand alone Blazor application and go though the steps to enable prerendering. I've created a new stand alone Blazor application using the dotnet CLI. You can also use the template in Visual Studio.

dotnet new blazor -o BlazorPrerendering.Client
Enter fullscreen mode Exit fullscreen mode

If you are looking to enable prerendering on a client-side Blazor app that is already using the "Hosted" template. Then you can just add in the bits of configuration as we go along.

Adding a Host Project

The first thing we are going to do is add a new empty ASP.NET Core Web App. Again, I'm using the dotnet CLI but you can use the templates in Visual Studio if you prefer.

dotnet new web -o BlazorPrerendering.Server
Enter fullscreen mode Exit fullscreen mode

Our solution should now look like this.

Prerendering a Client-side Blazor Application

Then we need to add a project reference from the server project to the client project as well as a couple of NuGet packages. We also need to add in some additional sources for loading the Blazor.Server package. So the easiest thing to do is edit the csproj file directly.

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>netcoreapp3.0</TargetFramework>
    <RestoreAdditionalProjectSources>
      https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json;
      https://dotnet.myget.org/F/blazor-dev/api/v3/index.json;
    </RestoreAdditionalProjectSources>
    <LangVersion>7.3</LangVersion>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.Blazor.Server" Version="3.0.0-preview5-19227-01" />
    <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.0.0-preview5-19227-01" />
  </ItemGroup>

  <ItemGroup>
    <ProjectReference Include="..\BlazorPrerendering.Client\BlazorPrerendering.Client.csproj" />
  </ItemGroup>

</Project>
Enter fullscreen mode Exit fullscreen mode

Once you're done, your project file should look like the code above.

Configuring The Host

Now our projects are setup, we are going to make some changes to the server projects Startup.cs.

First, add the following code to the ConfigureServices method.

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc().AddNewtonsoftJson();
    services.AddResponseCompression(opts =>
    {
        opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(
            new[] { "application/octet-stream" });
    });
}
Enter fullscreen mode Exit fullscreen mode

We'll also need to add a using statement.

using Microsoft.AspNetCore.ResponseCompression;
Enter fullscreen mode Exit fullscreen mode

Then replace the code in the Configure method with the code below.

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseResponseCompression();

    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseBlazorDebugging();
    }

    app.UseHttpsRedirection();

    app.UseStaticFiles();

    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
        endpoints.MapFallbackToPage("/_Host");
    });

    app.UseBlazor<Client.Startup>();
}
Enter fullscreen mode Exit fullscreen mode

We're going to add a folder called wwwroot to the root of the server project. Inside this folder we also need to create another called js. Then inside the js folder we are going to create a file called blazor.webassembly.js and copy in this code.

Once that is done we need to copy the contents of the css folder in the Client projects wwwroot folder to server projects wwwroot folder. Once thats all done things should look like this.

Prerendering a Client-side Blazor Application

Finally, we need to create a folder called Pages in the root of the server project and create a file called _Host.cshtml with the following code.

@page "/"
@namespace BlazorPrerendering.Server.Pages
@using BlazorPrerendering.Client
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Prerendering client-side Blazor</title>
    <base href="~/" />
    <environment include="Development">
        <link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" />
    </environment>
    <environment exclude="Development">
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
              asp-fallback-href="css/bootstrap/bootstrap.min.css"
              asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute"
              crossorigin="anonymous"
              integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" />
    </environment>
    <link href="css/site.css" rel="stylesheet" />
</head>
<body>
    <app>@(await Html.RenderStaticComponentAsync<App>())</app>

    <script src="~/js/blazor.webassembly.js"></script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

Testing Prerendering

We should now be able to start up the server project and launch the application. Once the application has loaded, the easiest way to test prerendering is to disable JavaScript in your browser. Then reload the page, if the page loads then prerendering is working.

To achieve this in Chrome or Edgeium, open the dev tools and press ctrl+shift+p or cmd+shift+p, depending on your OS. The start typing javascript, you should see the option appear to disable javascript.

Prerendering a Client-side Blazor Application

You should still be able to navigate around the app but you will find components will not be interactive. Go ahead and enable JavaScript again (just repeat the steps to disable but now the option will be to Enable JavaScript) and refresh the page, you should now have an interactive application once more.

Summary

Prerendering is a really useful tool to have available and it's great that we can now use it with both server-side and client-side Blazor. In this post, I've shown how you can enable prerendering of your client-side Blazor applications by use of a hosted server project.

Top comments (1)

Collapse
 
henon profile image
Meinrad Recheis • Edited

Awesome Chris. I just discovered that search engines haven't been indexing any of the pages on the documentation web site of our open source component library MudBlazor at mudblazor.com
So we'll try to pre-render it to change that. Thanks!