'How to deploy Blazor WebAssembly as static site in GitLab Pages

I can't find any guide on how to deploy a Blazor web assembly app to GitLab Pages as a static site. Has anyone managed to do so for .NET 6?

I have created a sample web assembly Blazor client application:

https://gitlab.com/sunnyatticsoftware/sasw-community/sasw-editor

The steps to create this simple web assembly are:

  1. Install .NET 6 SDK
  2. Create repo and clone it (e.g: sasw-editor)
  3. Create the solution with web assembly Blazor project
    dotnet new gitignore
    dotnet new blazorwasm --name Sasw.Editor.Web --output src/Sasw.Editor.Web --no-https
    dotnet new sln
    dotnet sln add src/Sasw.Editor.Web
    
  4. Compile and run it
    dotnet build
    dotnet run --project src/Sasw.Editor.Web
    

That's a way to run the blazor app on the port defined at the launchsettings.json

Building...
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: http://localhost:5291
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: C:\src\sasw-editor\src\Sasw.Editor.Web

I stop it. It works fine when served with Kestrel.

Now, the process to publish a distribution folder would be like this

dotnet publish -c Release -o publish

All the artifacts and files are now under publish folder. So, in theory, I can serve those things with a simple web server. I install a basic web server tool called local-web-server (it requires NodeJs/npm but you can use any other web server)

npm install -g local-web-server

Now I navigate to the publish/wwwroot folder where my index.html is And I start the web server there

ws
Listening on http://5CD013DP5L:8000, http://192.168.1.13:8000, http://127.0.0.1:8000, http://172.21.208.1:8000

If I open the browser on http://127.0.0.1:8000, or any other of the above url, I can see my Blazor wasm app working perfectly.

I want to host that very same publish folder in GitLab pages which, in theory, is capable of serving static files.

So I create a .gitlab-ci.yml to compile, publish and copy contents to the public folder of GitLab pages.

image: mcr.microsoft.com/dotnet/sdk:6.0

variables:
  GIT_DEPTH: 1000
  PUBLISH_OUTPUT_DIR: publish

stages:
  - build
  - test
  - publish
  - delivery

build:
  stage: build
  script:
    - dotnet restore --no-cache --force
    - dotnet build --configuration Release --no-restore
  artifacts:
    paths:
    - test
    expire_in: 8 hour
  rules:
    - if: $CI_COMMIT_TAG
      when: never  
    - when: always

test:
  stage: test
  script: dotnet test --blame --configuration Release
  allow_failure: false
  rules:
    - if: $CI_COMMIT_TAG
      when: never  
    - exists:
      - test/**/*Tests.csproj

publish:
  stage: publish
  script:
    - dotnet publish -c Release -o $PUBLISH_OUTPUT_DIR
  artifacts:
    paths: 
      - $PUBLISH_OUTPUT_DIR/
    expire_in: 8 hour
  rules:
    - if: $CI_COMMIT_TAG
      when: never  
    - when: on_success

pages:
  stage: delivery
  script:
    - cp -a $PUBLISH_OUTPUT_DIR/ public
  artifacts:
    paths:
    - public
  only:
  - main

The pipeline completes successfully. I can see the exact same structure I had locally within publish folder, this time under public folder in GitLab

But it fails to render the app https://sunnyatticsoftware.gitlab.io/-/sasw-community/sasw-editor/-/jobs/1846501612/artifacts/public/wwwroot/index.html

shows

Loading...
An unhandled error has occurred. Reload 🗙 

I can see it's attempting to access https://sunnyatticsoftware.gitlab.io/ or https://sunnyatticsoftware.gitlab.io/favicon.ico and returning 404

The favicon.ico would exist on https://sunnyatticsoftware.gitlab.io/-/sasw-community/sasw-editor/-/jobs/1846501612/artifacts/public/wwwroot/favicon.ico

so it must be some kind of URL re-write problem, right?

Any help would be much appreciated.



Solution 1:[1]

The solution is simply to use the following

pages:
  stage: delivery
  script:
    - cp -a $PUBLISH_OUTPUT_DIR/wwwroot public
  artifacts:
    paths:
    - public
  only:
  - main

and to use the <base href="/sasw-community/sasw-editor/" /> in index.html with the relative path.

I've recorded a quick tutorial on my Odysee channel https://odysee.com/@sunnyAtticSoftware:a/blazor-wasm-gitlab-pages:e

See https://gitlab.com/sunnyatticsoftware/training/blazorwasm-pages with a full sample

I still don't know of a good way to mix local development's base / relative path with prod base /sasw-community/sasw-editor/ and change it dynamically (is it even possible?)

But the problem is solved.

Solution 2:[2]

Always keep it at base href="/" and then in your ci change it to whatever you need. E.g. on gitlab you can use the CI_PROJECT_NAME variable.

pages:
  stage: deploy
  variables:
    SED_COMMAND: 's#<base\shref="\/"\s?\/>#<base href="\/$CI_PROJECT_NAME\/" \/>#g'
  script:
    - cp -a $PUBLISH_OUTPUT_DIR/wwwroot public
    - sed -r -i "$SED_COMMAND" public/index.html
  artifacts:
    paths:
    - public
  only:
    - main

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Alexander Schulz