Fix OverrideHtmlAssetPlaceholders to fingerprint assets with ./ relative prefix#53407
Draft
Fix OverrideHtmlAssetPlaceholders to fingerprint assets with ./ relative prefix#53407
Conversation
Co-authored-by: maraf <10020471+maraf@users.noreply.github.com>
Copilot
AI
changed the title
[WIP] Fix fingerprinting of module asset placeholders with relative paths
Fix OverrideHtmlAssetPlaceholders to fingerprint assets with ./ relative prefix
Mar 12, 2026
This was referenced Mar 12, 2026
Open
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
GetFingerprintedAssetPathonly performed exact dictionary lookups against label-keyed mappings (e.g.main.mjs), so asset placeholders using./-relative paths (common in generated importmaps) were never fingerprinted —./main#[.{fingerprint}].mjswould be left as-is instead of being replaced with the fingerprinted endpoint URL.Changes
OverrideHtmlAssetPlaceholders.cs— after an exact lookup miss, ifassetPathstarts with./, retry with the prefix stripped viaSubstring(2).IncludeOnlyHardFingerprintedModulessemantics are preserved for both lookup paths. Method visibility changed fromprivatetointernalfor testability.Substring(2)is used over the[2..]range operator since the project multi-targetsnet472.OverrideHtmlAssetPlaceholdersTest.cs— added unit tests for the new./-prefix fallback, covering.js/.mjsextensions, no-match passthrough,IncludeOnlyHardFingerprintedModuleswith hard- and soft-fingerprinted assets.Example
Original prompt
Goal
Fix #53406:
OverrideHtmlAssetPlaceholdersshould fingerprint module asset placeholders even when the module src/import path uses a relative./prefix (e.g../main#[.{fingerprint}].mjs).Background
Microsoft.NET.Sdk.StaticWebAssetstaskOverrideHtmlAssetPlaceholdersuses a regex (_assetsRegex) to locate asset placeholder strings and then usesGetFingerprintedAssetPath(urlMappings, assetPath)to map the non-fingerprinted label to the fingerprinted endpoint URL.Currently,
GetFingerprintedAssetPathonly attempts an exact lookup in theurlMappingsdictionary. This fails whenassetPathcontains a./prefix (common in generated importmaps), because the mapping keys are based on labels likemain.js, while the extractedassetPathcan be./main.js.Required changes
Update task logic
src/StaticWebAssetsSdk/Tasks/OverrideHtmlAssetPlaceholders.csGetFingerprintedAssetPath(Dictionary<string, ResourceAsset> urlMappings, string assetPath)so that it supports an optional leading./.assetPath.assetPathstarts with./, retry lookup with the prefix stripped (assetPath.Substring(2)), while still returning the original form (with./) if not fingerprinted.IncludeOnlyHardFingerprintedModulessemantics.Path.GetFullPath, no OS-specific separator changes) — only handle the./prefix.Update/add unit tests
./main#[.{fingerprint}].js(or.mjs) gets replaced with the fingerprinted endpoint URL when a mapping exists formain.js/main.mjs.test/Microsoft.NET.Sdk.StaticWebAssets.Tests/StaticWebAssets/OverrideHtmlAssetPlaceholdersTest.cs(task-level behavior test).test/Microsoft.NET.Sdk.StaticWebAssets.Tests/StaticWebAssetsFingerprintingTest.csby adding a data row that uses./main.jsand ensures fingerprinting occurs.Keep changes minimal
Acceptance criteria
OverrideHtmlAssetPlaceholderscorrectly fingerprints placeholders when the asset path begins with./../remains unchanged../scenario.Notes
.jsand.mjsmodule routes as applicable.The following is the prior conversation context from the user's chat exploration (may be truncated):
User: @dotnet/sdk/issues/53406
There is a feature
OverrideHtmlAssetPlaceholdersinMicrosoft.NET.Sdk.StaticWebAssets, it uses regex to find values of attributes and tries to put in fingerprint. It does it by finding corelating endpoint. Currently we support only exact match, but when generating impormap, we generate relative paths, like./main.js. We should support./prefix here as well. Update related unit tests as wellAssistant: I’ve submitted the requested repository changes for your approval, and I’m waiting on your accept/reject response before I can continue with applying them and validating the update (including the unit test changes for the
./prefix case).User: @copilot Accepted Confirmation: Are you sure?
Assistant: You’re right about where the bug is:
OverrideHtmlAssetPlaceholdersonly fingerprints when the matchedassetPathexactly equals a key in the label→endpoint mapping, and the mapping keys are the endpoint labels (e.g.main.js), not variants like./main.js. So when HTML contains:the regex captures
assetPathas./main.mjs, andurlMappings.TryGetValue("./main.mjs", ...)fails, so it leaves the path unchanged.Minimal fix
Update
GetFingerprintedAssetPath(...)to also attempt a lookup after stripping the leading./(and only that prefix), while still returning the original value if nothing matches. This keeps behavior minimal and avoids broader URL normalization changes.Pseudo-shape of the change (not applied yet):
assetPath)"./", try match forassetPath.Substring(2)IncludeOnlyHardFingerprintedModules), otherwise return the originalassetPathUnit tests to update/add
You should add coverage that exercises the lookup behavior (not just regex matching):
This pull request was created from Copilot chat.
🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.