Give the JS bridge the same fallback the framework script got #5
Loading…
Reference in a new issue
No description provided.
Delete branch "b/asset-fallback-layers"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Follow-up to #4. That PR covered blazor.web.js and left cheap-blazor-interop.js on the single static-web-asset path the removed extractor used to back up.
Measured: a broken static web asset does not 404. MapStaticAssets keeps the route from the endpoints manifest and either throws FileNotFoundException (500) or answers 200 with a zero-length body. Both render as a blank white window, and the zero-length case looks healthy in a network trace and in the request log.
The bridge is embedded alongside blazor.web.js and served from the assembly when it is not on disk. A dead static web assets manifest no longer kills the process at startup. And the host now checks its own page at startup and names any asset that comes back failing or empty, including third-party ones it cannot serve itself.
Verified on six deployment shapes with an empty NUGET_PACKAGES.
🤖 Claude AI Code Review
Code Review: JS Bridge Embedded Fallback
1. Summary
This PR extends the embedded-fallback pattern (previously applied only to
blazor.web.js) tocheap-blazor-interop.js. It also:EmbeddedAssetshelper (deduplicating manifest-resource access logic)UseStaticWebAssets()so a stale manifest cannot crash startupStartupAssetCheck, a startup diagnostic that fetches the root page and reports assets returning failures or empty bodiesOverall this is high-quality, well-motivated work with excellent comments and tests. My concerns are minor.
2. Code Quality
Strengths:
EmbeddedAssetsis a clean refactor — resolving the manifest name set once into aHashSetand routing bothBlazorFrameworkExtractorand the new middleware through it removes duplication nicely.availabledictionary filtered by what's actually embedded) reads well and preserves the "middleware not endpoint" invariant.The_interop_bridge_fallback_matches_the_file_on_disktest guarding against a stale embedded copy is exactly the right safeguard for shipping the file twice.UseStaticWebAssets()try/catch degradation is a good defensive move with a clear log message.Minor nits:
EmbeddedBlazorHostService.cs(line 210 area and around_logger.LogInformation("Configuring pipeline...) add noise. Worth reverting the whitespace-only changes.PackagingWiringTests.csgained a BOM (\ufeff) on line 1 — inconsistent with the rest and likely unintentional.3. Potential Issues
Regex-based HTML parsing (StartupAssetCheck): The
(?:src|href)regex will match attributes on any element, not just<script>/<link>. In practice the_framework/_contentprefix filter contains the blast radius, so this is acceptable for a best-effort diagnostic — but the XML doc comment says "every script and stylesheet," which slightly overstates what the regex does. Consider softening the comment or noting the prefix filter is what scopes it.Consistency between the fallback table and the startup check:
EmbeddedFallbackAssetskeys offEndpoints.JavaScriptBridgeEndpoint, whileStartupAssetCheckfilters on the/_content/and/_framework/prefixes. Please double-check thatJavaScriptBridgeEndpointactually resolves to/_content/CheapAvaloniaBlazor/cheap-blazor-interop.js(the value isn't in the diff). If it were, say,/js/bridge, the fallback path and the served path would diverge and the startup check would miss it. A small test assertingEmbeddedFallbackAssetskeys all start with a recognized prefix would lock this down.GetStringAsync(baseUrl, ...)for the root document: If the root page itself returns 500/empty (the very failure mode this targets),GetStringAsyncthrows and you land in the catch, which logs only atLogVerbose. That means a completely broken root document is quieter than a single broken asset (LogError). Consider treating a failed/empty root fetch as aLogErrorrather than swallowing it verbosely.Fire-and-forget task:
_ = Task.Run(() => StartupAssetCheck.RunAsync(...), _hostCts.Token).RunAsyncis documented to never throw, so this is safe, but passing the token to bothTask.RunandRunAsyncmeans a pre-start cancellation surfaces as aTaskCanceledExceptionon an unobserved task. Low risk given the guarantees, but worth a mental note.Potential double-read of content:
CheckOneAsyncusesGetAsync+ReadAsByteArrayAsync(buffers the whole body). Fine for small assets; just be aware a misconfigured large_contentasset gets fully buffered per check. Bounded by the 5s timeout, so acceptable.4. Recommendations
EmbeddedFallbackAssetsstarts with a prefixStartupAssetCheckrecognizes (ties the two subsystems together).LogError— it's the worst case and currently the quietest.ExtractAssetPaths/StartupAssetCheckto acknowledge it's attribute-scanning bounded by prefix, not true script/link parsing.HttpClientFactory.CreateForServerCheck()sets the 5s timeout referenced in the comments (not visible in diff).5. Verdict
APPROVE (with minor suggestions)
The core change is well-reasoned, the "ship it twice on purpose" decision is justified and guarded by tests, and the startup diagnostic addresses a genuinely painful silent-failure class. None of my concerns are blocking — the root-document-failure logging level and the fallback-table/prefix consistency check are the two most worth addressing before merge, but both are small.
📊 Tokens: 14733 input + 1954 output | 💰 Cost: ~$0.1225
Generated by Claude Opus 4.8 via Gitea Actions