In my last blog post, I discussed hosting a React application with a subpath. It's a common question I've been getting about Static Web Apps.

Hosting an application with a subpath allows you to host multiple separate websites within the same domain, giving your users the impression that it is one site. Behind the scenes, the one site is composed of multiple 'micro-frontends', which facilitates the development of large websites (independent deployment, separation of domain, etc.). Read up on micro-frontends here!

I recently built this a demo similar to my last blog post with Blazor, so I figured I'd document it formally! In this blog post, I'll demonstrate how we can host a Blazor WASM app with a subpath on Static Web Apps as per this pattern.

The objective

We'll be hosting the Blazor WASM Static Web App at a subpath <hostname>.azurestaticapps.net/<subpath>, rather than the root domain <hostname>.azurestaticapps.net. The implementation will be similar to my React implementation from my last blog post.

This implementation focuses on Blazor WASM applications, though you should be able to generalize it to your frontend framework of choice. If you're trying to do this for a React application, checkout my last blog post.

Let's build it out!

The solution

Hosting an application on Azure Static Web Apps with a subpath requires the following:

  1. The Blazor WASM application must be built with the subpath. This will ensure the Blazor WASM app retrieves assets from the subpath and routes with the subpath.
  2. The Static Web Apps host must be configured to expect the application in the subpath.

I've built this out with Blazor WASM, and the sample project can be accessed on GitHub here: https://github.com/thomasgauvin/blazor-swa-with-subpath.

The application is also deployed here: https://red-ocean-027945410.2.azurestaticapps.net/app/. As you can see, this Blazor WASM application is hosted at the /app subpath.

Configuring the Blazor WASM application to have a subpath

We'll start by modifying the Blazor WASM application to support the subpath.

