From cf5171c237a5740a20bf5ef51167b482e2526c8f Mon Sep 17 00:00:00 2001 From: maddalax Date: Fri, 27 Sep 2024 09:46:45 -0500 Subject: [PATCH] add benchmarks --- framework/h/attribute.go | 8 ++ framework/h/render_test.go | 177 +++++++++++++++++++++++++++++++++++++ framework/h/renderer.go | 16 +++- framework/h/tag.go | 12 ++- 4 files changed, 205 insertions(+), 8 deletions(-) diff --git a/framework/h/attribute.go b/framework/h/attribute.go index 9232776..afb207d 100644 --- a/framework/h/attribute.go +++ b/framework/h/attribute.go @@ -125,6 +125,14 @@ func D(value string) Ren { return Attribute("d", value) } +func Alt(value string) Ren { + return Attribute("alt", value) +} + +func For(value string) Ren { + return Attribute("for", value) +} + func Type(name string) Ren { return Attribute("type", name) } diff --git a/framework/h/render_test.go b/framework/h/render_test.go index 1b5a2a2..0ea8394 100644 --- a/framework/h/render_test.go +++ b/framework/h/render_test.go @@ -103,3 +103,180 @@ func TestConditional(t *testing.T) { ) assert.Equal(t, "
", result) } + +func BenchmarkMailTo(b *testing.B) { + b.ReportAllocs() + ctx := RenderContext{ + builder: &strings.Builder{}, + } + for i := 0; i < b.N; i++ { + MailTo().Render(&ctx) + ctx.builder.Reset() + } +} + +func BenchmarkComplexPage(b *testing.B) { + b.ReportAllocs() + ctx := RenderContext{ + builder: &strings.Builder{}, + } + for i := 0; i < b.N; i++ { + ComplexPage().Render(&ctx) + ctx.builder.Reset() + } +} + +func ComplexPage() *Element { + return Html( + Head( + Meta("title", "Complex Page"), + Meta( + "charset", + "UTF-8", + ), + Meta( + "viewport", + "width=device-width, initial-scale=1.0", + ), + Link( + "stylesheet", + "https://example.com/styles.css", + ), + ), + Body( + Header( + Class("bg-gray-800 text-white py-4"), + Div( + Class("container mx-auto"), + H1(Class("text-3xl font-bold"), Text("Welcome to the Complex Page")), + Nav( + Ul( + Class("flex space-x-4"), + Li(A(Href("#"), Text("Home"))), + Li(A(Href("#"), Text("About"))), + Li(A(Href("#"), Text("Services"))), + Li(A(Href("#"), Text("Contact"))), + ), + ), + ), + ), + Main( + Class("container mx-auto mt-10"), + Section( + Class("grid grid-cols-3 gap-4"), + Article( + Class("col-span-2"), + H2(Class("text-2xl font-semibold mb-4"), Text("Featured Article")), + Img(Src("https://example.com/featured.jpg"), Alt("Featured Image")), + P(Class("mt-2 text-lg"), Text("This is a large article to test rendering performance.")), + ), + Aside( + Class("bg-gray-100 p-4"), + H3(Class("text-xl font-bold"), Text("Related Links")), + Ul( + Li(A(Href("#"), Text("Related Link 1"))), + Li(A(Href("#"), Text("Related Link 2"))), + Li(A(Href("#"), Text("Related Link 3"))), + ), + ), + ), + Section( + Class("my-8"), + H2(Class("text-2xl font-semibold mb-4"), Text("User Registration Form")), + Form( + Post("/register", "click"), + Div( + Class("grid grid-cols-2 gap-4"), + Label(For("first_name"), Text("First Name")), + Input("text", Id("first_name"), Name("first_name"), Class("border p-2 w-full")), + Label(For("last_name"), Text("Last Name")), + Input("text", Id("last_name"), Name("last_name"), Class("border p-2 w-full")), + Label(For("email"), Text("Email")), + Input("email", Id("email"), Name("email"), Class("border p-2 w-full")), + Label(For("password"), Text("Password")), + Input("password", Id("password"), Name("password"), Class("border p-2 w-full")), + ), + Button( + Type("submit"), + Class("bg-blue-500 text-white py-2 px-4 mt-4"), + Text("Register"), + ), + ), + ), + Section( + Class("my-8"), + H2(Class("text-2xl font-semibold mb-4"), Text("Data Table")), + Table( + Class("table-auto w-full border-collapse border"), + THead( + Tr( + Th(Class("border px-4 py-2"), Text("ID")), + Th(Class("border px-4 py-2"), Text("Name")), + Th(Class("border px-4 py-2"), Text("Age")), + Th(Class("border px-4 py-2"), Text("Occupation")), + ), + ), + TBody( + Tr( + Td(Class("border px-4 py-2"), Text("1")), + Td(Class("border px-4 py-2"), Text("John Doe")), + Td(Class("border px-4 py-2"), Text("28")), + Td(Class("border px-4 py-2"), Text("Engineer")), + ), + Tr( + Td(Class("border px-4 py-2"), Text("2")), + Td(Class("border px-4 py-2"), Text("Jane Smith")), + Td(Class("border px-4 py-2"), Text("34")), + Td(Class("border px-4 py-2"), Text("Designer")), + ), + Tr( + Td(Class("border px-4 py-2"), Text("3")), + Td(Class("border px-4 py-2"), Text("Alice Johnson")), + Td(Class("border px-4 py-2"), Text("45")), + Td(Class("border px-4 py-2"), Text("Manager")), + ), + ), + ), + ), + ), + Footer( + Class("bg-gray-800 text-white py-4 mt-10"), + Div( + Class("container mx-auto text-center"), + Text("© 2024 Complex Page Inc. All rights reserved."), + ), + ), + ), + ) +} + +func MailTo() *Element { + return Div( + H1( + Text("Contact Us"), + ), + Div( + Style("font-family: 'sans-serif'"), + Id("test"), + Attribute("data-contents", `something with "quotes" and a `), + Div( + Text("email:"), + A( + Href("mailto:"+"test@htmgo.dev"), + Text("Email me"), + ), + ), + ), + Hr( + Attribute("noshade", ""), + ), + Hr( + Attribute("optionA", ""), + Attribute("optionB", ""), + Attribute("optionC", "other"), + ), + Hr( + Attribute("noshade", ""), + ), + ) +} diff --git a/framework/h/renderer.go b/framework/h/renderer.go index ecd2635..a3e4021 100644 --- a/framework/h/renderer.go +++ b/framework/h/renderer.go @@ -3,6 +3,7 @@ package h import ( "fmt" "github.com/maddalax/htmgo/framework/hx" + "golang.org/x/net/html" "strings" ) @@ -25,7 +26,8 @@ func (node *Element) Render(context *RenderContext) { // some elements may not have a tag, such as a Fragment if node.tag != "" { - context.builder.WriteString("<" + node.tag) + context.builder.WriteString("<") + context.builder.WriteString(node.tag) context.builder.WriteString(" ") for name, value := range node.attributes { @@ -34,7 +36,7 @@ func (node *Element) Render(context *RenderContext) { } // first pass, flatten the children - flatChildren := make([]Ren, 0) + flatChildren := make([]Ren, 0, len(node.children)) for _, child := range node.children { switch child.(type) { case *ChildList: @@ -75,7 +77,9 @@ func (node *Element) Render(context *RenderContext) { if node.tag != "" { renderScripts(context) - context.builder.WriteString("") + context.builder.WriteString("") } } @@ -87,7 +91,11 @@ func renderScripts(context *RenderContext) { } func (a *AttributeR) Render(context *RenderContext) { - context.builder.WriteString(fmt.Sprintf(`%s="%s"`, a.Name, a.Value)) + context.builder.WriteString(a.Name) + context.builder.WriteString(`=`) + context.builder.WriteString(`"`) + context.builder.WriteString(html.EscapeString(a.Value)) + context.builder.WriteString(`"`) } func (t *TextContent) Render(context *RenderContext) { diff --git a/framework/h/tag.go b/framework/h/tag.go index 59ace19..c085df7 100644 --- a/framework/h/tag.go +++ b/framework/h/tag.go @@ -356,8 +356,8 @@ func Children(children ...Ren) *ChildList { return NewChildList(children...) } -func Label(text string) *Element { - return Tag("label", Text(text)) +func Label(children ...Ren) *Element { + return Tag("label", children...) } func IFrame(src string) *Element { @@ -400,8 +400,8 @@ func Header(children ...Ren) *Element { return Tag("header", children...) } -func Hr() *Element { - return Tag("hr") +func Hr(children ...Ren) *Element { + return Tag("hr", children...) } func LabelFor(id string, text string) *Element { @@ -420,6 +420,10 @@ func Ul(children ...Ren) *Element { return Tag("ul", children...) } +func Li(children ...Ren) *Element { + return Tag("li", children...) +} + func Select(children ...Ren) *Element { return Tag("select", children...) }