Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/slimy-suits-sparkle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@astrojs/compiler': patch
---

Updates `compressHTML` logic to account for elements which are known to be whitespace sensitive
65 changes: 62 additions & 3 deletions internal/transform/transform.go
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,62 @@ func isWhitespaceInsensitiveElement(n *astro.Node) bool {
return n.Data == "head"
}

var knownTextElements = map[string]bool{
"a": true,
"abbr": true,
"b": true,
"bdi": true,
"bdo": true,
"blockquote": true,
"br": true,
"caption": true,
"cite": true,
"code": true,
"col": true,
"colgroup": true,
"data": true,
"del": true,
"dfn": true,
"em": true,
"h1": true,
"h2": true,
"h3": true,
"h4": true,
"h5": true,
"h6": true,
"i": true,
"ins": true,
"kbd": true,
"mark": true,
"p": true,
"q": true,
"rp": true,
"rt": true,
"ruby": true,
"s": true,
"samp": true,
"small": true,
"span": true,
"strong": true,
"sub": true,
"sup": true,
"table": true,
"tbody": true,
"td": true,
"tfoot": true,
"th": true,
"thead": true,
"time": true,
"tr": true,
"u": true,
"var": true,
"wbr": true,
}

func isTextElement(n *astro.Node) bool {
return knownTextElements[n.Data]
}

func collapseWhitespace(doc *astro.Node) {
walk(doc, func(n *astro.Node) {
if n.Type == astro.TextNode {
Expand All @@ -304,10 +360,13 @@ func collapseWhitespace(doc *astro.Node) {

// If the node is only whitespace, clear it
if len(strings.TrimFunc(n.Data, unicode.IsSpace)) == 0 {
// If it's a lone text node, or if it's within a whitespace-insensitive element, clear completely
if (n.PrevSibling == nil && n.NextSibling == nil) || n.Closest(isWhitespaceInsensitiveElement) != nil {
if isTextElement(n) {
// Known textual elements can be handled early
n.Data = " "
} else if (n.PrevSibling == nil && n.NextSibling == nil) || n.Closest(isWhitespaceInsensitiveElement) != nil {
// If it's a lone text node, or if it's within a whitespace-insensitive element, clear completely
n.Data = ""
} else {
} else if n.Parent != nil {
n.Data = " "
}
return
Expand Down
25 changes: 25 additions & 0 deletions internal/transform/transform_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,16 @@ func TestCompactTransform(t *testing.T) {
source: "<div>Click <a>here</a> <span>space</span></div>",
want: "<div>Click <a>here</a> <span>space</span></div>",
},
{
name: "preserve in-between inline elements I",
source: "<p>{'text'} <span>text</span></p>",
want: "<p>{'text'} <span>text</span></p>",
},
{
name: "preserve in-between inline elements II",
source: "<p><span>text</span> <span>text</span></p>",
want: "<p><span>text</span> <span>text</span></p>",
},
{
name: "expression trim first",
source: "<div>{\n() => {\n\t\treturn <span />}}</div>",
Expand Down Expand Up @@ -463,6 +473,21 @@ func TestCompactTransform(t *testing.T) {
source: "<div>{ a + b }</div>",
want: "<div>{a + b}</div>",
},
{
name: "meaningful whitspace regression I",
source: "<a href={``}>\n<span />\n<span />\n<span>{title}</span></a>",
want: "<a href={``}> <span></span> <span></span> <span>{title}</span></a>",
},
{
name: "meaningful whitspace regression I",
source: "<a href={``}>\n<span />\n<span />\n<span>{title}</span></a>",
want: "<a href={``}> <span></span> <span></span> <span>{title}</span></a>",
},
{
name: "meaningful whitespace regression II",
source: "<h2>\n <span>Contributors with this achievement</span>\n <span>Badge</span>\n</h2>",
want: "<h2> <span>Contributors with this achievement</span> <span>Badge</span> </h2>",
},
}
var b strings.Builder
for _, tt := range tests {
Expand Down
4 changes: 4 additions & 0 deletions packages/compiler/test/compact/minify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ test('collapsing', async () => {
assert.match(await minify(`<span> inline </span>`), '$$render`<span> inline </span>`');
assert.match(await minify(`<span>\n inline \t{\t expression \t}</span>`), '$$render`<span>\ninline ${expression}</span>`');
assert.match(await minify(`<span> inline { expression }</span>`), '$$render`<span> inline ${expression}</span>`');
assert.match(
await minify('<div>\n <p>{"text"} <span>text</span></p>\n <p><span>text</span> <span>text</span></p>\n</div>'),
'<div> <p>${"text"} <span>text</span></p> <p><span>text</span> <span>text</span></p> </div>'
);
});

test('space normalization between attributes', async () => {
Expand Down