Files
Resume/.junie/plans/rename-website-to-web-and-convert-blazor-standalone.md
T
2026-09-09 13:38:34 -04:00

12 KiB

sessionId
sessionId
session-260909-131140-mwcu

Requirements

Overview & Goals

The objective of this task is to rename the Website project to Web and migrate it from an ASP.NET Core server-hosted Blazor model to a Blazor Standalone (client-side WebAssembly) application.

Converting the resume website to a standalone WebAssembly client maximizes practical utility:

  • Zero Server Overhead: Eliminates the ongoing cost, server compute requirements, and connection state management of Blazor Server.
  • Reliability & Availability: Removes SignalR disconnection fragility for users viewing the resume, ensuring seamless offline and low-bandwidth reading.
  • Static Hostability: Allows the build output to be deployed to any high-efficiency static storage or CDN provider (e.g., GitHub Pages, Cloudflare Pages, Azure Static Web Apps, AWS S3).
  • Naming Consistency: Unifies the repository naming conventions around Web.

Scope

In Scope

  • Rename folder Website to Web and project file Website.csproj to Web.csproj.
  • Update solution configuration Resume.slnx.
  • Refactor all namespaces from Website.* to Web.*.
  • Change project SDK to Microsoft.NET.Sdk.BlazorWebAssembly.
  • Replace server package dependencies with Microsoft.AspNetCore.Components.WebAssembly and Microsoft.AspNetCore.Components.WebAssembly.DevServer.
  • Add wwwroot/index.html as the host document.
  • Migrate Program.cs to WebAssemblyHostBuilder.
  • Convert App.razor to client router structure and purge server-only components (ReconnectModal, server-bound Error.razor).
  • Update scoped CSS stylesheet references to Web.styles.css.

Out of Scope

  • Altering the resume data models (Overview.cs, PersonalInfo.cs, Skills.cs, WorkExperience.cs) or resume content.
  • Visual restyling of Home.razor or MainLayout.razor.

User Stories

  • As a recruiter or hiring manager viewing the resume, I want instant page load and resilient navigation without connection drops or server lag so that I can evaluate candidate qualifications smoothly.
  • As a developer maintaining the site, I want a lightweight static client structure with clean Web naming so that deployment pipelines and local iteration are simple, cheap, and efficient.

Functional Requirements

  • The project must build and run successfully via dotnet build and dotnet run.
  • Navigating to / must render the resume content (Home.razor) through MainLayout.razor.
  • Navigating to undefined routes must display the not-found view (NotFound.razor / <NotFound>).
  • Client asset loading (Bootstrap, app.css, scoped CSS, favicon) must resolve properly without 404 errors.

Non-Functional Requirements

  • Efficiency: The published output must consist strictly of static assets (WASM binaries, HTML, CSS, JS) suitable for edge distribution.
  • Compatibility: Targets .NET 10.0 runtime with modern browser support.

Technical Design

Current Implementation

The application currently resides in directory Website/ with project file Website/Website.csproj using Microsoft.NET.Sdk.Web on net10.0. It utilizes server-side interactive Razor Components with WebApplication builder, server routing, and ReconnectModal for SignalR circuit reconnections.

Key Decisions

  • SDK & Package Strategy: Transition from Microsoft.NET.Sdk.Web to Microsoft.NET.Sdk.BlazorWebAssembly. Remove Microsoft.AspNetCore.Components.WebAssembly.Server and install Microsoft.AspNetCore.Components.WebAssembly with Microsoft.AspNetCore.Components.WebAssembly.DevServer for seamless local debugging.
  • Client Host Document (index.html): In standalone Blazor, the host page is wwwroot/index.html rather than App.razor. index.html will contain #app mount point, fallback loader, and script reference to _framework/blazor.webassembly.js.
  • Component Hierarchy: Convert App.razor to contain the root <Router> component, delegating page rendering to MainLayout and pages.
  • Server Artifact Deletion: Cleanly delete ReconnectModal.razor / .css / .js (SignalR circuit reconnects) and ASP.NET Core server-dependent Error.razor (HttpContext.TraceIdentifier).

Proposed Changes

C:\Users\jonmc\Resume
├── Resume.slnx                  (Updated project path to Web/Web.csproj)
└── Web/                         (Renamed from Website/)
    ├── Components/
    │   ├── Layout/
    │   │   ├── MainLayout.razor
    │   │   └── MainLayout.razor.css
    │   ├── Pages/
    │   │   ├── Home.razor       (Updated namespace Web.Data)
    │   │   ├── Home.razor.css
    │   │   └── NotFound.razor
    │   ├── App.razor            (Converted to client Router root)
    │   └── _Imports.razor       (Updated usings to Web.*)
    ├── Data/                    (Updated namespaces to Web.Data)
    │   ├── Overview.cs
    │   ├── PersonalInfo.cs
    │   ├── Skills.cs
    │   └── WorkExperience.cs
    ├── Properties/
    │   └── launchSettings.json  (Updated profiles for WebAssembly dev server)
    ├── wwwroot/
    │   ├── index.html           (Added client host document)
    │   ├── app.css
    │   ├── favicon.png
    │   └── lib/bootstrap/...
    ├── Program.cs               (WebAssemblyHostBuilder startup)
    └── Web.csproj               (Renamed & converted to BlazorWebAssembly SDK)

Data Models & Contracts

