Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue/978/css auto naming clash #996

Merged
merged 3 commits into from
Nov 12, 2024
Merged
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
2 changes: 1 addition & 1 deletion .version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.2.793
0.2.796
4 changes: 2 additions & 2 deletions generator/test-css-expression/render_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import (
)

var expected = templ.ComponentCSSClass{
ID: "className_34fc",
Class: templ.SafeCSS(`.className_34fc{background-color:#ffffff;max-height:calc(100vh - 170px);color:#ff0000;}`),
ID: "className_34fc0328",
Class: templ.SafeCSS(`.className_34fc0328{background-color:#ffffff;max-height:calc(100vh - 170px);color:#ff0000;}`),
}

func TestCSSExpression(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion generator/test-css-middleware/expected.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<div class="red_050e">
<div class="red_050e5e03">
Red text
</div>
2 changes: 1 addition & 1 deletion generator/test-css-middleware/render_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import (
//go:embed expected.html
var expected string

var expectedCSS = `.red_050e{color:red;}
var expectedCSS = `.red_050e5e03{color:red;}
`

func Test(t *testing.T) {
Expand Down
24 changes: 12 additions & 12 deletions generator/test-css-usage/expected.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,33 @@
}
</style>
<div class="test">Style tags are supported</div>
<style type="text/css">.cssComponentGreen_58d2{color:#00ff00;}</style>
<div class="cssComponentGreen_58d2">CSS components are supported</div>
<div class="cssComponentGreen_58d2 classA &amp;&amp;&amp;classB classC d e" type="button">Both CSS components and constants are supported</div>
<div class="cssComponentGreen_58d2 classA &amp;&amp;&amp;classB classC d e" type="button">Both CSS components and constants are supported</div>
<style type="text/css">.cssComponentGreen_58d2872e{color:#00ff00;}</style>
<div class="cssComponentGreen_58d2872e">CSS components are supported</div>
<div class="cssComponentGreen_58d2872e classA &amp;&amp;&amp;classB classC d e" type="button">Both CSS components and constants are supported</div>
<div class="cssComponentGreen_58d2872e classA &amp;&amp;&amp;classB classC d e" type="button">Both CSS components and constants are supported</div>
<div class="a c">Maps can be used to determine if a class should be added or not.</div>
<style type="text/css">.e_739d{font-size:14pt;}</style>
<div class="a c e_739d">KV can be used to conditionally set classes.</div>
<style type="text/css">.e_739d4573{font-size:14pt;}</style>
<div class="a c e_739d4573">KV can be used to conditionally set classes.</div>
<div class="bg-violet-500 hover:bg-red-600 hover:bg-sky-700 text-[#50d71e] w-[calc(100%-4rem)">Psuedo attributes and complex class names are supported.</div>
<div class="a&#34; onClick=&#34;alert(&#39;hello&#39;)&#34;">
Class names are HTML escaped.
</div>
<style type="text/css">
.loading_a3cc{width:50%;}
.loading_a3cc3f08{width:50%;}
</style>
<div class="loading_a3cc">
<div class="loading_a3cc3f08">
CSS components can be used with arguments.
</div>
<style type="text/css">
.loading_9ccc{width:100%;}
.loading_9ccc4ca9{width:100%;}
</style>
<div class="loading_9ccc">
<div class="loading_9ccc4ca9">
CSS components can be used with arguments.
</div>
<style type="text/css">
.windVaneRotation_b68b{transform:rotate(45deg);}
.windVaneRotation_b68b990e{transform:rotate(45deg);}
</style>
<div class="windVaneRotation_b68b">
<div class="windVaneRotation_b68b990e">
Rotate
</div>

8 changes: 4 additions & 4 deletions generator/test-element-attributes/expected.html
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
<style type="text/css">
.important_2ed1{width:100;}
.important_2ed176fc{width:100;}
</style>
<div style="width: 100;">
Important
</div>
<style type="text/css">
.unimportant_900a{width:50;}
.unimportant_900aeb18{width:50;}
</style>
<div style="width: 100;" class="unimportant_900a">
<div style="width: 100;" class="unimportant_900aeb18">
Unimportant
</div>
<div style="width: 100;" class="unimportant_900a">
<div style="width: 100;" class="unimportant_900aeb18">
Else
</div>
<div data-script="on click
Expand Down
4 changes: 2 additions & 2 deletions runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -256,11 +256,11 @@ func (css ComponentCSSClass) ClassName() string {
// CSSID calculates an ID.
func CSSID(name string, css string) string {
sum := sha256.Sum256([]byte(css))
hp := hex.EncodeToString(sum[:])[0:4]
hs := hex.EncodeToString(sum[:])[0:8] // NOTE: See issue #978. Minimum recommended hs length is 6.
// Benchmarking showed this was fastest, and with fewest allocations (1).
// Using strings.Builder (2 allocs).
// Using fmt.Sprintf (3 allocs).
return name + "_" + hp
return name + "_" + hs
}

// NewCSSMiddleware creates HTTP middleware that renders a global stylesheet of ComponentCSSClass
Expand Down
24 changes: 24 additions & 0 deletions runtime_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,30 @@ import (
"github.com/google/go-cmp/cmp"
)

func TestCSSID(t *testing.T) {
t.Run("minimum hash suffix length is 8", func(t *testing.T) {
// See issue #978.
name := "classA"
css := "background-color:white;"
actual := len(templ.CSSID(name, css))
expected := len(name) + 1 + 8
if expected != actual {
t.Errorf("expected length %d, got %d", expected, actual)
}
})
t.Run("known hash collisions are avoided", func(t *testing.T) {
name := "classA"
// Note that the first 4 characters of the hash are the same.
css1 := "grid-column:1;grid-row:1;" // After hash: f781266f
css2 := "grid-column:13;grid-row:6;" // After hash: f781f18b
id1 := templ.CSSID(name, css1)
id2 := templ.CSSID(name, css2)
if id1 == id2 {
t.Errorf("hash collision: %s == %s", id1, id2)
}
})
}

func TestCSSHandler(t *testing.T) {
tests := []struct {
name string
Expand Down