diff --git a/src/Mvc/Mvc.TagHelpers/src/PublicAPI.Unshipped.txt b/src/Mvc/Mvc.TagHelpers/src/PublicAPI.Unshipped.txt index 7dc5c58110bf..1bbff6be240e 100644 --- a/src/Mvc/Mvc.TagHelpers/src/PublicAPI.Unshipped.txt +++ b/src/Mvc/Mvc.TagHelpers/src/PublicAPI.Unshipped.txt @@ -1 +1,2 @@ #nullable enable +~override Microsoft.AspNetCore.Mvc.TagHelpers.ScriptTagHelper.ProcessAsync(Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext context, Microsoft.AspNetCore.Razor.TagHelpers.TagHelperOutput output) -> System.Threading.Tasks.Task diff --git a/src/Mvc/Mvc.TagHelpers/src/ScriptTagHelper.cs b/src/Mvc/Mvc.TagHelpers/src/ScriptTagHelper.cs index 64cc1be2f694..3706be8d03ff 100644 --- a/src/Mvc/Mvc.TagHelpers/src/ScriptTagHelper.cs +++ b/src/Mvc/Mvc.TagHelpers/src/ScriptTagHelper.cs @@ -236,14 +236,27 @@ private StringWriter StringWriter /// public override void Process(TagHelperContext context, TagHelperOutput output) + { + ProcessAsync(context, output).GetAwaiter().GetResult(); + } + + /// + public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output) { ArgumentNullException.ThrowIfNull(context); ArgumentNullException.ThrowIfNull(output); if (string.Equals(Type, "importmap", StringComparison.OrdinalIgnoreCase)) { - // This is an importmap script, we'll write out the import map and - // stop processing. + // This is an importmap script, check if there's existing content first + var childContent = await output.GetChildContentAsync(); + if (!childContent.IsEmptyOrWhiteSpace) + { + // User provided explicit content, preserve it + return; + } + + // No existing content, so we can apply import map logic var importMap = ImportMap ?? ViewContext.HttpContext.GetEndpoint()?.Metadata.GetMetadata(); if (importMap == null) { diff --git a/src/Mvc/Mvc.TagHelpers/test/ScriptTagHelperTest.cs b/src/Mvc/Mvc.TagHelpers/test/ScriptTagHelperTest.cs index 18ffbc3cd10f..11003dcd5e3c 100644 --- a/src/Mvc/Mvc.TagHelpers/test/ScriptTagHelperTest.cs +++ b/src/Mvc/Mvc.TagHelpers/test/ScriptTagHelperTest.cs @@ -794,6 +794,60 @@ public void ScriptTagHelper_RendersImportMap_FromEndpoint() Assert.Equal(importMap.ToJson(), output.Content.GetContent()); } + [Fact] + public async Task ScriptTagHelper_PreservesExplicitImportMapContent_WhenUserProvidesContent() + { + // Arrange - this simulates the user's scenario where they provide explicit importmap content + var context = MakeTagHelperContext( + attributes: new TagHelperAttributeList + { + new TagHelperAttribute("type", "importmap"), + }); + + var output = MakeTagHelperOutput("script", attributes: new TagHelperAttributeList()); + // Simulate user providing explicit content + output.Content.SetHtmlContent(@"{""imports"":{""jquery"":""https://code.jquery.com/jquery.js""}}"); + + var helper = GetHelper(); + helper.Type = "importmap"; + // No endpoint with ImportMapDefinition - this should NOT suppress the output + // since user provided explicit content + + // Act + await helper.ProcessAsync(context, output); + + // Assert + Assert.Equal("script", output.TagName); // Tag should not be suppressed + Assert.Equal("importmap", output.Attributes["type"].Value); + // The user's explicit content should be preserved + Assert.Equal(@"{""imports"":{""jquery"":""https://code.jquery.com/jquery.js""}}", output.Content.GetContent()); + } + + [Fact] + public async Task ScriptTagHelper_SuppressesOutput_WhenNoContentAndNoImportMapDefinition() + { + // Arrange - this simulates an empty importmap script with no definition + var context = MakeTagHelperContext( + attributes: new TagHelperAttributeList + { + new TagHelperAttribute("type", "importmap"), + }); + + var output = MakeTagHelperOutput("script", attributes: new TagHelperAttributeList()); + // No content provided + + var helper = GetHelper(); + helper.Type = "importmap"; + // No endpoint with ImportMapDefinition and no explicit content + // This should suppress the output since there's nothing to render + + // Act + await helper.ProcessAsync(context, output); + + // Assert - output should be suppressed when no content and no definition + Assert.Null(output.TagName); // Tag should be suppressed + } + private Endpoint CreateEndpoint(ImportMapDefinition importMap = null) { return new Endpoint(