Data classes remain statically available under Web.Data:

  • Web.Data.Overview.Get() -> Overview.Data
  • Web.Data.PersonalInfo.Get() -> PersonalInfo.Data
  • Web.Data.Skills.Get() -> Skills.Data
  • Web.Data.WorkExperience.Get() -> WorkExperience.Data

Entry Point Contract (Web/Program.cs)

using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Web;

var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");

builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });

await builder.Build().RunAsync();

Root Host Document (Web/wwwroot/index.html)

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Jonathan McCaffrey - Resume</title>
    <base href="/" />
    <link rel="stylesheet" href="lib/bootstrap/dist/css/bootstrap.min.css" />
    <link rel="stylesheet" href="app.css" />
    <link rel="stylesheet" href="Web.styles.css" />
    <link rel="icon" type="image/png" href="favicon.png" />
    <HeadOutlet />
</head>

<body>
    <div id="app">
        <svg class="loading-progress">
            <circle r="40%" cx="50%" cy="50%" />
            <circle r="40%" cx="50%" cy="50%" />
        </svg>
        <div class="loading-progress-text"></div>
    </div>

    <div id="blazor-error-ui">
        An unhandled error has occurred.
        <a href="." class="reload">Reload</a>
        <span class="dismiss">🗙</span>
    </div>
    <script src="_framework/blazor.webassembly.js"></script>
</body>

</html>

Project File Contract (Web/Web.csproj)

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

  <PropertyGroup>
    <TargetFramework>net10.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <RootNamespace>Web</RootNamespace>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="10.0.6" />
    <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="10.0.6" PrivateAssets="all" />
  </ItemGroup>

</Project>

Testing

Validation Approach

Verification focuses on compilation integrity, project file correctness, client asset resolution, and routing fidelity under the standalone execution model.

Key Scenarios

  • Build Verification: Run dotnet build on Resume.slnx and Web/Web.csproj to confirm zero compilation warnings or errors across the new namespaces.
  • Startup Execution: Launch the project via dotnet run --project Web/Web.csproj and verify that the development server starts up cleanly on the configured localhost port.
  • Root Page Rendering (/): Verify index.html loads, WebAssembly runtime bootstraps App.razor, and Home.razor displays Jonathan McCaffrey's overview, contact info, skills, and work experience.
  • Routing & Not Found (/invalid-path): Verify that navigating to unmapped routes renders the NotFound component inside MainLayout.
  • Static Assets Integrity: Check that Bootstrap, app.css, Web.styles.css, and favicon.png are returned with HTTP 200 responses.

Edge Cases

  • Scoped CSS bundle path changes (Website.styles.css -> Web.styles.css) properly reflected in index.html.
  • No lingering references to Website in usings, project configurations, or solution metadata.
  • Clean removal of ReconnectModal and Error.razor without dangling references in App.razor or _Imports.razor.

Delivery Steps

✓ Step 1: Rename project files, solution references, and namespace declarations

The project directory, project file, solution definition, and all source namespaces are unified under Web.

  • Rename the directory Website to Web and rename Website.csproj to Web.csproj.
  • Update the solution file Resume.slnx to reference Web/Web.csproj instead of Website/Website.csproj.
  • Update the <RootNamespace> in Web.csproj to Web.
  • Refactor all C# namespace declarations in Web/Data/Overview.cs, Web/Data/PersonalInfo.cs, Web/Data/Skills.cs, and Web/Data/WorkExperience.cs from Website.Data to Web.Data.
  • Refactor @using Website.* statements across Web/Components/_Imports.razor, Web/Components/Pages/Home.razor, and Web/Program.cs to Web.*.
  • Update scoped CSS bundle link references from Website.styles.css to Web.styles.css.

✓ Step 2: Convert project SDK and package dependencies to Blazor Standalone

The project file is configured as a standalone Blazor WebAssembly application with client-side runtime packages and tooling.

  • Update the project SDK in Web.csproj from Microsoft.NET.Sdk.Web to Microsoft.NET.Sdk.BlazorWebAssembly.
  • Remove the server hosting package Microsoft.AspNetCore.Components.WebAssembly.Server.
  • Add Microsoft.AspNetCore.Components.WebAssembly (version 10.0.*) as a runtime package reference.
  • Add Microsoft.AspNetCore.Components.WebAssembly.DevServer (version 10.0.*, PrivateAssets="all") for local development execution.
  • Update Web/Properties/launchSettings.json to streamline local development profiles with the WebAssembly debug proxy and browser launch.

✓ Step 3: Restructure client entry point, HTML host, and Blazor component hierarchy

The application boots as a client-side WebAssembly single-page application using index.html and WebAssemblyHostBuilder.

  • Create Web/wwwroot/index.html with root mounting target #app, <HeadOutlet /> integration, static stylesheet references, and _framework/blazor.webassembly.js.
  • Rewrite Web/Program.cs to initialize WebAssemblyHostBuilder.CreateDefault(args), mount App to #app and HeadOutlet to head::after, configure standard scoped HttpClient, and execute await builder.Build().RunAsync().
  • Update Web/Components/App.razor to act as the client component router containing <Router>, <Found>, and <NotFound> definitions.
  • Remove server-specific artifacts that are obsolete in standalone mode: Web/Components/Layout/ReconnectModal.razor, ReconnectModal.razor.css, ReconnectModal.razor.js, and Web/Components/Pages/Error.razor.
  • Clean up Web/Components/_Imports.razor to remove server render-mode directives and include client WebAssembly namespaces.
  • Move or verify client configuration files in Web/wwwroot/ if required for client settings.