🐛 Bug Report
A <template> or <f-template> closing tag that contains whitespace before the > (for example </template\n\t>) is not recognized by the SSR template parser. The content gets dropped or the malformed tag is left in the output. This affects the declarative HTML pipeline used by @microsoft/fast-build (the microsoft-fast-build crate) and @microsoft/fast-test-harness.
💻 Repro or Code Sample
A template whose closing tag wraps onto a new line:
<f-template name="my-element" shadowrootmode="open">
<template>
<span>hello</span>
</template
>
</f-template>
Run it through convertTemplate in generate-templates.ts, or Locator::from_patterns → parse_f_templates in the crate, and inspect the output.
Minimal Rust reproduction (added as a unit test in crates/microsoft-fast-build/src/locator.rs):
#[test]
fn test_parse_f_templates_closing_tag_with_whitespace() {
let html = "<f-template name=\"my-button\"><template><button>{{label}}</button></template\n\t></f-template>";
let results = parse_f_templates(html);
assert_eq!(results.len(), 1);
assert_eq!(results[0].name, Some("my-button".to_string()));
assert_eq!(results[0].content, "<button>{{label}}</button>");
}
This test fails. extract_template_content never finds the literal </template>, falls back to the trimmed inner string, and the wrapper plus the malformed closing tag leak into content:
left: "<template><button>{{label}}</button></template\n\t>"
right: "<button>{{label}}</button>"
🤔 Expected Behavior
</template\n\t>, </template >, and </f-template\n> should parse the same as </template> and </f-template>.
The WHATWG HTML Living Standard, section 13.1.2.2 (End tags), defines an end tag as: <, then /, then the tag name, then optionally one or more ASCII whitespace, then >. Whitespace between the tag name and > is conforming HTML, so </template\n\t> is valid and must be handled. (Whitespace is not permitted between <, /, and the tag name, and end tags carry no attributes.)
😯 Current Behavior
Both parsers search for the exact closing-tag strings.
In crates/microsoft-fast-build/src/locator.rs, parse_f_templates calls html[inner_start..].find("</f-template>") and extract_template_content calls html[tag_end..].find("</template>"). When the real tag contains whitespace, these find calls return None and fall back to the untrimmed inner string. The malformed tag stays in the output, and the template is dropped entirely when </f-template> cannot be located.
In packages/fast-test-harness/src/build/generate-templates.ts, the wrapper strip html.replace(/<\/?template[^>]*>/g, "") does not match closing tags whose whitespace falls outside the [^>]* boundary in every code path.
Templates with whitespace in the closing tag produce invalid generated HTML.
💁 Possible Solution
Match closing tags with a whitespace-tolerant scan rather than a literal substring search: the tag name followed by zero or more ASCII whitespace, then >. In the crate, replace the find("</template>") and find("</f-template>") calls in locator.rs with a helper that, after matching </template / </f-template, skips ASCII whitespace and expects >. In the harness, narrow the regex to /<\/(f-)?template\s*>/g so it tolerates trailing whitespace without accepting non-conforming forms. I'm willing to contribute the fix.
🔦 Context
I author component templates as standalone HTML files and render them through the FAST SSR and test-harness pipeline. Formatters routinely wrap long closing tags onto a new line, which produces </template\n\t>. The parser rejects that whitespace, so spec-conforming HTML silently renders broken output, and the cause is hard to track down. I found no open or closed issue covering this case.
🌍 Your Environment
- OS & Device: macOS
- Browser: N/A (build/SSR-time issue)
- Version:
@microsoft/fast-build / @microsoft/fast-test-harness (v3 prerelease)
🐛 Bug Report
A
<template>or<f-template>closing tag that contains whitespace before the>(for example</template\n\t>) is not recognized by the SSR template parser. The content gets dropped or the malformed tag is left in the output. This affects the declarative HTML pipeline used by@microsoft/fast-build(themicrosoft-fast-buildcrate) and@microsoft/fast-test-harness.💻 Repro or Code Sample
A template whose closing tag wraps onto a new line:
Run it through
convertTemplateingenerate-templates.ts, orLocator::from_patterns→parse_f_templatesin the crate, and inspect the output.Minimal Rust reproduction (added as a unit test in
crates/microsoft-fast-build/src/locator.rs):This test fails.
extract_template_contentnever finds the literal</template>, falls back to the trimmed inner string, and the wrapper plus the malformed closing tag leak intocontent:🤔 Expected Behavior
</template\n\t>,</template >, and</f-template\n>should parse the same as</template>and</f-template>.The WHATWG HTML Living Standard, section 13.1.2.2 (End tags), defines an end tag as:
<, then/, then the tag name, then optionally one or more ASCII whitespace, then>. Whitespace between the tag name and>is conforming HTML, so</template\n\t>is valid and must be handled. (Whitespace is not permitted between<,/, and the tag name, and end tags carry no attributes.)😯 Current Behavior
Both parsers search for the exact closing-tag strings.
In
crates/microsoft-fast-build/src/locator.rs,parse_f_templatescallshtml[inner_start..].find("</f-template>")andextract_template_contentcallshtml[tag_end..].find("</template>"). When the real tag contains whitespace, thesefindcalls returnNoneand fall back to the untrimmed inner string. The malformed tag stays in the output, and the template is dropped entirely when</f-template>cannot be located.In
packages/fast-test-harness/src/build/generate-templates.ts, the wrapper striphtml.replace(/<\/?template[^>]*>/g, "")does not match closing tags whose whitespace falls outside the[^>]*boundary in every code path.Templates with whitespace in the closing tag produce invalid generated HTML.
💁 Possible Solution
Match closing tags with a whitespace-tolerant scan rather than a literal substring search: the tag name followed by zero or more ASCII whitespace, then
>. In the crate, replace thefind("</template>")andfind("</f-template>")calls inlocator.rswith a helper that, after matching</template/</f-template, skips ASCII whitespace and expects>. In the harness, narrow the regex to/<\/(f-)?template\s*>/gso it tolerates trailing whitespace without accepting non-conforming forms. I'm willing to contribute the fix.🔦 Context
I author component templates as standalone HTML files and render them through the FAST SSR and test-harness pipeline. Formatters routinely wrap long closing tags onto a new line, which produces
</template\n\t>. The parser rejects that whitespace, so spec-conforming HTML silently renders broken output, and the cause is hard to track down. I found no open or closed issue covering this case.🌍 Your Environment
@microsoft/fast-build/@microsoft/fast-test-harness(v3 prerelease)