Date: 2026-05-19
Branch: main
Result: Complete — 0 build errors, 914/914 tests pass.
frontend/vite.config.ts updated: build.outDir = '../LSPDFRManager.LocalApi/wwwroot'
Running npm run build now writes index.html + assets directly into the LocalApi project.
Program.cs updated with UseDefaultFiles() + UseStaticFiles() + MapFallbackToFile("index.html").
React SPA routing works: any unknown path falls back to index.html.
New LSPDFRManager.LocalApi/LocalApiHost.cs:
- Picks a free TCP port at startup via
TcpListeneron port 0 - Exposes
PortTask(aTask<int>) that completes once the server is listening - Exposes
BaseUrl(http://127.0.0.1:{port}) StartAsync()configures and starts aWebApplicationin-process (non-blocking)StopAsync()shuts it down cleanly
<Content Update="wwwroot\**" CopyToOutputDirectory="PreserveNewest" />Uses Update (not Include) to avoid duplicate-item error with the Web SDK's implicit Content glob.
wwwroot files are copied to the WPF output directory so AppContext.BaseDirectory + "wwwroot" resolves correctly at runtime.
LSPDFRManager.csproj:
- Added
<ProjectReference Include="LSPDFRManager.LocalApi\LSPDFRManager.LocalApi.csproj" /> - Added
frontend\**to all four SDK Remove patterns (Compile, EmbeddedResource, None, Page) to prevent VS from treatingfrontend/source as WPF project content.
App.xaml.cs:
OnStartup: firesLocalApiHost.StartAsync()on a background thread immediately (non-blocking)OnExit: callsLocalApiHost.StopAsync()
ViewModels/ReactPreviewViewModel.cs:
- Exposes
IsReadyandStatusText WaitForReadyAsync()awaitsLocalApiHost.PortTaskthen signals ready
Views/ReactPreviewView.xaml + ReactPreviewView.xaml.cs:
- Shows "Starting local API…" until ready
- Initializes WebView2 with a dedicated profile (
%APPDATA%/LSPDFRManager/WebView2React) - Navigates to
LocalApiHost.BaseUrlonce the port is ready
MainViewModel: addedReactPreviewVM,IsReactPreviewActive,"ReactPreview"case in Navigate switchApp.xaml: addedDataTemplateforReactPreviewViewModel → ReactPreviewViewMainWindow.xaml: added "React UI" nav button (Segoe MDL2 icon , nav keyReactPreview)
After adding the LocalApi project reference, the Roslyn IDE analyzer shows type-conflict hints in App.xaml.cs for AppDataPaths, LspdfrInstallLocator, etc.:
"The type 'AppDataPaths' in '...\LSPDFRManager.Shared\Services\AppDataPaths.cs' conflicts with the imported type 'AppDataPaths' in 'LSPDFRManager.Shared, Version=3.7.17.0, Culture=neutral, PublicKeyToken=null'"
Root cause: The IDE's Roslyn analyzer sees the type both via the direct ProjectReference → Shared (which includes source compilation) and via LocalApi → Shared (DLL import). MSBuild deduplicates at compile time; dotnet build produces 0 warnings and 0 errors.
Impact: None — compiler agrees, all 914 tests pass. Resolvable in a future milestone by restructuring the project graph (e.g., adding ExcludeAssets="compile" to the direct Shared reference).
On app startup:
- WPF shell starts normally (existing UI unchanged)
LocalApiHost.StartAsync()runs in the background — picks a free port, starts ASP.NET Core- Navigating to "React UI" in the sidebar shows a loading message
- Once
PortTaskcompletes, WebView2 initializes and navigates tohttp://127.0.0.1:{port}/ - The React SPA loads with all 17 route stubs and the sidebar nav
All existing WPF views remain fully functional.
| Command | Result |
|---|---|
npm run build (frontend/) |
Pass — dist/ written to LSPDFRManager.LocalApi/wwwroot/ |
npm run typecheck |
Pass — 0 errors |
npm run lint |
Pass — 0 errors |
dotnet build LSPDFRManager.sln |
Pass — 0 errors |
dotnet test |
Pass — 914/914 |
LSPDFRManager.LocalApi/LocalApiHost.csViewModels/ReactPreviewViewModel.csViews/ReactPreviewView.xamlViews/ReactPreviewView.xaml.csMILESTONE4_RESULT.md
frontend/vite.config.ts— build.outDir → LocalApi/wwwrootLSPDFRManager.LocalApi/Program.cs— static files + fallbackLSPDFRManager.LocalApi/LSPDFRManager.LocalApi.csproj— wwwroot Content UpdateLSPDFRManager.csproj— added LocalApi ProjectReference; frontend** exclusionApp.xaml.cs— LocalApiHost.StartAsync/StopAsyncApp.xaml— DataTemplate for ReactPreviewViewModelMainWindow.xaml— React UI nav buttonViewModels/MainViewModel.cs— ReactPreviewVM, IsReactPreviewActive, nav case
- IDE type-conflict hints from double Shared reference — resolvable by adding
<ExcludeAssets>compile</ExcludeAssets>or restructuring (Milestone 14+) - Vite proxy config for dev server (so
npm run devproxies/apito LocalApi during frontend development) - Port communicated to WPF shell — currently the WebView2 uses
LocalApiHost.BaseUrl(static). Could be passed as a window title or IPC for more explicit WPF/React integration - Session token for DNS rebinding protection (Milestone 9 security concern from migration plan)
- API endpoint groups (Milestones 5–13)