Skip to content

Commit 15776b3

Browse files
Copilotjaviercn
andcommitted
Fix ScriptTagHelper importmap regression by checking for existing content
Co-authored-by: javiercn <6995051+javiercn@users.noreply.github.com>
1 parent 9a91938 commit 15776b3

File tree

3 files changed

+39
-33
lines changed

3 files changed

+39
-33
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
#nullable enable
2+
~override Microsoft.AspNetCore.Mvc.TagHelpers.ScriptTagHelper.ProcessAsync(Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext context, Microsoft.AspNetCore.Razor.TagHelpers.TagHelperOutput output) -> System.Threading.Tasks.Task

src/Mvc/Mvc.TagHelpers/src/ScriptTagHelper.cs

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -236,36 +236,40 @@ private StringWriter StringWriter
236236

237237
/// <inheritdoc />
238238
public override void Process(TagHelperContext context, TagHelperOutput output)
239+
{
240+
ProcessAsync(context, output).GetAwaiter().GetResult();
241+
}
242+
243+
/// <inheritdoc />
244+
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
239245
{
240246
ArgumentNullException.ThrowIfNull(context);
241247
ArgumentNullException.ThrowIfNull(output);
242248

243249
if (string.Equals(Type, "importmap", StringComparison.OrdinalIgnoreCase))
244250
{
245-
// This is an importmap script, we'll write out the import map and
246-
// stop processing.
247-
var importMap = ImportMap ?? ViewContext.HttpContext.GetEndpoint()?.Metadata.GetMetadata<ImportMapDefinition>();
248-
if (importMap == null)
251+
// This is an importmap script, check if there's existing content first
252+
var childContent = await output.GetChildContentAsync();
253+
if (!childContent.IsEmptyOrWhiteSpace)
249254
{
250-
// No importmap found. Only suppress output if this was intended to be
251-
// an automatically generated importmap (i.e., when asp-importmap was used).
252-
// If the user provided explicit content without asp-importmap, let it render as-is.
253-
if (ImportMap != null || context.AllAttributes.ContainsName(ImportMapAttributeName))
254-
{
255-
output.SuppressOutput();
256-
return;
257-
}
258-
// Let the tag render as-is by continuing with normal processing
259-
// Don't return here, let normal attribute copying happen
255+
// User provided explicit content, preserve it
256+
return;
260257
}
261-
else
258+
259+
// No existing content, so we can apply import map logic
260+
var importMap = ImportMap ?? ViewContext.HttpContext.GetEndpoint()?.Metadata.GetMetadata<ImportMapDefinition>();
261+
if (importMap == null)
262262
{
263-
output.TagName = "script";
264-
output.TagMode = TagMode.StartTagAndEndTag;
265-
output.Attributes.SetAttribute("type", "importmap");
266-
output.Content.SetHtmlContent(importMap.ToString());
263+
// No importmap found, nothing to do.
264+
output.SuppressOutput();
267265
return;
268266
}
267+
268+
output.TagName = "script";
269+
output.TagMode = TagMode.StartTagAndEndTag;
270+
output.Attributes.SetAttribute("type", "importmap");
271+
output.Content.SetHtmlContent(importMap.ToString());
272+
return;
269273
}
270274

271275
// Pass through attribute that is also a well-known HTML attribute.

src/Mvc/Mvc.TagHelpers/test/ScriptTagHelperTest.cs

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -795,55 +795,56 @@ public void ScriptTagHelper_RendersImportMap_FromEndpoint()
795795
}
796796

797797
[Fact]
798-
public void ScriptTagHelper_PreservesExplicitImportMapContent_WhenNoImportMapDefinition()
798+
public async Task ScriptTagHelper_PreservesExplicitImportMapContent_WhenUserProvidesContent()
799799
{
800800
// Arrange - this simulates the user's scenario where they provide explicit importmap content
801-
// without using asp-importmap attribute
802801
var context = MakeTagHelperContext(
803802
attributes: new TagHelperAttributeList
804803
{
805804
new TagHelperAttribute("type", "importmap"),
806805
});
807806

808807
var output = MakeTagHelperOutput("script", attributes: new TagHelperAttributeList());
808+
// Simulate user providing explicit content
809+
output.Content.SetHtmlContent(@"{""imports"":{""jquery"":""https://code.jquery.com/jquery.js""}}");
809810

810811
var helper = GetHelper();
811812
helper.Type = "importmap";
812-
// No endpoint with ImportMapDefinition and no asp-importmap attribute
813-
// This should NOT suppress the output, allowing user content to render
813+
// No endpoint with ImportMapDefinition - this should NOT suppress the output
814+
// since user provided explicit content
814815

815816
// Act
816-
helper.Process(context, output);
817+
await helper.ProcessAsync(context, output);
817818

818819
// Assert
819820
Assert.Equal("script", output.TagName); // Tag should not be suppressed
820821
Assert.Equal("importmap", output.Attributes["type"].Value);
821-
// The output should not be suppressed, allowing user's explicit content to render
822-
Assert.False(output.IsContentModified); // Content should remain as user provided
822+
// The user's explicit content should be preserved
823+
Assert.Equal(@"{""imports"":{""jquery"":""https://code.jquery.com/jquery.js""}}", output.Content.GetContent());
823824
}
824825

825826
[Fact]
826-
public void ScriptTagHelper_SuppressesOutput_WhenAspImportMapAttributeUsedButNoDefinition()
827+
public async Task ScriptTagHelper_SuppressesOutput_WhenNoContentAndNoImportMapDefinition()
827828
{
828-
// Arrange - this simulates using asp-importmap attribute but having no ImportMapDefinition
829+
// Arrange - this simulates an empty importmap script with no definition
829830
var context = MakeTagHelperContext(
830831
attributes: new TagHelperAttributeList
831832
{
832833
new TagHelperAttribute("type", "importmap"),
833-
new TagHelperAttribute("asp-importmap", null), // asp-importmap used but no value
834834
});
835835

836836
var output = MakeTagHelperOutput("script", attributes: new TagHelperAttributeList());
837+
// No content provided
837838

838839
var helper = GetHelper();
839840
helper.Type = "importmap";
840-
// No endpoint with ImportMapDefinition but asp-importmap attribute is present
841-
// This should suppress the output since it was intended to be auto-generated
841+
// No endpoint with ImportMapDefinition and no explicit content
842+
// This should suppress the output since there's nothing to render
842843

843844
// Act
844-
helper.Process(context, output);
845+
await helper.ProcessAsync(context, output);
845846

846-
// Assert - output should be suppressed when asp-importmap is used but no definition found
847+
// Assert - output should be suppressed when no content and no definition
847848
Assert.Null(output.TagName); // Tag should be suppressed
848849
}
849850

0 commit comments

Comments
 (0)