Create a starter Blazor WASM application (if you don't have one already)

Don't have a Blazor WASM application to start with? Create a simple app with the following commands:

  1. Create a Blazor WASM application: dotnet new blazorwasm -n blazor-swa-with-subpath.
  2. Open blazor-swa-with-subpath in VSCode.
  3. You can now run the project with dotnet run.

Edit your Blazor WASM application to support a subpath (we'll choose app)

Next, we'll configure our Blazor WASM application to support the app subpath. This is needed so that your Blazor application can make requests to the right files when it is deployed with a subpath. For this example, we will use subpath app, though you can choose any subpath for your project.

  1. In the blazor-swa-with-subpath.csproj file, add <StaticWebAssetBasePath>app</StaticWebAssetBasePath> to the <PropertyGroup>. This ensures that when you run dotnet publish, the publish folder is created with the static web assets within an wwwroot/app folder. Check out the docs of the StaticWebAssetBasePath property.

  2. In the wwwroot/index.html file, change the base href to <base href="/app/" />. This ensures that requests from your index.html are prepended by /app/. This will break the default development website served by dotnet run. You will now have to call dotnet run with the pathbase argument as such: dotnet run --pathbase=/app. This will ensure that your Blazor WASM development server hosts your app at the subpath.

  3. In the wwwroot/index.html file, change the script for blazor.webassembly.js to <script src="/app/_framework/blazor.webassembly.js"></script>. This will also break the default development website served by dotnet run, so as I mentioned before, you will have to use the dotnet run --pathbase=/app command instead.

  4. Build your Blazor project with dotnet publish -o publish. This will create a publish folder, containing wwwroot folder, which contains folder app, which contains the Blazor application.

  5. Optional step: You may now serve your built Blazor application with the dotnet-serve package. From publish/wwwroot, run dotnet serve -o --fallback-file ./app/index.html. The fallback file indicates the entry point of your Blazor app, in case a user tries to access a specific page of your Blazor app directly. Navigate to http://localhost:<PORT>/app to see your built Blazor app working.

Configure the Static Web Apps resource to host your Blazor WASM app with a subpath

To host your Blazor WASM app with a subpath, you must add the following configurations so that Static Web Apps redirects users to your Blazor app on the /app path.

The wwwroot folder will be our application folder, as defined by Static Web Apps. It will contain the following: the app folder (which contains our Blazor application served at the app subpath (the folder name is the same as the subpath)), index.html which is needed by Static Web Apps, and staticwebapp.config.json which contains the necessary redirects and navigation fallbacks for the Blazor app. The index.html placed in publish/wwwroot is needed because Static Web Apps requires an index.html file at the base of the application folder.

  1. Within publish/wwwroot, create an index.html file with the following contents:

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta http-equiv="Refresh" content="0; url='/app/'" />
    </head>
    
    <body>
    Redirecting to Blazor application
    </body>
    
    </html>

    This HTML is needed since Static Web Apps requires an index.html at the root of the project. It redirects requests to /index.html (or /) to /app/, where our Blazor app is hosted.

  2. Within publish/wwwroot, create a staticwebapp.config.json file with the following contents:

    {
        "navigationFallback": {
        "rewrite": "/app/index.html"
        },
        "routes": [{
            "route": "/",
            "redirect": "/app/"
        }]
    }

    This provides the navigation fallback for the entry-point of the Blazor WASM application. This also redirects customers accessing / to /app/ which is the entrypoint of our Blazor WASM application.

  3. (Optional) Use the swa cli to simulate the deployed Static Web Apps experience locally.

    1. From publish/wwwroot, run swa start. This will simulate your Static Web Apps locally, along with the staticwebapp.config.json and newly created index.html file.
    2. Open http://localhost:4280/ in your browser.

    Note: If this simulated Static Web Apps environment is not working, debug and resolve before moving onto the next step.

This is akin to a custom build process. In this tutorial, I am completing these steps manually, since it is easier to explain this way. You may consider creating the stub publish/wwwroot/index.html and placing the staticwebapp.config.json files as part of a build process/script for automation.

Deploy to Static Web Apps with the SWA CLI

Note: This application requires a custom build process (as done manually above). As such, I will be uploading the built project to my GitHub repository (typically, one wouldn't commit built assets to one's repository, rather these would be built as part of the build pipeline).

For this blog, the custom-built project will be committed and uploaded to the Static Web Apps resource as is. This can be done using either a repository integration for Static Web Apps or the SWA CLI. In either case, the app build would need to be skipped, so that these custom build modifications are kept.

Alternatively, you may add these build customizations to your build scripts, so that you can have this build as part of a CI/CD pipeline.

Below, we show how to upload this project to an Azure Static Web Apps resource with the SWA CLI. If you are considering creating a resource from the Azure Portal instead, ensure that you skip the app build by following the Skip building front-end app guide.

  1. Navigate to the /publish directory (cd ..).

  2. Deploy the contents of /publish/wwwroot using swa deploy wwwroot.

    Note that/publish/wwwroot should contain the app folder, the index.html file, and the staticwebapp.config.json file. The publish folder has been provided in this repository for reference.

  3. Browse you app at the deployed project link indicated by the swa cli. For instance, https://red-ocean-027945410.2.azurestaticapps.net.

Limitations

Hosting applications with a subpath in this manner has some limitations. Since we are hosting the application with a different path, it must be noted that some features of Static Web Apps will not use this subpath.

  • Static Web Apps backend integration allows you to have a managed functions backend or to link an API backend, and will route requests to the /api path to the backend. The path of /api cannot be changed, and as such, if you are hosting an application on /app, these will be making API calls to /api rather than /app/api. This could cause conflicts if you intend to host multiple SWAs on the same domain.
  • Static Web Apps has built-in authentication, which relies on special paths such as the /.auth path. This cannot be changed to the /app/.auth path for instance, so authentication using the built-in authentication could cause conflicts between applications.

These limitations can be circumvented by opting out of these Azure Static Web Apps features, for instance by calling APIs directly and using another authentication provider.

Conclusion

In this blog post, we successfully built and deployed a Blazor WASM app with a subpath to Azure Static Web Apps. Although we focused on Blazor, the steps to configure the Static Web App and build the project can be adapted to any web app. Hosting an application with a subpath can be quite useful when trying to host multiple Static Web Apps within the same domain, so this solution helps to enable those use cases.

Sources:

https://stackoverflow.com/questions/66862350/how-to-change-the-base-url-of-a-blazor-wasm-app, https://github.com/dotnet/AspNetCore.Docs/issues/26170, https://github.com/dotnet/AspNetCore.Docs/pull/26198/files