├── .gitignore ├── README.md ├── ace └── simple.ace ├── amber └── simple.amber ├── bench.sh ├── ego ├── footer.ego ├── footer.ego.go ├── header.ego ├── header.ego.go ├── index.ego ├── index.ego.go ├── navigation.ego ├── navigation.ego.go ├── simple.ego └── simple.ego.go ├── ftmpl ├── base.go ├── base.tmpl ├── basecontent.go ├── basecontent.tmpl ├── footer.go ├── footer.tmpl ├── header.go ├── header.tmpl ├── index.go ├── index.tmpl ├── index2.go ├── index2.tmpl ├── navigation.go ├── navigation.tmpl ├── simple.go └── simple.tmpl ├── go.mod ├── go.sum ├── go ├── includes │ ├── base.tmpl │ ├── footer.tmpl │ ├── header.tmpl │ └── navigation.tmpl ├── layout │ └── index.tmpl └── simple.tmpl ├── goh ├── footer.html ├── footer.html.go ├── header.html ├── header.html.go ├── index.html ├── index.html.go ├── navigation.html ├── navigation.html.go ├── simple.html └── simple.html.go ├── golang ├── footer.go ├── header.go ├── index.go ├── navigation.go └── simple.go ├── gomponents └── simple.go ├── gorazor ├── index.go ├── index.gohtml ├── simple.go ├── simple.gohtml └── tpl │ ├── helper │ ├── footer.go │ ├── footer.gohtml │ ├── header.go │ ├── header.gohtml │ ├── navigation.go │ └── navigation.gohtml │ └── layout │ ├── base.go │ └── base.gohtml ├── hero ├── footer.html ├── footer.html.go ├── header.html ├── header.html.go ├── index.html ├── index.html.go ├── navigation.html ├── navigation.html.go ├── simple.html └── simple.html.go ├── htmlbuilder └── simple.go ├── jade ├── footer.jade ├── header.jade ├── index.jade ├── index.jade.go ├── jade.go ├── navigation.jade ├── simple.jade └── simple.jade.go ├── jet ├── blocks.jet ├── index.jet ├── layout.jet └── simple.jet ├── main.sh ├── model └── data.go ├── mustache ├── base.mustache ├── footer.mustache ├── header.mustache ├── index.mustache ├── navigation.mustache └── simple.mustache ├── pongo2 └── simple.pongo ├── quicktemplate ├── footer.qtpl ├── footer.qtpl.go ├── header.qtpl ├── header.qtpl.go ├── index.qtpl ├── index.qtpl.go ├── navigation.qtpl ├── navigation.qtpl.go ├── simple.qtpl └── simple.qtpl.go ├── raymond └── simple.handle ├── soy └── simple.soy ├── templates_complex_test.go ├── templates_test.go └── templbench ├── footer.templ ├── footer_templ.go ├── header.templ ├── header_templ.go ├── index.templ ├── index_templ.go ├── navigation.templ ├── navigation_templ.go ├── simple.templ └── simple_templ.go /.gitignore: -------------------------------------------------------------------------------- 1 | vendor 2 | prof.mem 3 | cpu*.prof 4 | mem*.prof 5 | *.test 6 | files/results* -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # goTemplateBenchmark 2 | 3 | comparing the performance of different template engines 4 | 5 | ## full featured template engines 6 | 7 | - [Ace](https://github.com/yosssi/ace) 8 | - [Amber](https://github.com/eknkc/amber) 9 | - [Go](https://golang.org/pkg/html/template) 10 | - [Handlebars](https://github.com/aymerick/raymond) 11 | - [Mustache](https://github.com/hoisie/mustache) 12 | - [Pongo2](https://github.com/flosch/pongo2) 13 | - [Soy](https://github.com/robfig/soy) 14 | - [Jet](https://github.com/CloudyKit/jet) 15 | 16 | ## precompilation to Go code 17 | 18 | - [ego](https://github.com/benbjohnson/ego) 19 | - [ftmpl](https://github.com/tkrajina/ftmpl) 20 | - [Goh](https://github.com/OblivionOcean/Goh) 21 | - [Gorazor](https://github.com/sipin/gorazor) 22 | - [Quicktemplate](https://github.com/valyala/quicktemplate) 23 | - [Hero](https://github.com/shiyanhui/hero) 24 | - [Jade](https://github.com/Joker/jade) 25 | - [templ](https://github.com/a-h/templ) 26 | - [gomponents](https://github.com/maragudk/gomponents) 27 | - [hb](https://github.com/gouniverse/hb) 28 | 29 | ## baseline benchmarks for comparison 30 | 31 | - DirectBuffer - Use go to write the HTML by hand to the buffer with basic escaping 32 | 33 | ## transpiling to Go Template 34 | 35 | - [Damsel](https://github.com/dskinner/damsel) I won't benchmark transpiling 36 | engines, because transpilation should just happen once at startup. If you 37 | cache the transpilation result, which is recommended, you would have the same 38 | performance numbers as html/template for rendering. 39 | 40 | ## Why? 41 | 42 | Just for fun. Go Templates work nice out of the box and should be used for 43 | rendering from a security point of view. If you care about performance you 44 | should cache the rendered output. 45 | 46 | Sometimes there are templates that cannot be reasonably cached. Then you might 47 | need a really fast template engine with code generation. 48 | 49 | ## How to run the benchmarks 50 | 51 | ``` 52 | ./bench.sh -c go 53 | ``` 54 | 55 | ## Results dev machine 56 | 57 | local desktop: ryzen 3900x 58 | 59 | ## simple benchmarks 60 | ### full featured template engines 61 | | Name | Runs | µs/op | B/op | allocations/op | 62 | | ---------- | --------- | ------ | ----- | -------------- | 63 | | Ace | 256,797 | 13.017 | 1,121 | 40 | 64 | | Amber | 373,540 | 8.926 | 849 | 36 | 65 | | Golang | 604,209 | 8.650 | 769 | 35 | 66 | | GolangText | 1,426,340 | 2.453 | 128 | 7 | 67 | | Handlebars | 254,118 | 13.904 | 3,424 | 75 | 68 | | JetHTML | 4,334,586 | 0.794 | 0 | 0 | 69 | | Mustache | 810,091 | 4.483 | 1,723 | 30 | 70 | | Pongo2 | 586,269 | 5.805 | 2,075 | 32 | 71 | | Soy | 1,000,000 | 3.545 | 1,224 | 19 | 72 | 73 | 74 | ### precompilation to Go code 75 | | Name | Runs | µs/op | B/op | allocations/op | 76 | | ------------- | ---------- | ----- | ----- | -------------- | 77 | | Ego | 3,287,790 | 1.024 | 85 | 8 | 78 | | Ftmpl | 2,133,676 | 1.704 | 774 | 12 | 79 | | Goh | 41,564,152 | 0.085 | 0 | 0 | 80 | | Gomponents | 630,400 | 5.394 | 1,240 | 64 | 81 | | Gorazor | 4,209,751 | 0.852 | 512 | 5 | 82 | | HB | 735,676 | 4.749 | 1,984 | 36 | 83 | | Hero | 30,954,032 | 0.120 | 0 | 0 | 84 | | Jade | 38,540,751 | 0.083 | 0 | 0 | 85 | | Quicktemplate | 17,429,122 | 0.183 | 0 | 0 | 86 | | Templ | 6,126,406 | 0.575 | 96 | 2 | 87 | 88 | 89 | ## more complex test with template inheritance (if possible) 90 | ### full featured template engines 91 | | Name | Runs | µs/op | B/op | allocations/op | 92 | | ----------------- | ------- | ------ | ----- | -------------- | 93 | | ComplexGolang | 49,784 | 72.503 | 6,565 | 290 | 94 | | ComplexGolangText | 120,789 | 32.198 | 2,236 | 107 | 95 | | ComplexJetHTML | 287,542 | 12.108 | 535 | 5 | 96 | | ComplexMustache | 128,841 | 27.375 | 7,275 | 156 | 97 | 98 | 99 | ### precompilation to Go code 100 | | Name | Runs | µs/op | B/op | allocations/op | 101 | | --------------------- | --------- | ----- | ----- | -------------- | 102 | | ComplexEgo | 1,000,000 | 5.352 | 569 | 31 | 103 | | ComplexFtmpl | 512,026 | 7.545 | 3,536 | 38 | 104 | | ComplexGoDirectBuffer | 6,203,253 | 0.543 | 0 | 0 | 105 | | ComplexGoh | 6,074,386 | 0.569 | 0 | 0 | 106 | | ComplexGorazor | 636,561 | 5.653 | 3,688 | 24 | 107 | | ComplexHero | 3,706,204 | 0.955 | 0 | 0 | 108 | | ComplexJade | 4,795,210 | 0.708 | 0 | 0 | 109 | | ComplexQuicktemplate | 3,466,336 | 1.012 | 0 | 0 | 110 | | ComplexTempl | 1,265,850 | 2.790 | 408 | 11 | 111 | 112 | ## Security 113 | 114 | All packages assume that template authors are trusted. If you allow custom 115 | templates you have to sanitize your user input e.g. 116 | [bluemonday](https://github.com/microcosm-cc/bluemonday). Generally speaking I 117 | would suggest to sanitize every input not just HTML-input. 118 | 119 | ### Attention: This part is not updated since 2016. 120 | 121 | | Framework | Security | Comment | 122 | | ------------- | ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | 123 | | Ace | No | | 124 | | amber | No | | 125 | | ego | Partial (html.EscapeString) | only HTML, others need to be called manually | 126 | | egon | Partial (html.EscapeString) | only HTML, others need to be called manually | 127 | | egonslinso | Partial (html.EscapeString) | only HTML, others need to be called manually | 128 | | ftmpl | Partial (html.EscapeString) | only HTML, others need to be called manually | 129 | | Go | Yes | contextual escaping [html/template Security Model](https://golang.org/pkg/html/template/#hdr-Security_Model) | 130 | | Gorazor | Partial (template.HTMLEscapeString) | only HTML, others need to be called manually | 131 | | Handlebars | Partial (raymond.escape) | only HTML | 132 | | Hero | Partial (html.EscapeString) | only HTML, others need to be called manually | 133 | | Jade | Partial (html.EscapeString) | Autoescape for HTML, others need to be called manually | 134 | | Jet | Partial (html.EscapeString) | Autoescape for HTML, others need to be called manually | 135 | | Kasia | Partial (kasia.WriteEscapedHtml) | only HTML | 136 | | Mustache | Partial (template.HTMLEscape) | only HTML | 137 | | Pongo2 | Partial (pongo2.filterEscape, pongo2.filterEscapejs) | autoescape only escapes HTML, others could be implemented as pongo filters | 138 | | Quicktemplate | Partial (html.EscapeString) | only HTML, others need to be called manually | 139 | | Soy | Partial (template.HTMLEscapeString, url.QueryEscape, template.JSEscapeString) | autoescape only escapes HTML, contextual escaping is defined as a project goal | 140 | -------------------------------------------------------------------------------- /ace/simple.ace: -------------------------------------------------------------------------------- 1 | html 2 | body 3 | h1 {{.FirstName}} 4 | 5 | p Here's a list of your favorite colors: 6 | ul 7 | {{range .FavoriteColors }} 8 | li {{.}} 9 | {{ end }} -------------------------------------------------------------------------------- /amber/simple.amber: -------------------------------------------------------------------------------- 1 | html 2 | body 3 | h1 #{FirstName} 4 | 5 | p Here's a list of your favorite colors: 6 | ul 7 | each $colorName in FavoriteColors 8 | li #{$colorName} -------------------------------------------------------------------------------- /bench.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # This file: 3 | # 4 | # - Run the benchmarks and output github compatible markdown for the readme.md 5 | # 6 | # Usage: 7 | # 8 | # ./bench.sh 9 | # 10 | # Testing: 11 | # only run the benchmarks 12 | # ./bench.sh -O -F 13 | # 14 | # Based on a template by BASH3 Boilerplate v2.3.0 15 | # http://bash3boilerplate.sh/#authors 16 | # 17 | # The MIT License (MIT) 18 | # Copyright (c) 2013 Kevin van Zonneveld and contributors 19 | # You are not obligated to bundle the LICENSE file with your b3bp projects as long 20 | # as you leave these references intact in the header comments of your source files. 21 | 22 | # shellcheck disable=SC2034 23 | read -r -d '' __usage <<-'EOF' || true # exits non-zero when EOF encountered 24 | -t --time [arg] Benchmark duration. Required. Default="3s" 25 | -c --compare [arg] Old go version binary? Required. 26 | -n --count [arg] Number of runs for comparison. Default=1 27 | -g --go [arg] Curenct go version binary? Required. Default="go" 28 | -B --no-benchmarks Do NOT run the benchmarks. 29 | -F --no-format Do NOT format the results. 30 | -u --update update dependencies. 31 | -v Enable verbose mode, print script as it is executed 32 | -d --debug Enables debug mode 33 | -h --help This page 34 | EOF 35 | 36 | # shellcheck disable=SC2034 37 | read -r -d '' __helptext <<-'EOF' || true # exits non-zero when EOF encountered 38 | This is Bash3 Boilerplate's help text. Feel free to add any description of your 39 | program or elaborate more on command-line arguments. This section is not 40 | parsed and will be added as-is to the help. 41 | EOF 42 | 43 | # shellcheck source=main.sh 44 | source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/main.sh" 45 | 46 | ### Signal trapping and backtracing 47 | ############################################################################## 48 | 49 | # requires `set -o errtrace` 50 | __b3bp_err_report() { 51 | local error_code=${?} 52 | # shellcheck disable=SC2154 53 | error "Error in ${__file} in function ${1} on line ${2}" 54 | exit ${error_code} 55 | } 56 | # Uncomment the following line for always providing an error backtrace 57 | trap '__b3bp_err_report "${FUNCNAME:-.}" ${LINENO}' ERR 58 | 59 | ### Command-line argument switches (like -d for debugmode, -h for showing helppage) 60 | ############################################################################## 61 | 62 | # debug mode 63 | if [[ "${arg_d:?}" == "1" ]]; then 64 | set -o xtrace 65 | PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }' 66 | LOG_LEVEL="7" 67 | # Enable error backtracing 68 | trap '__b3bp_err_report "${FUNCNAME:-.}" ${LINENO}' ERR 69 | fi 70 | 71 | # verbose mode 72 | if [[ "${arg_v:?}" == "1" ]]; then 73 | set -o verbose 74 | fi 75 | 76 | # help mode 77 | if [[ "${arg_h:?}" == "1" ]]; then 78 | # Help exists with code 1 79 | help "Help using ${0}" 80 | fi 81 | 82 | __no_benchmarks="false" 83 | if [[ "${arg_B:?}" == "1" ]]; then 84 | __no_benchmarks="true" 85 | fi 86 | 87 | __no_format="false" 88 | if [[ "${arg_F:?}" == "1" ]]; then 89 | __no_format="true" 90 | fi 91 | 92 | ### Validation. Error out if the things required for your script are not present 93 | ############################################################################## 94 | 95 | [[ "${arg_t:-}" ]] || help "Setting benchmark druation with -t or --time is required" 96 | [[ "${arg_c:-}" ]] || help "Setting go versions which will be compared with -c or --compare is required" 97 | [[ "${arg_g:-}" ]] || help "Setting go versions which will be compared with -g or --go is required" 98 | [[ "${LOG_LEVEL:-}" ]] || emergency "Cannot continue without LOG_LEVEL. " 99 | 100 | ### Runtime 101 | ############################################################################## 102 | 103 | info "OSTYPE: ${OSTYPE}" 104 | 105 | info "benchmark duration: ${arg_t}" 106 | info "compare: ${arg_c} to ${arg_g}" 107 | info "count: ${arg_n}" 108 | info "run benchmarks: $([[ "${__no_benchmarks}" == "true" ]] && echo "false" || echo "true")" 109 | info "format output: $([[ "${__no_format}" == "true" ]] && echo "false" || echo "true")" 110 | 111 | # TODO: check if specific go versions are installed, otherise install 112 | # go install golang.org/dl/go1.10.7@latest 113 | # go1.10.7 download 114 | 115 | _updateDeps() { 116 | info "Update dependencies" 117 | go get -u -v ./... 118 | 119 | go install -v github.com/tkrajina/ftmpl@master 120 | ftmpl ftmpl/ 121 | 122 | go install -v github.com/sipin/gorazor@main 123 | gorazor -prefix github.com/SlinSo/goTemplateBenchmark gorazor gorazor 124 | 125 | go install -v github.com/valyala/quicktemplate/qtc@master 126 | qtc -dir quicktemplate 127 | 128 | go install -v github.com/benbjohnson/ego/cmd/ego@master 129 | ego ego 130 | 131 | go install -v github.com/shiyanhui/hero/hero@master 132 | hero -source hero/ 133 | 134 | # update jade manually 135 | go install -v github.com/Joker/jade/cmd/jade@latest 136 | 137 | jade -d jade/ jade/simple.jade 138 | jade -d jade/ jade/index.jade 139 | 140 | go install github.com/OblivionOcean/Goh@main 141 | 142 | go mod tidy 143 | go test . 144 | } 145 | [[ "${arg_u:?}" == "1" ]] && _updateDeps 146 | 147 | # run old benchmarks 148 | _run_old_benchmarks() { 149 | ${arg_c} test -bench "k(Ace|Amber|Golang|GolangText|Handlebars|Mustache|Pongo2|Soy|JetHTML)$" -benchmem -benchtime="${arg_t}" -count="${arg_n}" | tee ./files/results-1.old 150 | ${arg_c} test -bench "k(Ego|Quicktemplate|Ftmpl|Goh|Gorazor|Hero|Jade|HB|Gomponents|Templ)$" -benchmem -benchtime="${arg_t}" -count="${arg_n}" | tee ./files/results-2.old 151 | ${arg_c} test -bench "Complex(Ace|Amber|Golang|GolangText|Handlebars|Mustache|Pongo2|Soy|JetHTML)$" -benchmem -benchtime="${arg_t}" -count="${arg_n}" | tee ./files/results-3.old 152 | ${arg_c} test -bench "Complex(Ego|Quicktemplate|Ftmpl|Goh|Gorazor|Hero|Jade|Templ|GoDirectBuffer)$" -benchmem -benchtime="${arg_t}" -count="${arg_n}" | tee ./files/results-4.old 153 | } 154 | # [[ "${__no_benchmarks}" == "true" ]] || _run_old_benchmarks 155 | 156 | # run benchmarks 157 | _run_benchmarks() { 158 | ${arg_g} test -bench "k(Ace|Amber|Golang|GolangText|Handlebars|Mustache|Pongo2|Soy|JetHTML)$" -benchmem -benchtime="${arg_t}" -count="${arg_n}" | tee ./files/results-1.new 159 | ${arg_g} test -bench "k(Ego|Quicktemplate|Ftmpl|Goh|Gorazor|Hero|Jade|HB|Gomponents|Templ)$" -benchmem -benchtime="${arg_t}" -count="${arg_n}" | tee ./files/results-2.new 160 | ${arg_g} test -bench "Complex(Ace|Amber|Golang|GolangText|Handlebars|Mustache|Pongo2|Soy|JetHTML)$" -benchmem -benchtime="${arg_t}" -count="${arg_n}" | tee ./files/results-3.new 161 | ${arg_g} test -bench "Complex(Ego|Quicktemplate|Ftmpl|Goh|Gorazor|Hero|Jade|Templ|GoDirectBuffer)$" -benchmem -benchtime="${arg_t}" -count="${arg_n}" | tee ./files/results-4.new 162 | } 163 | [[ "${__no_benchmarks}" == "true" ]] || _run_benchmarks 164 | 165 | # formats a single benchmark 166 | # $1: number of the benchmark 167 | __format_single_benchmark() { 168 | local i=${1} 169 | pb <./files/results-"${i}".new | grep \| | sed '/Name/a \| --- \| --- \| --- \| --- \| --- \|' 170 | echo "" 171 | # echo "\`\`\`" 172 | # echo "comparing: ${arg_c} to ${arg_g}" 173 | # benchstat files/results-"${i}".old files/results-"${i}".new | tee files/results-"${i}"-benchstat.txt 174 | # echo "\`\`\`" 175 | } 176 | 177 | # pretty print for readme.md 178 | _format_benchmarks() { 179 | echo "" 180 | echo "## simple benchmarks" 181 | echo "### full featured template engines" 182 | __format_single_benchmark 1 183 | 184 | echo "" 185 | echo "### precompilation to Go code" 186 | __format_single_benchmark 2 187 | 188 | echo "" 189 | echo "## more complex test with template inheritance (if possible)" 190 | echo "### full featured template engines" 191 | __format_single_benchmark 3 192 | 193 | echo "" 194 | echo "### precompilation to Go code" 195 | __format_single_benchmark 4 196 | } 197 | [[ "${__no_format}" == "true" ]] || _format_benchmarks 198 | -------------------------------------------------------------------------------- /ego/footer.ego: -------------------------------------------------------------------------------- 1 | <% package ego 2 | 3 | func EgoFooter(w io.Writer) { %> 4 | 5 | <% } %> -------------------------------------------------------------------------------- /ego/footer.ego.go: -------------------------------------------------------------------------------- 1 | // Generated by ego. 2 | // DO NOT EDIT 3 | 4 | //line ego/footer.ego:1 5 | package ego 6 | 7 | import "fmt" 8 | import "html" 9 | import "io" 10 | import 11 | 12 | //line ego/footer.ego:4 13 | "context" 14 | 15 | func EgoFooter(w io.Writer) { 16 | 17 | _, _ = io.WriteString(w, "\n
copyright 2016
\n") 18 | //line ego/footer.ego:5 19 | } 20 | 21 | var _ fmt.Stringer 22 | var _ io.Reader 23 | var _ context.Context 24 | var _ = html.EscapeString 25 | -------------------------------------------------------------------------------- /ego/header.ego: -------------------------------------------------------------------------------- 1 | <% package ego 2 | 3 | func EgoHeader(w io.Writer, title string) { %> 4 | <%= title %>'s Home Page 5 |
Page Header
6 | <% } %> -------------------------------------------------------------------------------- /ego/header.ego.go: -------------------------------------------------------------------------------- 1 | // Generated by ego. 2 | // DO NOT EDIT 3 | 4 | //line ego/header.ego:1 5 | package ego 6 | 7 | import "fmt" 8 | import "html" 9 | import "io" 10 | import "context" 11 | 12 | func EgoHeader(w io.Writer, title string) { 13 | //line ego/header.ego:4 14 | _, _ = io.WriteString(w, "\n") 15 | //line ego/header.ego:4 16 | _, _ = io.WriteString(w, html.EscapeString(fmt.Sprint(title))) 17 | //line ego/header.ego:4 18 | _, _ = io.WriteString(w, "'s Home Page\n
Page Header
\n") 19 | //line ego/header.ego:6 20 | } 21 | 22 | var _ fmt.Stringer 23 | var _ io.Reader 24 | var _ context.Context 25 | var _ = html.EscapeString 26 | -------------------------------------------------------------------------------- /ego/index.ego: -------------------------------------------------------------------------------- 1 | <% package ego 2 | import "github.com/SlinSo/goTemplateBenchmark/model" 3 | 4 | func EgoComplex(w io.Writer, u *model.User, nav []*model.Navigation, title string) { %> 5 | 6 | 7 | 8 | 9 |
10 | <% EgoHeader(w, title) %> 11 |
12 | 13 | 16 | 17 |
18 |
19 |
20 |

Hello <%= u.FirstName %>

21 | 22 |
<%== u.RawContent %>
23 |
<%= u.EscapedContent %>
24 |
25 | 26 | <% 27 | for i := 1; i <= 5; i++ { 28 | if i == 1 { %> 29 |

<%=u.FirstName%> has <%=i%> message

30 | <% } else { %> 31 |

<%=u.FirstName%> has <%=i%> messages

32 | <% } 33 | } 34 | %> 35 |
36 |
37 | 38 | 41 | 42 | 43 | 44 | <% } %> -------------------------------------------------------------------------------- /ego/index.ego.go: -------------------------------------------------------------------------------- 1 | // Generated by ego. 2 | // DO NOT EDIT 3 | 4 | //line ego/index.ego:1 5 | package ego 6 | 7 | import "fmt" 8 | import "html" 9 | import "io" 10 | import "context" 11 | import "github.com/SlinSo/goTemplateBenchmark/model" 12 | 13 | func EgoComplex(w io.Writer, u *model.User, nav []*model.Navigation, title string) { 14 | //line ego/index.ego:5 15 | _, _ = io.WriteString(w, "\n\n\n\n\n
\n") 16 | //line ego/index.ego:10 17 | EgoHeader(w, title) 18 | //line ego/index.ego:11 19 | _, _ = io.WriteString(w, "\n
\n\n\n\n
\n
\n\t
\n\t\t

Hello ") 24 | //line ego/index.ego:20 25 | _, _ = io.WriteString(w, html.EscapeString(fmt.Sprint(u.FirstName))) 26 | //line ego/index.ego:20 27 | _, _ = io.WriteString(w, "

\n\t\t\n\t\t
") 28 | //line ego/index.ego:22 29 | _, _ = fmt.Fprint(w, u.RawContent) 30 | //line ego/index.ego:22 31 | _, _ = io.WriteString(w, "
\n\t\t
") 32 | //line ego/index.ego:23 33 | _, _ = io.WriteString(w, html.EscapeString(fmt.Sprint(u.EscapedContent))) 34 | //line ego/index.ego:23 35 | _, _ = io.WriteString(w, "
\n\t
\n\n") 36 | //line ego/index.ego:26 37 | 38 | for i := 1; i <= 5; i++ { 39 | if i == 1 { 40 | //line ego/index.ego:29 41 | _, _ = io.WriteString(w, "\n\t\t\t

") 42 | //line ego/index.ego:29 43 | _, _ = io.WriteString(w, html.EscapeString(fmt.Sprint(u.FirstName))) 44 | //line ego/index.ego:29 45 | _, _ = io.WriteString(w, " has ") 46 | //line ego/index.ego:29 47 | _, _ = io.WriteString(w, html.EscapeString(fmt.Sprint(i))) 48 | //line ego/index.ego:29 49 | _, _ = io.WriteString(w, " message

\n\t") 50 | //line ego/index.ego:30 51 | } else { 52 | //line ego/index.ego:31 53 | _, _ = io.WriteString(w, "\n\t\t\t

") 54 | //line ego/index.ego:31 55 | _, _ = io.WriteString(w, html.EscapeString(fmt.Sprint(u.FirstName))) 56 | //line ego/index.ego:31 57 | _, _ = io.WriteString(w, " has ") 58 | //line ego/index.ego:31 59 | _, _ = io.WriteString(w, html.EscapeString(fmt.Sprint(i))) 60 | //line ego/index.ego:31 61 | _, _ = io.WriteString(w, " messages

\n\t\t") 62 | //line ego/index.ego:32 63 | } 64 | } 65 | 66 | //line ego/index.ego:35 67 | _, _ = io.WriteString(w, "\n
\n
\n\n\n\n\n\n") 72 | //line ego/index.ego:44 73 | } 74 | 75 | var _ fmt.Stringer 76 | var _ io.Reader 77 | var _ context.Context 78 | var _ = html.EscapeString 79 | -------------------------------------------------------------------------------- /ego/navigation.ego: -------------------------------------------------------------------------------- 1 | <% package ego 2 | import "github.com/SlinSo/goTemplateBenchmark/model" 3 | 4 | func EgoNavigation(w io.Writer, nav []*model.Navigation) { %> 5 | 11 | <% } %> 12 | -------------------------------------------------------------------------------- /ego/navigation.ego.go: -------------------------------------------------------------------------------- 1 | // Generated by ego. 2 | // DO NOT EDIT 3 | 4 | //line ego/navigation.ego:1 5 | package ego 6 | 7 | import "fmt" 8 | import "html" 9 | import "io" 10 | import "context" 11 | import "github.com/SlinSo/goTemplateBenchmark/model" 12 | 13 | func EgoNavigation(w io.Writer, nav []*model.Navigation) { 14 | //line ego/navigation.ego:5 15 | _, _ = io.WriteString(w, "\n\n") 33 | //line ego/navigation.ego:11 34 | } 35 | 36 | var _ fmt.Stringer 37 | var _ io.Reader 38 | var _ context.Context 39 | var _ = html.EscapeString 40 | -------------------------------------------------------------------------------- /ego/simple.ego: -------------------------------------------------------------------------------- 1 | <% package ego 2 | import "github.com/SlinSo/goTemplateBenchmark/model" 3 | 4 | func EgoSimple(w io.Writer, u *model.User) { %> 5 | 6 | 7 |

<%= u.FirstName %>

8 | 9 |

Here's a list of your favorite colors:

10 | 14 | 15 | 16 | <% } %> -------------------------------------------------------------------------------- /ego/simple.ego.go: -------------------------------------------------------------------------------- 1 | // Generated by ego. 2 | // DO NOT EDIT 3 | 4 | //line ego/simple.ego:1 5 | package ego 6 | 7 | import "fmt" 8 | import "html" 9 | import "io" 10 | import "context" 11 | import "github.com/SlinSo/goTemplateBenchmark/model" 12 | 13 | func EgoSimple(w io.Writer, u *model.User) { 14 | //line ego/simple.ego:5 15 | _, _ = io.WriteString(w, "\n\n \n

") 16 | //line ego/simple.ego:7 17 | _, _ = io.WriteString(w, html.EscapeString(fmt.Sprint(u.FirstName))) 18 | //line ego/simple.ego:7 19 | _, _ = io.WriteString(w, "

\n\n

Here's a list of your favorite colors:

\n \n \n\n") 32 | //line ego/simple.ego:16 33 | } 34 | 35 | var _ fmt.Stringer 36 | var _ io.Reader 37 | var _ context.Context 38 | var _ = html.EscapeString 39 | -------------------------------------------------------------------------------- /ftmpl/base.go: -------------------------------------------------------------------------------- 1 | // Package ftmpl is generated with ftmpl {{{v0.3.1}}}, do not edit!!!! */ 2 | package ftmpl 3 | 4 | import ( 5 | "bytes" 6 | "errors" 7 | "fmt" 8 | "github.com/SlinSo/goTemplateBenchmark/model" 9 | "html" 10 | "os" 11 | ) 12 | 13 | func init() { 14 | _ = fmt.Sprintf 15 | _ = errors.New 16 | _ = os.Stderr 17 | _ = html.EscapeString 18 | } 19 | 20 | // TMPLERRbase evaluates a template base.tmpl 21 | func TMPLERRbase(u *model.User, nav []*model.Navigation, title string) (string, error) { 22 | _template := "base.tmpl" 23 | _escape := html.EscapeString 24 | var _ftmpl bytes.Buffer 25 | _w := func(str string) { _, _ = _ftmpl.WriteString(str) } 26 | _, _, _ = _template, _escape, _w 27 | 28 | _w(` 29 | 30 | 31 | 32 |
33 | `) 34 | _w(`
35 | 36 | 39 | 40 |
41 | `) 42 | _w(`
43 | 44 | 47 | 48 | 49 | `) 50 | 51 | return _ftmpl.String(), nil 52 | } 53 | 54 | // TMPLbase evaluates a template base.tmpl 55 | func TMPLbase(u *model.User, nav []*model.Navigation, title string) string { 56 | html, err := TMPLERRbase(u, nav, title) 57 | if err != nil { 58 | _, _ = os.Stderr.WriteString("Error running template base.tmpl:" + err.Error()) 59 | } 60 | return html 61 | } 62 | -------------------------------------------------------------------------------- /ftmpl/base.tmpl: -------------------------------------------------------------------------------- 1 | !#import "github.com/SlinSo/goTemplateBenchmark/model" 2 | !#arg u *model.User 3 | !#arg nav []*model.Navigation 4 | !#arg title string 5 | 6 | 7 | 8 | 9 |
10 | !#include header 11 |
12 | 13 | 16 | 17 |
18 | !#include body 19 |
20 | 21 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /ftmpl/basecontent.go: -------------------------------------------------------------------------------- 1 | // Package ftmpl is generated with ftmpl {{{v0.3.1}}}, do not edit!!!! */ 2 | package ftmpl 3 | 4 | import ( 5 | "bytes" 6 | "errors" 7 | "fmt" 8 | "github.com/SlinSo/goTemplateBenchmark/model" 9 | "html" 10 | "os" 11 | ) 12 | 13 | func init() { 14 | _ = fmt.Sprintf 15 | _ = errors.New 16 | _ = os.Stderr 17 | _ = html.EscapeString 18 | } 19 | 20 | // TMPLERRbasecontent evaluates a template basecontent.tmpl 21 | func TMPLERRbasecontent(u *model.User, nav []*model.Navigation, title string) (string, error) { 22 | _template := "basecontent.tmpl" 23 | _escape := html.EscapeString 24 | var _ftmpl bytes.Buffer 25 | _w := func(str string) { _, _ = _ftmpl.WriteString(str) } 26 | _, _, _ = _template, _escape, _w 27 | 28 | _w(` 29 | `) 30 | _w(` 31 | 32 | 33 | 34 |
35 | `) 36 | _w(``) 37 | _w(fmt.Sprintf(`%s`, _escape(title))) 38 | _w(`'s Home Page 39 |
Page Header
40 | 41 | `) 42 | _w(`
43 | 44 | 60 | 61 |
62 | `) 63 | _w(`
64 | 65 | 71 | 72 | 73 | `) 74 | 75 | return _ftmpl.String(), nil 76 | } 77 | 78 | // TMPLbasecontent evaluates a template basecontent.tmpl 79 | func TMPLbasecontent(u *model.User, nav []*model.Navigation, title string) string { 80 | html, err := TMPLERRbasecontent(u, nav, title) 81 | if err != nil { 82 | _, _ = os.Stderr.WriteString("Error running template basecontent.tmpl:" + err.Error()) 83 | } 84 | return html 85 | } 86 | -------------------------------------------------------------------------------- /ftmpl/basecontent.tmpl: -------------------------------------------------------------------------------- 1 | !#extends base 2 | 3 | !#sub header 4 | !#arg title string 5 | {{s title}}'s Home Page 6 |
Page Header
7 | 8 | !#sub footer 9 | 10 | 11 | !#sub navigation 12 | !#import "github.com/SlinSo/goTemplateBenchmark/model" 13 | !#arg nav []*model.Navigation 14 | -------------------------------------------------------------------------------- /ftmpl/footer.go: -------------------------------------------------------------------------------- 1 | // Package ftmpl is generated with ftmpl {{{v0.3.1}}}, do not edit!!!! */ 2 | package ftmpl 3 | 4 | import ( 5 | "bytes" 6 | "errors" 7 | "fmt" 8 | "html" 9 | "os" 10 | ) 11 | 12 | func init() { 13 | _ = fmt.Sprintf 14 | _ = errors.New 15 | _ = os.Stderr 16 | _ = html.EscapeString 17 | } 18 | 19 | // TMPLERRfooter evaluates a template footer.tmpl 20 | func TMPLERRfooter() (string, error) { 21 | _template := "footer.tmpl" 22 | _escape := html.EscapeString 23 | var _ftmpl bytes.Buffer 24 | _w := func(str string) { _, _ = _ftmpl.WriteString(str) } 25 | _, _, _ = _template, _escape, _w 26 | 27 | _w(``) 28 | 29 | return _ftmpl.String(), nil 30 | } 31 | 32 | // TMPLfooter evaluates a template footer.tmpl 33 | func TMPLfooter() string { 34 | html, err := TMPLERRfooter() 35 | if err != nil { 36 | _, _ = os.Stderr.WriteString("Error running template footer.tmpl:" + err.Error()) 37 | } 38 | return html 39 | } 40 | -------------------------------------------------------------------------------- /ftmpl/footer.tmpl: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ftmpl/header.go: -------------------------------------------------------------------------------- 1 | // Package ftmpl is generated with ftmpl {{{v0.3.1}}}, do not edit!!!! */ 2 | package ftmpl 3 | 4 | import ( 5 | "bytes" 6 | "errors" 7 | "fmt" 8 | "html" 9 | "os" 10 | ) 11 | 12 | func init() { 13 | _ = fmt.Sprintf 14 | _ = errors.New 15 | _ = os.Stderr 16 | _ = html.EscapeString 17 | } 18 | 19 | // TMPLERRheader evaluates a template header.tmpl 20 | func TMPLERRheader(title string) (string, error) { 21 | _template := "header.tmpl" 22 | _escape := html.EscapeString 23 | var _ftmpl bytes.Buffer 24 | _w := func(str string) { _, _ = _ftmpl.WriteString(str) } 25 | _, _, _ = _template, _escape, _w 26 | 27 | _w(``) 28 | _w(fmt.Sprintf(`%s`, _escape(title))) 29 | _w(`'s Home Page 30 |
Page Header
`) 31 | 32 | return _ftmpl.String(), nil 33 | } 34 | 35 | // TMPLheader evaluates a template header.tmpl 36 | func TMPLheader(title string) string { 37 | html, err := TMPLERRheader(title) 38 | if err != nil { 39 | _, _ = os.Stderr.WriteString("Error running template header.tmpl:" + err.Error()) 40 | } 41 | return html 42 | } 43 | -------------------------------------------------------------------------------- /ftmpl/header.tmpl: -------------------------------------------------------------------------------- 1 | !#arg title string 2 | {{s title}}'s Home Page 3 |
Page Header
-------------------------------------------------------------------------------- /ftmpl/index.go: -------------------------------------------------------------------------------- 1 | // Package ftmpl is generated with ftmpl {{{v0.3.1}}}, do not edit!!!! */ 2 | package ftmpl 3 | 4 | import ( 5 | "bytes" 6 | "errors" 7 | "fmt" 8 | "github.com/SlinSo/goTemplateBenchmark/model" 9 | "html" 10 | "os" 11 | ) 12 | 13 | func init() { 14 | _ = fmt.Sprintf 15 | _ = errors.New 16 | _ = os.Stderr 17 | _ = html.EscapeString 18 | } 19 | 20 | // TMPLERRindex evaluates a template index.tmpl 21 | func TMPLERRindex(u *model.User, nav []*model.Navigation, title string) (string, error) { 22 | _template := "index.tmpl" 23 | _escape := html.EscapeString 24 | var _ftmpl bytes.Buffer 25 | _w := func(str string) { _, _ = _ftmpl.WriteString(str) } 26 | _, _, _ = _template, _escape, _w 27 | 28 | _w(` 29 | `) 30 | _w(` 31 | 32 | 33 | 34 |
35 | `) 36 | _w(``) 37 | _w(fmt.Sprintf(`%s`, _escape(title))) 38 | _w(`'s Home Page 39 |
Page Header
40 | 41 | `) 42 | _w(`
43 | 44 | 62 | 63 |
64 | `) 65 | _w(`
66 |
67 |

Hello `) 68 | _w(fmt.Sprintf(`%s`, _escape(u.FirstName))) 69 | _w(`

70 | 71 |
`) 72 | _w(fmt.Sprintf(`%s`, u.RawContent)) 73 | _w(`
74 |
`) 75 | _w(fmt.Sprintf(`%s`, _escape(u.EscapedContent))) 76 | _w(`
77 |
78 | 79 | 80 | `) 81 | for i := 1; i <= 5; i++ { 82 | if i == 1 { 83 | _w(`

`) 84 | _w(fmt.Sprintf(`%s`, _escape(u.FirstName))) 85 | _w(` has `) 86 | _w(fmt.Sprintf(`%d`, i)) 87 | _w(` message

88 | `) 89 | } else { 90 | _w(`

`) 91 | _w(fmt.Sprintf(`%s`, _escape(u.FirstName))) 92 | _w(` has `) 93 | _w(fmt.Sprintf(`%d`, i)) 94 | _w(` messages

95 | `) 96 | } 97 | } 98 | _w(`
99 | `) 100 | _w(`
101 | 102 | 108 | 109 | 110 | `) 111 | 112 | return _ftmpl.String(), nil 113 | } 114 | 115 | // TMPLindex evaluates a template index.tmpl 116 | func TMPLindex(u *model.User, nav []*model.Navigation, title string) string { 117 | html, err := TMPLERRindex(u, nav, title) 118 | if err != nil { 119 | _, _ = os.Stderr.WriteString("Error running template index.tmpl:" + err.Error()) 120 | } 121 | return html 122 | } 123 | -------------------------------------------------------------------------------- /ftmpl/index.tmpl: -------------------------------------------------------------------------------- 1 | !#extends base 2 | 3 | !#sub header 4 | {{s title}}'s Home Page 5 |
Page Header
6 | 7 | !#sub footer 8 | 9 | 10 | !#sub navigation 11 | 16 | 17 | !#sub body 18 |
19 |
20 |

Hello {{s u.FirstName }}

21 | 22 |
{{=s u.RawContent }}
23 |
{{s u.EscapedContent }}
24 |
25 | 26 | 27 | ! for i := 1; i <= 5; i++ { 28 | ! if i == 1 { 29 |

{{s u.FirstName}} has {{d i}} message

30 | ! } else { 31 |

{{s u.FirstName}} has {{d i}} messages

32 | ! } 33 | ! } 34 |
35 | -------------------------------------------------------------------------------- /ftmpl/index2.go: -------------------------------------------------------------------------------- 1 | // Package ftmpl is generated with ftmpl {{{v0.3.1}}}, do not edit!!!! */ 2 | package ftmpl 3 | 4 | import ( 5 | "bytes" 6 | "errors" 7 | "fmt" 8 | "github.com/SlinSo/goTemplateBenchmark/model" 9 | "html" 10 | "os" 11 | ) 12 | 13 | func init() { 14 | _ = fmt.Sprintf 15 | _ = errors.New 16 | _ = os.Stderr 17 | _ = html.EscapeString 18 | } 19 | 20 | // TMPLERRindex2 evaluates a template index2.tmpl 21 | func TMPLERRindex2(u *model.User, nav []*model.Navigation, title string) (string, error) { 22 | _template := "index2.tmpl" 23 | _escape := html.EscapeString 24 | var _ftmpl bytes.Buffer 25 | _w := func(str string) { _, _ = _ftmpl.WriteString(str) } 26 | _, _, _ = _template, _escape, _w 27 | 28 | _w(` 29 | `) 30 | _w(` 31 | 32 | 33 | 34 |
35 | `) 36 | _w(``) 37 | _w(fmt.Sprintf(`%s`, _escape(title))) 38 | _w(`'s Home Page 39 |
Page Header
`) 40 | _w(` 41 | 42 | `) 43 | _w(`
44 | 45 | 64 | 65 |
66 | `) 67 | _w(`
68 |
69 |

Hello `) 70 | _w(fmt.Sprintf(`%s`, _escape(u.FirstName))) 71 | _w(`

72 | 73 |
`) 74 | _w(fmt.Sprintf(`%s`, u.RawContent)) 75 | _w(`
76 |
`) 77 | _w(fmt.Sprintf(`%s`, _escape(u.EscapedContent))) 78 | _w(`
79 |
80 | 81 | 82 | `) 83 | for i := 1; i <= 5; i++ { 84 | if i == 1 { 85 | _w(`

`) 86 | _w(fmt.Sprintf(`%s`, _escape(u.FirstName))) 87 | _w(` has `) 88 | _w(fmt.Sprintf(`%d`, i)) 89 | _w(` message

90 | `) 91 | } else { 92 | _w(`

`) 93 | _w(fmt.Sprintf(`%s`, _escape(u.FirstName))) 94 | _w(` has `) 95 | _w(fmt.Sprintf(`%d`, i)) 96 | _w(` messages

97 | `) 98 | } 99 | } 100 | _w(`
101 | `) 102 | _w(`
103 | 104 | 111 | 112 | 113 | `) 114 | 115 | return _ftmpl.String(), nil 116 | } 117 | 118 | // TMPLindex2 evaluates a template index2.tmpl 119 | func TMPLindex2(u *model.User, nav []*model.Navigation, title string) string { 120 | html, err := TMPLERRindex2(u, nav, title) 121 | if err != nil { 122 | _, _ = os.Stderr.WriteString("Error running template index2.tmpl:" + err.Error()) 123 | } 124 | return html 125 | } 126 | -------------------------------------------------------------------------------- /ftmpl/index2.tmpl: -------------------------------------------------------------------------------- 1 | !#extends base 2 | 3 | !#sub header 4 | {{!#insert "header.tmpl" }} 5 | 6 | !#sub footer 7 | {{!#insert "footer.tmpl" }} 8 | 9 | !#sub navigation 10 | {{!#insert "navigation.tmpl" }} 11 | 12 | !#sub body 13 |
14 |
15 |

Hello {{s u.FirstName }}

16 | 17 |
{{=s u.RawContent }}
18 |
{{s u.EscapedContent }}
19 |
20 | 21 | 22 | ! for i := 1; i <= 5; i++ { 23 | ! if i == 1 { 24 |

{{s u.FirstName}} has {{d i}} message

25 | ! } else { 26 |

{{s u.FirstName}} has {{d i}} messages

27 | ! } 28 | ! } 29 |
30 | -------------------------------------------------------------------------------- /ftmpl/navigation.go: -------------------------------------------------------------------------------- 1 | // Package ftmpl is generated with ftmpl {{{v0.3.1}}}, do not edit!!!! */ 2 | package ftmpl 3 | 4 | import ( 5 | "bytes" 6 | "errors" 7 | "fmt" 8 | "github.com/SlinSo/goTemplateBenchmark/model" 9 | "html" 10 | "os" 11 | ) 12 | 13 | func init() { 14 | _ = fmt.Sprintf 15 | _ = errors.New 16 | _ = os.Stderr 17 | _ = html.EscapeString 18 | } 19 | 20 | // TMPLERRnavigation evaluates a template navigation.tmpl 21 | func TMPLERRnavigation(nav []*model.Navigation) (string, error) { 22 | _template := "navigation.tmpl" 23 | _escape := html.EscapeString 24 | var _ftmpl bytes.Buffer 25 | _w := func(str string) { _, _ = _ftmpl.WriteString(str) } 26 | _, _, _ = _template, _escape, _w 27 | 28 | _w(``) 41 | 42 | return _ftmpl.String(), nil 43 | } 44 | 45 | // TMPLnavigation evaluates a template navigation.tmpl 46 | func TMPLnavigation(nav []*model.Navigation) string { 47 | html, err := TMPLERRnavigation(nav) 48 | if err != nil { 49 | _, _ = os.Stderr.WriteString("Error running template navigation.tmpl:" + err.Error()) 50 | } 51 | return html 52 | } 53 | -------------------------------------------------------------------------------- /ftmpl/navigation.tmpl: -------------------------------------------------------------------------------- 1 | !#import "github.com/SlinSo/goTemplateBenchmark/model" 2 | !#arg nav []*model.Navigation 3 | -------------------------------------------------------------------------------- /ftmpl/simple.go: -------------------------------------------------------------------------------- 1 | // Package ftmpl is generated with ftmpl {{{v0.3.1}}}, do not edit!!!! */ 2 | package ftmpl 3 | 4 | import ( 5 | "bytes" 6 | "errors" 7 | "fmt" 8 | "github.com/SlinSo/goTemplateBenchmark/model" 9 | "html" 10 | "os" 11 | ) 12 | 13 | func init() { 14 | _ = fmt.Sprintf 15 | _ = errors.New 16 | _ = os.Stderr 17 | _ = html.EscapeString 18 | } 19 | 20 | // TMPLERRsimple evaluates a template simple.tmpl 21 | func TMPLERRsimple(u *model.User) (string, error) { 22 | _template := "simple.tmpl" 23 | _escape := html.EscapeString 24 | var _ftmpl bytes.Buffer 25 | _w := func(str string) { _, _ = _ftmpl.WriteString(str) } 26 | _, _, _ = _template, _escape, _w 27 | 28 | _w(` 29 | 30 |

`) 31 | _w(fmt.Sprintf(`%s`, _escape(u.FirstName))) 32 | _w(`

33 | 34 |

Here's a list of your favorite colors:

35 | 45 | 46 | `) 47 | 48 | return _ftmpl.String(), nil 49 | } 50 | 51 | // TMPLsimple evaluates a template simple.tmpl 52 | func TMPLsimple(u *model.User) string { 53 | html, err := TMPLERRsimple(u) 54 | if err != nil { 55 | _, _ = os.Stderr.WriteString("Error running template simple.tmpl:" + err.Error()) 56 | } 57 | return html 58 | } 59 | -------------------------------------------------------------------------------- /ftmpl/simple.tmpl: -------------------------------------------------------------------------------- 1 | !#import "github.com/SlinSo/goTemplateBenchmark/model" 2 | !#arg u *model.User 3 | 4 | 5 |

{{s u.FirstName }}

6 | 7 |

Here's a list of your favorite colors:

8 | 12 | 13 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/SlinSo/goTemplateBenchmark 2 | 3 | go 1.23.0 4 | 5 | toolchain go1.23.6 6 | 7 | require ( 8 | github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible 9 | github.com/OblivionOcean/Goh v1.0.3 10 | github.com/a-h/templ v0.3.833 11 | github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible 12 | github.com/dchest/htmlmin v1.2.0 13 | github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385 14 | github.com/flosch/pongo2 v0.0.0-20200913210552-0d938eb266f3 15 | github.com/gouniverse/hb v1.83.3 16 | github.com/hoisie/mustache v0.0.0-20160804235033-6375acf62c69 17 | github.com/robfig/soy v0.0.0-20210708182426-5db4016fcbab 18 | github.com/shiyanhui/hero v0.0.2 19 | github.com/sipin/gorazor v1.2.2 20 | github.com/valyala/bytebufferpool v1.0.1-0.20180905182247-cdfbe9377474 21 | github.com/valyala/quicktemplate v1.8.0 22 | github.com/yosssi/ace v0.0.5 23 | maragu.dev/gomponents v1.0.0 24 | ) 25 | 26 | require ( 27 | github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53 // indirect 28 | github.com/dchest/cssmin v0.0.0-20151210170030-fb8d9b44afdc // indirect 29 | github.com/dchest/jsmin v0.0.0-20220218165748-59f39799265f // indirect 30 | github.com/fsnotify/fsnotify v1.7.0 // indirect 31 | github.com/kr/text v0.2.0 // indirect 32 | github.com/robertkrimen/otto v0.0.0-20210614181706-373ff5438452 // indirect 33 | github.com/robfig/gettext v0.0.0-20210319194541-81dadf19848b // indirect 34 | golang.org/x/net v0.34.0 // indirect 35 | golang.org/x/sys v0.29.0 // indirect 36 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect 37 | gopkg.in/yaml.v2 v2.4.0 // indirect 38 | ) 39 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53 h1:sR+/8Yb4slttB4vD+b9btVEnWgL3Q00OBTzVT8B9C0c= 2 | github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= 3 | github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible h1:rZgFj+Gtf3NMi/U5FvCvhzaxzW/TaPYgUYx3bAPz9DE= 4 | github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w= 5 | github.com/OblivionOcean/Goh v1.0.3 h1:qLxX2bhYBUV47jixxVrSKuqjGfzThkMcPYq/58w28DQ= 6 | github.com/OblivionOcean/Goh v1.0.3/go.mod h1:FRmIA1vHrY9KeF5RHIJ+XtLcPurq4C6xtFMs3RAmm9c= 7 | github.com/a-h/templ v0.3.833 h1:L/KOk/0VvVTBegtE0fp2RJQiBm7/52Zxv5fqlEHiQUU= 8 | github.com/a-h/templ v0.3.833/go.mod h1:cAu4AiZhtJfBjMY0HASlyzvkrtjnHWPeEsyGK2YYmfk= 9 | github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= 10 | github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible h1:Ppm0npCCsmuR9oQaBtRuZcmILVE74aXE+AmrJj8L2ns= 11 | github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= 12 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 13 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 14 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 15 | github.com/dchest/cssmin v0.0.0-20151210170030-fb8d9b44afdc h1:VBS1z48BFEe00G81z8MKOtwX7f/ISkuH38NscT8iVPw= 16 | github.com/dchest/cssmin v0.0.0-20151210170030-fb8d9b44afdc/go.mod h1:ABJPuor7YlcsHmvJ1QxX38e2NcufLY3hm0yXv+cy9sI= 17 | github.com/dchest/htmlmin v1.2.0 h1:0IC9DqQj2riphSYNlrSxwgBr8q5Qx81Dj0/GSHo9hus= 18 | github.com/dchest/htmlmin v1.2.0/go.mod h1:QylviOfB3doepxYcCxvu71oZe98jP0SrO5iiWKGvHxo= 19 | github.com/dchest/jsmin v0.0.0-20220218165748-59f39799265f h1:OGqDDftRTwrvUoL6pOG7rYTmWsTCvyEWFsMjg+HcOaA= 20 | github.com/dchest/jsmin v0.0.0-20220218165748-59f39799265f/go.mod h1:Dv9D0NUlAsaQcGQZa5kc5mqR9ua72SmA8VXi4cd+cBw= 21 | github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385 h1:clC1lXBpe2kTj2VHdaIu9ajZQe4kcEY9j0NsnDDBZ3o= 22 | github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= 23 | github.com/flosch/pongo2 v0.0.0-20200913210552-0d938eb266f3 h1:fmFk0Wt3bBxxwZnu48jqMdaOR/IZ4vdtJFuaFV8MpIE= 24 | github.com/flosch/pongo2 v0.0.0-20200913210552-0d938eb266f3/go.mod h1:bJWSKrZyQvfTnb2OudyUjurSG4/edverV7n82+K3JiM= 25 | github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= 26 | github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= 27 | github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= 28 | github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= 29 | github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 30 | github.com/gouniverse/hb v1.83.3 h1:26hEkS6/Hul8PkzgH8JZnQvFI/aWx7DuT3MFdgmjI/w= 31 | github.com/gouniverse/hb v1.83.3/go.mod h1:WDUCGoptHp/fAYT634lQ2846sGx88yXOOWMvlEaezYM= 32 | github.com/hoisie/mustache v0.0.0-20160804235033-6375acf62c69 h1:umaj0TCQ9lWUUKy2DxAhEzPbwd0jnxiw1EI2z3FiILM= 33 | github.com/hoisie/mustache v0.0.0-20160804235033-6375acf62c69/go.mod h1:zdLK9ilQRSMjSeLKoZ4BqUfBT7jswTGF8zRlKEsiRXA= 34 | github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= 35 | github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= 36 | github.com/klauspost/cpuid v0.0.0-20180405133222-e7e905edc00e/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= 37 | github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= 38 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 39 | github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= 40 | github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 41 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 42 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 43 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 44 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 45 | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= 46 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 47 | github.com/robertkrimen/otto v0.0.0-20191219234010-c382bd3c16ff/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY= 48 | github.com/robertkrimen/otto v0.0.0-20210614181706-373ff5438452 h1:ewTtJ72GFy2e0e8uyiDwMG3pKCS5mBh+hdSTYsPKEP8= 49 | github.com/robertkrimen/otto v0.0.0-20210614181706-373ff5438452/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY= 50 | github.com/robfig/gettext v0.0.0-20200526193151-a093425df149/go.mod h1:5KSZdCir8kQ33UwFOeBzxIXDVCb7ine4/iCMiJ9D1oQ= 51 | github.com/robfig/gettext v0.0.0-20210319194541-81dadf19848b h1:V1N1ZQEzu4ell92Avbw+KVlmfaQo60UvGAF0Z+tfRMo= 52 | github.com/robfig/gettext v0.0.0-20210319194541-81dadf19848b/go.mod h1:5KSZdCir8kQ33UwFOeBzxIXDVCb7ine4/iCMiJ9D1oQ= 53 | github.com/robfig/soy v0.0.0-20210708182426-5db4016fcbab h1:TlVjS8Eu05dVtQRiykqPE8G+Zm3752JpvOWE122eXEg= 54 | github.com/robfig/soy v0.0.0-20210708182426-5db4016fcbab/go.mod h1:VTQjKFKmnjdLvj+6scw5cZb/z7TCcEhk/THXjTDTrUc= 55 | github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= 56 | github.com/shiyanhui/hero v0.0.2 h1:RF8fwiIeWbVsdki8LCS905pxLjCQbOz/NcKE0g1ZOJc= 57 | github.com/shiyanhui/hero v0.0.2/go.mod h1:aBlyf5bmklQfvOmVQm5i04lIGFY7t2QYIJdqEMNGJZM= 58 | github.com/sipin/gorazor v1.2.2 h1:iAsGoBVNakC0VaMS+izk9YFPK5dzTtL5TZ4Q9fLDqYE= 59 | github.com/sipin/gorazor v1.2.2/go.mod h1:IjfAnNow6XFn9MAVnwvy7QqUQPPtJM7jz0WREmdgktU= 60 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 61 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 62 | github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= 63 | github.com/valyala/bytebufferpool v1.0.1-0.20180905182247-cdfbe9377474 h1:5x9cPAJaXVu7KpYQ5rcHWufoM4BK2e+3EbNv24URpbk= 64 | github.com/valyala/bytebufferpool v1.0.1-0.20180905182247-cdfbe9377474/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= 65 | github.com/valyala/fasthttp v1.2.0/go.mod h1:4vX61m6KN+xDduDNwXrhIAVZaZaZiQ1luJk8LWSxF3s= 66 | github.com/valyala/quicktemplate v1.1.1/go.mod h1:EH+4AkTd43SvgIbQHYu59/cJyxDoOVRUAfrukLPuGJ4= 67 | github.com/valyala/quicktemplate v1.8.0 h1:zU0tjbIqTRgKQzFY1L42zq0qR3eh4WoQQdIdqCysW5k= 68 | github.com/valyala/quicktemplate v1.8.0/go.mod h1:qIqW8/igXt8fdrUln5kOSb+KWMaJ4Y8QUsfd1k6L2jM= 69 | github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= 70 | github.com/yosssi/ace v0.0.5 h1:tUkIP/BLdKqrlrPwcmH0shwEEhTRHoGnc1wFIWmaBUA= 71 | github.com/yosssi/ace v0.0.5/go.mod h1:ALfIzm2vT7t5ZE7uoIZqF3TQ7SAOyupFZnkrF5id+K0= 72 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 73 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 74 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 75 | golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= 76 | golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= 77 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= 78 | golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= 79 | golang.org/x/net v0.0.0-20180911220305-26e67e76b6c3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 80 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 81 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 82 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 83 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 84 | golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= 85 | golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= 86 | golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= 87 | golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= 88 | golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= 89 | golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= 90 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 91 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 92 | golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 93 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 94 | golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 95 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 96 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 97 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 98 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 99 | golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 100 | golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 101 | golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 102 | golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 103 | golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= 104 | golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 105 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 106 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 107 | golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= 108 | golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= 109 | golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= 110 | golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= 111 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 112 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 113 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 114 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 115 | golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 116 | golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= 117 | golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= 118 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 119 | golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 120 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 121 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= 122 | golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= 123 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 124 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 125 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 126 | gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 127 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 128 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 129 | gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI= 130 | gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78= 131 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 132 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 133 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 134 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 135 | maragu.dev/gomponents v1.0.0 h1:eeLScjq4PqP1l+r5z/GC+xXZhLHXa6RWUWGW7gSfLh4= 136 | maragu.dev/gomponents v1.0.0/go.mod h1:oEDahza2gZoXDoDHhw8jBNgH+3UR5ni7Ur648HORydM= 137 | -------------------------------------------------------------------------------- /go/includes/base.tmpl: -------------------------------------------------------------------------------- 1 | {{ define "base" }} 2 | 3 | 4 | 5 | 6 |
7 | {{ template "header" . }} 8 |
9 | 10 | 13 | 14 |
15 | {{ template "content" .}} 16 |
17 | 18 | 21 | 22 | 23 | 24 | {{end}} -------------------------------------------------------------------------------- /go/includes/footer.tmpl: -------------------------------------------------------------------------------- 1 | {{ define "footer" }} 2 | 3 | {{ end }} -------------------------------------------------------------------------------- /go/includes/header.tmpl: -------------------------------------------------------------------------------- 1 | {{ define "header" }} 2 | {{ .Title }}'s Home Page 3 |
Page Header
4 | {{ end }} -------------------------------------------------------------------------------- /go/includes/navigation.tmpl: -------------------------------------------------------------------------------- 1 | {{ define "navigation" }} 2 | 7 | {{ end }} -------------------------------------------------------------------------------- /go/layout/index.tmpl: -------------------------------------------------------------------------------- 1 | {{ define "title"}}{{ .u.FirstName }}{{ end }} 2 | {{ define "content" }} 3 | 4 |
5 |
6 |

Hello {{ .User.FirstName }}

7 | 8 |
{{ .User.RawContent |safehtml}}
9 |
{{ .User.EscapedContent }}
10 |
11 | {{range .Messages}} 12 | {{if eq .I 1}} 13 |

{{ $.User.FirstName}} has {{ .I }} message

14 | {{else}} 15 |

{{ $.User.FirstName}} has {{ .I }} messages

16 | {{end}} 17 | {{end}} 18 |
19 | {{ end }} -------------------------------------------------------------------------------- /go/simple.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 |

{{ .FirstName }}

4 | 5 |

Here's a list of your favorite colors:

6 | 10 | 11 | -------------------------------------------------------------------------------- /goh/footer.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /goh/footer.html.go: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT! 2 | // Generate By Goh 3 | 4 | package template 5 | -------------------------------------------------------------------------------- /goh/header.html: -------------------------------------------------------------------------------- 1 | <%= title %>'s Home Page 2 |
Page Header
3 | -------------------------------------------------------------------------------- /goh/header.html.go: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT! 2 | // Generate By Goh 3 | 4 | package template 5 | -------------------------------------------------------------------------------- /goh/index.html: -------------------------------------------------------------------------------- 1 | <%: func Index(u *model.User, nav []*model.Navigation, title string, buffer *bytes.Buffer) %> 2 | 3 | <%! 4 | import "github.com/SlinSo/goTemplateBenchmark/model" 5 | %> 6 | 7 | 8 | 9 | 10 | 11 |
12 | <%+ "header.html" %> 13 |
14 | 15 | 18 | 19 |
20 |
21 |
22 |

Hello <%= u.FirstName %>

23 | 24 |
<%== u.RawContent %>
25 |
<%= u.EscapedContent %>
26 |
27 | 28 | <% for i := 1; i <= 5; i++ { %> 29 | <% if i == 1 { %> 30 |

<%= u.FirstName %> has <%=i i %> message

31 | <% } else { %> 32 |

<%= u.FirstName %> has <%=i i %> messages

33 | <% } %> 34 | <% } %> 35 |
36 |
37 | 38 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /goh/index.html.go: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT! 2 | // Generate By Goh 3 | 4 | package template 5 | 6 | import ( 7 | "bytes" 8 | 9 | Goh "github.com/OblivionOcean/Goh/utils" 10 | "github.com/SlinSo/goTemplateBenchmark/model" 11 | ) 12 | 13 | func Index(u *model.User, nav []*model.Navigation, title string, buffer *bytes.Buffer) { 14 | buffer.Grow(543) 15 | buffer.WriteString(` 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | `) 25 | Goh.EscapeHTML(title, buffer) 26 | buffer.WriteString(`'s Home Page 27 |
Page Header
28 | 29 |
30 | 31 | 47 | 48 |
49 |
50 |
51 |

Hello `) 52 | Goh.EscapeHTML(u.FirstName, buffer) 53 | buffer.WriteString(`

54 | 55 |
`) 56 | buffer.WriteString(u.RawContent) 57 | buffer.WriteString(`
58 |
`) 59 | Goh.EscapeHTML(u.EscapedContent, buffer) 60 | buffer.WriteString(`
61 |
62 | 63 | `) 64 | for i := 1; i <= 5; i++ { 65 | buffer.WriteString(` 66 | `) 67 | if i == 1 { 68 | buffer.WriteString(` 69 |

`) 70 | Goh.EscapeHTML(u.FirstName, buffer) 71 | buffer.WriteString(` has `) 72 | Goh.FormatInt(int64(i), buffer) 73 | buffer.WriteString(` message

74 | `) 75 | } else { 76 | buffer.WriteString(` 77 |

`) 78 | Goh.EscapeHTML(u.FirstName, buffer) 79 | buffer.WriteString(` has `) 80 | Goh.FormatInt(int64(i), buffer) 81 | buffer.WriteString(` messages

82 | `) 83 | } 84 | buffer.WriteString(` 85 | `) 86 | } 87 | buffer.WriteString(` 88 |
89 |
90 | 91 | 95 | 96 | 97 | 98 | `) 99 | } 100 | -------------------------------------------------------------------------------- /goh/navigation.html: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /goh/navigation.html.go: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT! 2 | // Generate By Goh 3 | 4 | package template 5 | -------------------------------------------------------------------------------- /goh/simple.html: -------------------------------------------------------------------------------- 1 | <%: func SimpleQtc(u *model.User, buffer *bytes.Buffer) %> 2 | 3 | <%! 4 | import "github.com/SlinSo/goTemplateBenchmark/model" 5 | %> 6 | 7 | 8 | 9 |

<%= u.FirstName %>

10 | 11 |

Here's a list of your favorite colors:

12 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /goh/simple.html.go: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT! 2 | // Generate By Goh 3 | 4 | package template 5 | 6 | import ( 7 | "bytes" 8 | 9 | "github.com/SlinSo/goTemplateBenchmark/model" 10 | 11 | Goh "github.com/OblivionOcean/Goh/utils" 12 | ) 13 | 14 | func SimpleQtc(u *model.User, buffer *bytes.Buffer) { 15 | buffer.Grow(194) 16 | buffer.WriteString(` 17 | 18 | 19 | 20 | 21 | 22 |

`) 23 | Goh.EscapeHTML(u.FirstName, buffer) 24 | buffer.WriteString(`

25 | 26 |

Here's a list of your favorite colors:

27 | 38 | 39 | 40 | `) 41 | } 42 | -------------------------------------------------------------------------------- /golang/footer.go: -------------------------------------------------------------------------------- 1 | package golang 2 | 3 | import ( 4 | "github.com/valyala/bytebufferpool" 5 | ) 6 | 7 | func WriteFooter(bb *bytebufferpool.ByteBuffer) { 8 | _, _ = bb.WriteString(``) 9 | } 10 | -------------------------------------------------------------------------------- /golang/header.go: -------------------------------------------------------------------------------- 1 | package golang 2 | 3 | import ( 4 | "html" 5 | 6 | "github.com/valyala/bytebufferpool" 7 | ) 8 | 9 | func Header(bb *bytebufferpool.ByteBuffer, title *string) { 10 | _, _ = bb.WriteString(``) 11 | _, _ = bb.WriteString(html.EscapeString(*title)) 12 | _, _ = bb.WriteString(`'s Home Page 13 |
Page Header
14 | `) 15 | } 16 | -------------------------------------------------------------------------------- /golang/index.go: -------------------------------------------------------------------------------- 1 | package golang 2 | 3 | import ( 4 | "bytes" 5 | "html" 6 | "reflect" 7 | "strconv" 8 | "unsafe" 9 | 10 | "github.com/SlinSo/goTemplateBenchmark/model" 11 | "github.com/valyala/bytebufferpool" 12 | ) 13 | 14 | var () 15 | 16 | func UnsafeStrToBytes(s string) []byte { 17 | sh := (*reflect.StringHeader)(unsafe.Pointer(&s)) 18 | bh := reflect.SliceHeader{ 19 | Data: sh.Data, 20 | Len: sh.Len, 21 | Cap: sh.Len, 22 | } 23 | return *(*[]byte)(unsafe.Pointer(&bh)) 24 | } 25 | 26 | func Escape(bb *bytebufferpool.ByteBuffer, b []byte) { 27 | write := bb.Write 28 | j := 0 29 | for i, c := range b { 30 | switch c { 31 | case '<': 32 | _, _ = write(b[j:i]) 33 | _, _ = write(strLT) 34 | j = i + 1 35 | case '>': 36 | _, _ = write(b[j:i]) 37 | _, _ = write(strGT) 38 | j = i + 1 39 | case '"': 40 | _, _ = write(b[j:i]) 41 | _, _ = write(strQuot) 42 | j = i + 1 43 | case '\'': 44 | _, _ = write(b[j:i]) 45 | _, _ = write(strApos) 46 | j = i + 1 47 | case '&': 48 | _, _ = write(b[j:i]) 49 | _, _ = write(strAmp) 50 | j = i + 1 51 | } 52 | } 53 | _, _ = write(b[j:]) 54 | } 55 | 56 | var ( 57 | strLT = []byte("<") 58 | strGT = []byte(">") 59 | strQuot = []byte(""") 60 | strApos = []byte("'") 61 | strAmp = []byte("&") 62 | ) 63 | 64 | func hyper(bb *bytebufferpool.ByteBuffer, s string) { 65 | classFound := false 66 | idFound := false 67 | _ = bb.WriteByte('<') 68 | 69 | b := UnsafeStrToBytes(s) 70 | 71 | for _, c := range b { 72 | switch c { 73 | case '#': 74 | _, _ = bb.WriteString(" id=\"") 75 | idFound = true 76 | case '.': 77 | if idFound { 78 | _ = bb.WriteByte('"') 79 | } 80 | if !classFound { 81 | _, _ = bb.WriteString(" class=\"") 82 | classFound = true 83 | } else { 84 | _ = bb.WriteByte(' ') 85 | } 86 | default: 87 | _ = bb.WriteByte(c) 88 | } 89 | } 90 | if idFound || classFound { 91 | _ = bb.WriteByte('"') 92 | } 93 | _ = bb.WriteByte('>') 94 | } 95 | 96 | func Index3(bb *bytebufferpool.ByteBuffer, u *model.User, nav []*model.Navigation, title string) { 97 | _, _ = bb.WriteString(` 98 | 99 | 100 | 101 |
Bob's Home Page 102 |
Page Header
103 |
104 | 105 | 111 | 112 |
113 | 114 |
115 |
116 |

Hello Bob

117 | 118 |

Raw Content to be displayed

119 |
<div><div><div>Escaped</div></div></div>
120 |

Bob has 1 message

Bob has 2 messages

Bob has 3 messages

Bob has 4 messages

Bob has 5 messages

121 |
122 |
123 | 124 | 126 | 127 | 128 | `) 129 | } 130 | 131 | func Index2(bb *bytebufferpool.ByteBuffer, u *model.User, nav []*model.Navigation, title string) { 132 | _, _ = bb.WriteString(``) 133 | hyper(bb, "html") 134 | hyper(bb, "body") 135 | hyper(bb, "header") 136 | Header(bb, &title) 137 | hyper(bb, "/header") 138 | hyper(bb, "nav") 139 | Navigation(bb, nav) 140 | hyper(bb, "/nav") 141 | hyper(bb, "section") 142 | hyper(bb, "div.content") 143 | hyper(bb, "div.welcome") 144 | hyper(bb, "h4") 145 | _, _ = bb.WriteString(`Hello `) 146 | _, _ = bb.WriteString(html.EscapeString(u.FirstName)) 147 | hyper(bb, "/h4") 148 | hyper(bb, "div.raw") 149 | _, _ = bb.WriteString(u.RawContent) 150 | hyper(bb, "/div") 151 | hyper(bb, "div.enc") 152 | Escape(bb, UnsafeStrToBytes(u.EscapedContent)) 153 | hyper(bb, "/div>`) 162 | } else { 163 | _, _ = bb.WriteString(` messages

`) 164 | } 165 | 166 | } 167 | hyper(bb, "/div>', '"'} 175 | escapedValues = []string{"&", "'", "<", ">", """} 176 | ) 177 | 178 | // EscapeHTML escapes the html and then put it to the buffer. 179 | func EscapeHTML(html string, buffer *bytebufferpool.ByteBuffer) { 180 | var i, j, k int 181 | 182 | for i < len(html) { 183 | for j = i; j < len(html); j++ { 184 | k = bytes.IndexByte(escapedKeys, html[j]) 185 | if k != -1 { 186 | break 187 | } 188 | } 189 | 190 | _, _ = buffer.WriteString(html[i:j]) 191 | if k != -1 { 192 | _, _ = buffer.WriteString(escapedValues[k]) 193 | } 194 | i = j + 1 195 | } 196 | } 197 | 198 | func Index(bb *bytebufferpool.ByteBuffer, u *model.User, nav []*model.Navigation, title string) { 199 | _, _ = bb.WriteString(` 200 | 201 | 202 | 203 | 204 |
205 | `) 206 | Header(bb, &title) 207 | _, _ = bb.WriteString(` 208 |
209 | 210 | 215 | 216 |
217 |
218 |
219 |

Hello `) 220 | Escape(bb, UnsafeStrToBytes(u.FirstName)) 221 | _, _ = bb.WriteString(`

222 | 223 |
`) 224 | _, _ = bb.WriteString(u.RawContent) 225 | _, _ = bb.WriteString(`
226 |
`) 227 | Escape(bb, UnsafeStrToBytes(u.EscapedContent)) 228 | _, _ = bb.WriteString(`
229 |
230 | 231 | `) 232 | for i := 1; i <= 5; i++ { 233 | _, _ = bb.WriteString(` 234 |

`) 235 | _, _ = bb.WriteString(html.EscapeString(u.FirstName)) 236 | _, _ = bb.WriteString(` has `) 237 | if i == 1 { 238 | _, _ = bb.WriteString(`1 message

`) 239 | } else { 240 | bb.B = strconv.AppendInt(bb.B, int64(i), 10) 241 | _, _ = bb.WriteString(` messages

`) 242 | } 243 | 244 | } 245 | _, _ = bb.WriteString(` 246 |
247 |
248 | 249 | 254 | 255 | 256 | 257 | `) 258 | } 259 | -------------------------------------------------------------------------------- /golang/navigation.go: -------------------------------------------------------------------------------- 1 | package golang 2 | 3 | import ( 4 | "html" 5 | 6 | "github.com/SlinSo/goTemplateBenchmark/model" 7 | "github.com/valyala/bytebufferpool" 8 | ) 9 | 10 | func Navigation(bb *bytebufferpool.ByteBuffer, nav []*model.Navigation) { 11 | _, _ = bb.WriteString(``) 21 | } 22 | -------------------------------------------------------------------------------- /golang/simple.go: -------------------------------------------------------------------------------- 1 | package golang 2 | 3 | import ( 4 | "html" 5 | "net/http" 6 | 7 | "github.com/SlinSo/goTemplateBenchmark/model" 8 | "github.com/valyala/bytebufferpool" 9 | ) 10 | 11 | type TemplateFunc func(string) 12 | 13 | func (f TemplateFunc) H(s string) { 14 | f(s) 15 | } 16 | 17 | type TemplateH interface { 18 | H(string) 19 | } 20 | type Me http.Handler 21 | type Me2 http.HandlerFunc 22 | 23 | type GoFunc struct { 24 | bb *bytebufferpool.ByteBuffer 25 | } 26 | 27 | func NewGoFunc(buf *bytebufferpool.ByteBuffer) *GoFunc { 28 | return &GoFunc{bb: buf} 29 | } 30 | 31 | func (g *GoFunc) H(elem string, fn func(*string)) func(*string) { 32 | return func(s *string) { 33 | 34 | _, _ = g.bb.WriteString("<") 35 | _, _ = g.bb.WriteString(elem) 36 | _, _ = g.bb.WriteString(">") 37 | 38 | if fn != nil { 39 | fn(s) 40 | } 41 | 42 | _, _ = g.bb.WriteString("") 45 | } 46 | } 47 | 48 | type Attr map[string]string 49 | 50 | func (g *GoFunc) html() { 51 | _, _ = g.bb.WriteString("") 52 | } 53 | func (g *GoFunc) htmlEnd() { 54 | _, _ = g.bb.WriteString("") 55 | } 56 | 57 | func (g *GoFunc) body() { 58 | _, _ = g.bb.WriteString("") 59 | } 60 | func (g *GoFunc) bodyEnd() { 61 | _, _ = g.bb.WriteString("") 62 | } 63 | 64 | func (g *GoFunc) h1() { 65 | _, _ = g.bb.WriteString("

") 66 | } 67 | func (g *GoFunc) h1End() { 68 | _, _ = g.bb.WriteString("

") 69 | } 70 | func (g *GoFunc) p() { 71 | _, _ = g.bb.WriteString("

") 72 | } 73 | func (g *GoFunc) pEnd() { 74 | _, _ = g.bb.WriteString("

") 75 | } 76 | func (g *GoFunc) li() { 77 | _, _ = g.bb.WriteString("
  • ") 78 | } 79 | func (g *GoFunc) liEnd() { 80 | _, _ = g.bb.WriteString("
  • ") 81 | } 82 | func (g *GoFunc) ul() { 83 | _, _ = g.bb.WriteString("") 87 | } 88 | func (g *GoFunc) escape(s string) { 89 | _, _ = g.bb.WriteString(html.EscapeString(s)) 90 | } 91 | func (g *GoFunc) s(s string) { 92 | _, _ = g.bb.WriteString(s) 93 | } 94 | func (g *GoFunc) elem(s []string) { 95 | for _, e := range s { 96 | _, _ = g.bb.WriteString("<") 97 | _, _ = g.bb.WriteString(e) 98 | _, _ = g.bb.WriteString(">") 99 | } 100 | } 101 | 102 | func GoFuncElem(g *GoFunc, u *model.User) { 103 | g.elem([]string{"html", "body", "h1"}) 104 | g.escape(u.FirstName) 105 | g.h1End() 106 | g.p() 107 | g.s("Here's a list of your favorite colors:") 108 | g.pEnd() 109 | g.ul() 110 | for _, colorName := range u.FavoriteColors { 111 | g.li() 112 | g.escape(colorName) 113 | g.liEnd() 114 | } 115 | g.ulEnd() 116 | g.bodyEnd() 117 | g.htmlEnd() 118 | } 119 | 120 | func GoFuncFunc(g *GoFunc, u *model.User) { 121 | g.html() 122 | g.body() 123 | g.h1() 124 | g.escape(u.FirstName) 125 | g.h1End() 126 | g.p() 127 | g.s("Here's a list of your favorite colors:") 128 | g.pEnd() 129 | g.ul() 130 | for _, colorName := range u.FavoriteColors { 131 | g.li() 132 | g.escape(colorName) 133 | g.liEnd() 134 | } 135 | g.ulEnd() 136 | g.bodyEnd() 137 | g.htmlEnd() 138 | } 139 | 140 | // WriteSimpleGolang golang funcion based template 141 | func WriteSimpleGolang(bb *bytebufferpool.ByteBuffer, u *model.User) { 142 | _, _ = bb.WriteString(` 143 | 144 | 145 |

    `) 146 | _, _ = bb.WriteString(html.EscapeString(u.FirstName)) 147 | _, _ = bb.WriteString(`

    148 |

    Here's a list of your favorite colors:

    149 | 158 | 159 | 160 | `) 161 | } 162 | -------------------------------------------------------------------------------- /gomponents/simple.go: -------------------------------------------------------------------------------- 1 | package gomponents 2 | 3 | import ( 4 | "github.com/SlinSo/goTemplateBenchmark/model" 5 | g "maragu.dev/gomponents" 6 | . "maragu.dev/gomponents/html" 7 | ) 8 | 9 | func Page(u *model.User) g.Node { 10 | return HTML( 11 | Body( 12 | H1(g.Raw(u.FirstName)), 13 | P(g.Raw("Here's a list of your favorite colors:")), 14 | Ul( 15 | g.Group(g.Map(u.FavoriteColors, func(colorname string) g.Node { 16 | return Li(g.Raw(colorname)) 17 | })), 18 | ), 19 | ), 20 | ) 21 | } 22 | -------------------------------------------------------------------------------- /gorazor/index.go: -------------------------------------------------------------------------------- 1 | // This file is generated by gorazor 1.2.2 2 | // DON'T modified manually 3 | // Should edit source file and re-generate: gorazor/index.gohtml 4 | 5 | package gorazor 6 | 7 | import ( 8 | "github.com/SlinSo/goTemplateBenchmark/gorazor/tpl/helper" 9 | "github.com/SlinSo/goTemplateBenchmark/gorazor/tpl/layout" 10 | "github.com/SlinSo/goTemplateBenchmark/model" 11 | "github.com/sipin/gorazor/gorazor" 12 | "io" 13 | "strings" 14 | ) 15 | 16 | // Index generates gorazor/index.gohtml 17 | func Index(u *model.User, nav []*model.Navigation, title string) string { 18 | var _b strings.Builder 19 | RenderIndex(&_b, u, nav, title) 20 | return _b.String() 21 | } 22 | 23 | // RenderIndex render gorazor/index.gohtml 24 | func RenderIndex(_buffer io.StringWriter, u *model.User, nav []*model.Navigation, title string) { 25 | 26 | _body := func(_buffer io.StringWriter) { 27 | // Line: 12 28 | _buffer.WriteString("\n\n
    \n\t
    \n\t\t

    Hello ") 29 | // Line: 16 30 | _buffer.WriteString(gorazor.HTMLEscStr(u.FirstName)) 31 | // Line: 16 32 | _buffer.WriteString("

    \n\n\t\t
    ") 33 | // Line: 18 34 | _buffer.WriteString((u.RawContent)) 35 | // Line: 18 36 | _buffer.WriteString("
    \n\t\t
    ") 37 | // Line: 19 38 | _buffer.WriteString(gorazor.HTMLEscStr(u.EscapedContent)) 39 | // Line: 19 40 | _buffer.WriteString("
    \n\t
    ") 41 | 42 | for i := 1; i <= 5; i++ { 43 | if i == 1 { 44 | 45 | // Line: 25 46 | _buffer.WriteString("

    ") 47 | // Line: 25 48 | _buffer.WriteString(gorazor.HTMLEscStr(u.FirstName)) 49 | // Line: 25 50 | _buffer.WriteString(" has ") 51 | // Line: 25 52 | _buffer.WriteString(gorazor.HTMLEscInt(i)) 53 | // Line: 25 54 | _buffer.WriteString(" message

    ") 55 | 56 | } else { 57 | 58 | // Line: 27 59 | _buffer.WriteString("

    ") 60 | // Line: 27 61 | _buffer.WriteString(gorazor.HTMLEscStr(u.FirstName)) 62 | // Line: 27 63 | _buffer.WriteString(" has ") 64 | // Line: 27 65 | _buffer.WriteString(gorazor.HTMLEscStr(gorazor.Itoa(i))) 66 | // Line: 27 67 | _buffer.WriteString(" messages

    ") 68 | 69 | } 70 | } 71 | 72 | // Line: 30 73 | _buffer.WriteString("\n
    ") 74 | 75 | } 76 | 77 | _header := func(_buffer io.StringWriter) { 78 | 79 | // Line: 34 80 | _buffer.WriteString((helper.Header(title))) 81 | 82 | } 83 | 84 | _footer := func(_buffer io.StringWriter) { 85 | 86 | // Line: 38 87 | _buffer.WriteString((helper.Footer())) 88 | 89 | } 90 | 91 | _navigation := func(_buffer io.StringWriter) { 92 | 93 | // Line: 42 94 | _buffer.WriteString((helper.Navigation(nav))) 95 | 96 | } 97 | 98 | layout.RenderBase(_buffer, _body, _header, _footer, _navigation) 99 | } 100 | -------------------------------------------------------------------------------- /gorazor/index.gohtml: -------------------------------------------------------------------------------- 1 | @{ 2 | import ( 3 | "github.com/SlinSo/goTemplateBenchmark/model" 4 | "github.com/sipin/gorazor/gorazor" 5 | "github.com/SlinSo/goTemplateBenchmark/gorazor/tpl/layout" 6 | "github.com/SlinSo/goTemplateBenchmark/gorazor/tpl/helper" 7 | ) 8 | layout := layout.Base 9 | var u *model.User 10 | var nav []*model.Navigation 11 | var title string 12 | } 13 | 14 |
    15 |
    16 |

    Hello @u.FirstName

    17 | 18 |
    @raw(u.RawContent)
    19 |
    @u.EscapedContent
    20 |
    21 | 22 | @{ 23 | for i := 1; i <= 5; i++ { 24 | if i == 1 { 25 |

    @u.FirstName has @i message

    26 | } else { 27 |

    @u.FirstName has @gorazor.Itoa(@i) messages

    28 | } 29 | } 30 | } 31 |
    32 | 33 | @section header { 34 | @helper.Header(@title) 35 | } 36 | 37 | @section footer { 38 | @helper.Footer() 39 | } 40 | 41 | @section navigation { 42 | @helper.Navigation(nav) 43 | } -------------------------------------------------------------------------------- /gorazor/simple.go: -------------------------------------------------------------------------------- 1 | // This file is generated by gorazor 1.2.2 2 | // DON'T modified manually 3 | // Should edit source file and re-generate: gorazor/simple.gohtml 4 | 5 | package gorazor 6 | 7 | import ( 8 | "github.com/SlinSo/goTemplateBenchmark/model" 9 | "github.com/sipin/gorazor/gorazor" 10 | "io" 11 | "strings" 12 | ) 13 | 14 | // Simple generates gorazor/simple.gohtml 15 | func Simple(u *model.User) string { 16 | var _b strings.Builder 17 | RenderSimple(&_b, u) 18 | return _b.String() 19 | } 20 | 21 | // RenderSimple render gorazor/simple.gohtml 22 | func RenderSimple(_buffer io.StringWriter, u *model.User) { 23 | // Line: 4 24 | _buffer.WriteString("\n\n \n

    ") 25 | // Line: 7 26 | _buffer.WriteString(gorazor.HTMLEscStr(u.FirstName)) 27 | // Line: 7 28 | _buffer.WriteString("

    \n\n

    Here's a list of your favorite colors:

    \n \n \n") 41 | 42 | } 43 | -------------------------------------------------------------------------------- /gorazor/simple.gohtml: -------------------------------------------------------------------------------- 1 | @{ 2 | import "github.com/SlinSo/goTemplateBenchmark/model" 3 | var u *model.User 4 | } 5 | 6 | 7 |

    @u.FirstName

    8 | 9 |

    Here's a list of your favorite colors:

    10 | 15 | 16 | -------------------------------------------------------------------------------- /gorazor/tpl/helper/footer.go: -------------------------------------------------------------------------------- 1 | // This file is generated by gorazor 1.2.2 2 | // DON'T modified manually 3 | // Should edit source file and re-generate: gorazor/tpl/helper/footer.gohtml 4 | 5 | package helper 6 | 7 | import ( 8 | "io" 9 | "strings" 10 | ) 11 | 12 | // Footer generates gorazor/tpl/helper/footer.gohtml 13 | func Footer() string { 14 | var _b strings.Builder 15 | RenderFooter(&_b) 16 | return _b.String() 17 | } 18 | 19 | // RenderFooter render gorazor/tpl/helper/footer.gohtml 20 | func RenderFooter(_buffer io.StringWriter) { 21 | // Line: 1 22 | _buffer.WriteString("
    copyright 2016
    ") 23 | 24 | } 25 | -------------------------------------------------------------------------------- /gorazor/tpl/helper/footer.gohtml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /gorazor/tpl/helper/header.go: -------------------------------------------------------------------------------- 1 | // This file is generated by gorazor 1.2.2 2 | // DON'T modified manually 3 | // Should edit source file and re-generate: gorazor/tpl/helper/header.gohtml 4 | 5 | package helper 6 | 7 | import ( 8 | "github.com/sipin/gorazor/gorazor" 9 | "io" 10 | "strings" 11 | ) 12 | 13 | // Header generates gorazor/tpl/helper/header.gohtml 14 | func Header(title string) string { 15 | var _b strings.Builder 16 | RenderHeader(&_b, title) 17 | return _b.String() 18 | } 19 | 20 | // RenderHeader render gorazor/tpl/helper/header.gohtml 21 | func RenderHeader(_buffer io.StringWriter, title string) { 22 | // Line: 3 23 | _buffer.WriteString("\n") 24 | // Line: 4 25 | _buffer.WriteString(gorazor.HTMLEscStr(title)) 26 | // Line: 4 27 | _buffer.WriteString("'s Home Page\n
    Page Header
    ") 28 | 29 | } 30 | -------------------------------------------------------------------------------- /gorazor/tpl/helper/header.gohtml: -------------------------------------------------------------------------------- 1 | @{ 2 | var title string 3 | } 4 | @title's Home Page 5 |
    Page Header
    -------------------------------------------------------------------------------- /gorazor/tpl/helper/navigation.go: -------------------------------------------------------------------------------- 1 | // This file is generated by gorazor 1.2.2 2 | // DON'T modified manually 3 | // Should edit source file and re-generate: gorazor/tpl/helper/navigation.gohtml 4 | 5 | package helper 6 | 7 | import ( 8 | "github.com/SlinSo/goTemplateBenchmark/model" 9 | "github.com/sipin/gorazor/gorazor" 10 | "io" 11 | "strings" 12 | ) 13 | 14 | // Navigation generates gorazor/tpl/helper/navigation.gohtml 15 | func Navigation(nav []*model.Navigation) string { 16 | var _b strings.Builder 17 | RenderNavigation(&_b, nav) 18 | return _b.String() 19 | } 20 | 21 | // RenderNavigation render gorazor/tpl/helper/navigation.gohtml 22 | func RenderNavigation(_buffer io.StringWriter, nav []*model.Navigation) { 23 | // Line: 6 24 | _buffer.WriteString("\n") 43 | 44 | } 45 | -------------------------------------------------------------------------------- /gorazor/tpl/helper/navigation.gohtml: -------------------------------------------------------------------------------- 1 | @{ 2 | import ( 3 | "github.com/SlinSo/goTemplateBenchmark/model" 4 | ) 5 | var nav []*model.Navigation 6 | } 7 | -------------------------------------------------------------------------------- /gorazor/tpl/layout/base.go: -------------------------------------------------------------------------------- 1 | // This file is generated by gorazor 1.2.2 2 | // DON'T modified manually 3 | // Should edit source file and re-generate: gorazor/tpl/layout/base.gohtml 4 | 5 | package layout 6 | 7 | import ( 8 | "io" 9 | "strings" 10 | ) 11 | 12 | // Base generates gorazor/tpl/layout/base.gohtml 13 | func Base(body string, header string, footer string, navigation string) string { 14 | var _b strings.Builder 15 | 16 | _body := func(_buffer io.StringWriter) { 17 | _buffer.WriteString(body) 18 | } 19 | 20 | _header := func(_buffer io.StringWriter) { 21 | _buffer.WriteString(header) 22 | } 23 | 24 | _footer := func(_buffer io.StringWriter) { 25 | _buffer.WriteString(footer) 26 | } 27 | 28 | _navigation := func(_buffer io.StringWriter) { 29 | _buffer.WriteString(navigation) 30 | } 31 | 32 | RenderBase(&_b, _body, _header, _footer, _navigation) 33 | return _b.String() 34 | } 35 | 36 | // RenderBase render gorazor/tpl/layout/base.gohtml 37 | func RenderBase(_buffer io.StringWriter, body func(_buffer io.StringWriter), header func(_buffer io.StringWriter), footer func(_buffer io.StringWriter), navigation func(_buffer io.StringWriter)) { 38 | // Line: 6 39 | _buffer.WriteString("\n\n\n\n\n
    ") 40 | // Line: 12 41 | header(_buffer) 42 | // Line: 12 43 | _buffer.WriteString("\n
    \n\n\n\n
    ") 48 | // Line: 20 49 | body(_buffer) 50 | // Line: 20 51 | _buffer.WriteString("\n
    \n\n\n\n\n") 56 | 57 | } 58 | -------------------------------------------------------------------------------- /gorazor/tpl/layout/base.gohtml: -------------------------------------------------------------------------------- 1 | @{ 2 | var body string 3 | var header string 4 | var footer string 5 | var navigation string 6 | } 7 | 8 | 9 | 10 | 11 |
    12 | @header 13 |
    14 | 15 | 18 | 19 |
    20 | @body 21 |
    22 | 23 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /hero/footer.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /hero/footer.html.go: -------------------------------------------------------------------------------- 1 | // Code generated by hero. 2 | // source: /home/sl/gospace/goTemplateBenchmark/hero/footer.html 3 | // DO NOT EDIT! 4 | package template 5 | -------------------------------------------------------------------------------- /hero/header.html: -------------------------------------------------------------------------------- 1 | <%= title %>'s Home Page 2 |
    Page Header
    3 | -------------------------------------------------------------------------------- /hero/header.html.go: -------------------------------------------------------------------------------- 1 | // Code generated by hero. 2 | // source: /home/sl/gospace/goTemplateBenchmark/hero/header.html 3 | // DO NOT EDIT! 4 | package template 5 | -------------------------------------------------------------------------------- /hero/index.html: -------------------------------------------------------------------------------- 1 | <%: func Index(u *model.User, nav []*model.Navigation, title string, buffer *bytes.Buffer) %> 2 | 3 | <%! 4 | import "github.com/SlinSo/goTemplateBenchmark/model" 5 | %> 6 | 7 | 8 | 9 | 10 | 11 |
    12 | <%+ "header.html" %> 13 |
    14 | 15 | 18 | 19 |
    20 |
    21 |
    22 |

    Hello <%= u.FirstName %>

    23 | 24 |
    <%== u.RawContent %>
    25 |
    <%= u.EscapedContent %>
    26 |
    27 | 28 | <% for i := 1; i <= 5; i++ { %> 29 | <% if i == 1 { %> 30 |

    <%= u.FirstName %> has <%=i i %> message

    31 | <% } else { %> 32 |

    <%= u.FirstName %> has <%=i i %> messages

    33 | <% } %> 34 | <% } %> 35 |
    36 |
    37 | 38 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /hero/index.html.go: -------------------------------------------------------------------------------- 1 | // Code generated by hero. 2 | // source: /home/sl/gospace/goTemplateBenchmark/hero/index.html 3 | // DO NOT EDIT! 4 | package template 5 | 6 | import ( 7 | "bytes" 8 | 9 | "github.com/SlinSo/goTemplateBenchmark/model" 10 | "github.com/shiyanhui/hero" 11 | ) 12 | 13 | func Index(u *model.User, nav []*model.Navigation, title string, buffer *bytes.Buffer) { 14 | buffer.WriteString(` 15 | 16 | 17 | 18 | 19 | 20 |
    21 | `) 22 | buffer.WriteString(``) 23 | hero.EscapeHTML(title, buffer) 24 | buffer.WriteString(`'s Home Page 25 |
    Page Header
    26 | `) 27 | buffer.WriteString(` 28 |
    29 | 30 | 48 | 49 |
    50 |
    51 |
    52 |

    Hello `) 53 | hero.EscapeHTML(u.FirstName, buffer) 54 | buffer.WriteString(`

    55 | 56 |
    `) 57 | buffer.WriteString(u.RawContent) 58 | buffer.WriteString(`
    59 |
    `) 60 | hero.EscapeHTML(u.EscapedContent, buffer) 61 | buffer.WriteString(`
    62 |
    63 | 64 | `) 65 | for i := 1; i <= 5; i++ { 66 | if i == 1 { 67 | buffer.WriteString(` 68 |

    `) 69 | hero.EscapeHTML(u.FirstName, buffer) 70 | buffer.WriteString(` has `) 71 | hero.FormatInt(int64(i), buffer) 72 | buffer.WriteString(` message

    73 | `) 74 | } else { 75 | buffer.WriteString(` 76 |

    `) 77 | hero.EscapeHTML(u.FirstName, buffer) 78 | buffer.WriteString(` has `) 79 | hero.FormatInt(int64(i), buffer) 80 | buffer.WriteString(` messages

    81 | `) 82 | } 83 | } 84 | buffer.WriteString(` 85 |
    86 |
    87 | 88 | 94 | 95 | 96 | 97 | `) 98 | 99 | } 100 | -------------------------------------------------------------------------------- /hero/navigation.html: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /hero/navigation.html.go: -------------------------------------------------------------------------------- 1 | // Code generated by hero. 2 | // source: /home/sl/gospace/goTemplateBenchmark/hero/navigation.html 3 | // DO NOT EDIT! 4 | package template 5 | -------------------------------------------------------------------------------- /hero/simple.html: -------------------------------------------------------------------------------- 1 | <%: func SimpleQtc(u *model.User, buffer *bytes.Buffer) %> 2 | 3 | <%! 4 | import "github.com/SlinSo/goTemplateBenchmark/model" 5 | %> 6 | 7 | 8 | 9 |

    <%= u.FirstName %>

    10 | 11 |

    Here's a list of your favorite colors:

    12 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /hero/simple.html.go: -------------------------------------------------------------------------------- 1 | // Code generated by hero. 2 | // source: /home/sl/gospace/goTemplateBenchmark/hero/simple.html 3 | // DO NOT EDIT! 4 | package template 5 | 6 | import ( 7 | "bytes" 8 | 9 | "github.com/SlinSo/goTemplateBenchmark/model" 10 | "github.com/shiyanhui/hero" 11 | ) 12 | 13 | func SimpleQtc(u *model.User, buffer *bytes.Buffer) { 14 | buffer.WriteString(` 15 | 16 | 17 | 18 |

    `) 19 | hero.EscapeHTML(u.FirstName, buffer) 20 | buffer.WriteString(`

    21 | 22 |

    Here's a list of your favorite colors:

    23 | 34 | 35 | 36 | `) 37 | 38 | } 39 | -------------------------------------------------------------------------------- /htmlbuilder/simple.go: -------------------------------------------------------------------------------- 1 | package htmlbuilder 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "html" 7 | "io" 8 | 9 | "github.com/SlinSo/goTemplateBenchmark/model" 10 | "github.com/gouniverse/hb" 11 | ) 12 | 13 | func HbSimple(w io.Writer, u *model.User) { 14 | ul := hb.NewUL() 15 | for i := 0; i < len(u.FavoriteColors); i++ { 16 | ul.Child(hb.NewLI().HTML(u.FavoriteColors[i])) 17 | } 18 | 19 | page := hb.NewTag("html"). 20 | Child(hb.NewTag("body"). 21 | Child(hb.NewHeading1().HTML(u.FirstName)). 22 | Child(hb.NewParagraph().HTML("Here's a list of your favorite colors:")). 23 | Child(ul), 24 | ).ToHTML() 25 | 26 | _, _ = io.WriteString(w, page) 27 | } 28 | 29 | var ( 30 | _ fmt.Stringer 31 | _ io.Reader 32 | _ context.Context 33 | _ = html.EscapeString 34 | ) 35 | -------------------------------------------------------------------------------- /jade/footer.jade: -------------------------------------------------------------------------------- 1 | .footer copyright 2016 2 | -------------------------------------------------------------------------------- /jade/header.jade: -------------------------------------------------------------------------------- 1 | title #{title}'s Home Page 2 | .header Page Header 3 | -------------------------------------------------------------------------------- /jade/index.jade: -------------------------------------------------------------------------------- 1 | :go:func Index(u *model.User, nav []*model.Navigation, title string) 2 | 3 | :go:import "github.com/SlinSo/goTemplateBenchmark/model" 4 | 5 | !!! 5 6 | html 7 | body 8 | header 9 | include header.jade 10 | nav 11 | include navigation.jade 12 | section 13 | .content 14 | .welcome 15 | h4 Hello #{u.FirstName} 16 | .raw!= u.RawContent 17 | .enc= u.EscapedContent 18 | - for i := 1; i <= 5; i++ { 19 | if i == 1 20 | p #{u.FirstName} has #{i} message 21 | else 22 | p #{u.FirstName} has #{i} messages 23 | - } 24 | footer 25 | include footer.jade 26 | -------------------------------------------------------------------------------- /jade/index.jade.go: -------------------------------------------------------------------------------- 1 | // Code generated by "jade.go"; DO NOT EDIT. 2 | 3 | package jade 4 | 5 | import ( 6 | "github.com/SlinSo/goTemplateBenchmark/model" 7 | pool "github.com/valyala/bytebufferpool" 8 | ) 9 | 10 | const ( 11 | index__0 = `
    ` 12 | index__1 = `'s Home Page
    Page Header

    Hello ` 14 | index__3 = `

    ` 15 | index__4 = `
    ` 16 | index__5 = `
    ` 17 | index__6 = `
    ` 18 | index__7 = `
  • ` 20 | index__9 = `
  • ` 21 | index__10 = `

    ` 22 | index__11 = ` has ` 23 | index__12 = ` message

    ` 24 | index__15 = ` messages

    ` 25 | ) 26 | 27 | func Index(u *model.User, nav []*model.Navigation, title string, buffer *pool.ByteBuffer) { 28 | 29 | buffer.WriteString(index__0) 30 | WriteEscString(title, buffer) 31 | buffer.WriteString(index__1) 32 | 33 | for _, item := range nav { 34 | buffer.WriteString(index__7) 35 | WriteEscString(item.Link, buffer) 36 | buffer.WriteString(index__8) 37 | WriteEscString(item.Item, buffer) 38 | buffer.WriteString(index__9) 39 | 40 | } 41 | buffer.WriteString(index__2) 42 | WriteEscString(u.FirstName, buffer) 43 | buffer.WriteString(index__3) 44 | buffer.WriteString(u.RawContent) 45 | buffer.WriteString(index__4) 46 | WriteEscString(u.EscapedContent, buffer) 47 | buffer.WriteString(index__5) 48 | 49 | for i := 1; i <= 5; i++ { 50 | if i == 1 { 51 | buffer.WriteString(index__10) 52 | WriteEscString(u.FirstName, buffer) 53 | buffer.WriteString(index__11) 54 | WriteInt(int64(i), buffer) 55 | buffer.WriteString(index__12) 56 | 57 | } else { 58 | buffer.WriteString(index__10) 59 | WriteEscString(u.FirstName, buffer) 60 | buffer.WriteString(index__11) 61 | WriteInt(int64(i), buffer) 62 | buffer.WriteString(index__15) 63 | 64 | } 65 | } 66 | buffer.WriteString(index__6) 67 | 68 | } 69 | -------------------------------------------------------------------------------- /jade/jade.go: -------------------------------------------------------------------------------- 1 | // Code generated by "jade.go"; DO NOT EDIT. 2 | package jade 3 | 4 | import ( 5 | "bytes" 6 | "io" 7 | "strconv" 8 | pool "github.com/valyala/bytebufferpool" 9 | ) 10 | 11 | var ( 12 | escaped = []byte{'<', '>', '"', '\'', '&'} 13 | replacing = []string{"<", ">", """, "'", "&"} 14 | ) 15 | 16 | func WriteEscString(st string, buffer *pool.ByteBuffer) { 17 | for i := 0; i < len(st); i++ { 18 | if n := bytes.IndexByte(escaped, st[i]); n >= 0 { 19 | buffer.WriteString(replacing[n]) 20 | } else { 21 | buffer.WriteByte(st[i]) 22 | } 23 | } 24 | } 25 | 26 | type WriterAsBuffer struct { 27 | io.Writer 28 | } 29 | 30 | func (w *WriterAsBuffer) WriteString(s string) (n int, err error) { 31 | n, err = w.Write([]byte(s)) 32 | return 33 | } 34 | 35 | func (w *WriterAsBuffer) WriteByte(b byte) (err error) { 36 | _, err = w.Write([]byte{b}) 37 | return 38 | } 39 | 40 | type stringer interface { 41 | String() string 42 | } 43 | 44 | func WriteAll(a interface{}, escape bool, buffer *pool.ByteBuffer) { 45 | switch v := a.(type) { 46 | case string: 47 | if escape { 48 | WriteEscString(v, buffer) 49 | } else { 50 | buffer.WriteString(v) 51 | } 52 | case int: 53 | WriteInt(int64(v), buffer) 54 | case int8: 55 | WriteInt(int64(v), buffer) 56 | case int16: 57 | WriteInt(int64(v), buffer) 58 | case int32: 59 | WriteInt(int64(v), buffer) 60 | case int64: 61 | WriteInt(v, buffer) 62 | case uint: 63 | WriteUint(uint64(v), buffer) 64 | case uint8: 65 | WriteUint(uint64(v), buffer) 66 | case uint16: 67 | WriteUint(uint64(v), buffer) 68 | case uint32: 69 | WriteUint(uint64(v), buffer) 70 | case uint64: 71 | WriteUint(v, buffer) 72 | case float32: 73 | buffer.WriteString(strconv.FormatFloat(float64(v), 'f', -1, 64)) 74 | case float64: 75 | buffer.WriteString(strconv.FormatFloat(v, 'f', -1, 64)) 76 | case bool: 77 | WriteBool(v, buffer) 78 | case stringer: 79 | if escape { 80 | WriteEscString(v.String(), buffer) 81 | } else { 82 | buffer.WriteString(v.String()) 83 | } 84 | default: 85 | buffer.WriteString("\n<<< unprinted type, fmt.Stringer implementation needed >>>\n") 86 | } 87 | } 88 | 89 | func ternary(condition bool, iftrue, iffalse interface{}) interface{} { 90 | if condition { 91 | return iftrue 92 | } else { 93 | return iffalse 94 | } 95 | } 96 | 97 | // Used part of go source: 98 | // https://github.com/golang/go/blob/master/src/strconv/itoa.go 99 | func WriteUint(u uint64, buffer *pool.ByteBuffer) { 100 | var a [64 + 1]byte 101 | i := len(a) 102 | 103 | if ^uintptr(0)>>32 == 0 { 104 | for u > uint64(^uintptr(0)) { 105 | q := u / 1e9 106 | us := uintptr(u - q*1e9) 107 | for j := 9; j > 0; j-- { 108 | i-- 109 | qs := us / 10 110 | a[i] = byte(us - qs*10 + '0') 111 | us = qs 112 | } 113 | u = q 114 | } 115 | } 116 | 117 | us := uintptr(u) 118 | for us >= 10 { 119 | i-- 120 | q := us / 10 121 | a[i] = byte(us - q*10 + '0') 122 | us = q 123 | } 124 | 125 | i-- 126 | a[i] = byte(us + '0') 127 | buffer.Write(a[i:]) 128 | } 129 | func WriteInt(i int64, buffer *pool.ByteBuffer) { 130 | if i < 0 { 131 | buffer.WriteByte('-') 132 | i = -i 133 | } 134 | WriteUint(uint64(i), buffer) 135 | } 136 | func WriteBool(b bool, buffer *pool.ByteBuffer) { 137 | if b { 138 | buffer.WriteString("true") 139 | return 140 | } 141 | buffer.WriteString("false") 142 | } 143 | -------------------------------------------------------------------------------- /jade/navigation.jade: -------------------------------------------------------------------------------- 1 | ul.navigation 2 | each item in nav 3 | li 4 | a(href=item.Link)= item.Item -------------------------------------------------------------------------------- /jade/simple.jade: -------------------------------------------------------------------------------- 1 | :go:func Simple( u *model.User) 2 | 3 | :go:import "github.com/SlinSo/goTemplateBenchmark/model" 4 | 5 | html 6 | body 7 | h1= u.FirstName 8 | p Here's a list of your favorite colors: 9 | ul 10 | each colorName in u.FavoriteColors 11 | li= colorName 12 | -------------------------------------------------------------------------------- /jade/simple.jade.go: -------------------------------------------------------------------------------- 1 | // Code generated by "jade.go"; DO NOT EDIT. 2 | 3 | package jade 4 | 5 | import ( 6 | "github.com/SlinSo/goTemplateBenchmark/model" 7 | pool "github.com/valyala/bytebufferpool" 8 | ) 9 | 10 | const ( 11 | simple__0 = `

    ` 12 | simple__1 = `

    Here's a list of your favorite colors:

    ` 14 | simple__3 = `
  • ` 15 | simple__4 = `
  • ` 16 | ) 17 | 18 | func Simple(u *model.User, buffer *pool.ByteBuffer) { 19 | 20 | buffer.WriteString(simple__0) 21 | WriteEscString(u.FirstName, buffer) 22 | buffer.WriteString(simple__1) 23 | 24 | for _, colorName := range u.FavoriteColors { 25 | buffer.WriteString(simple__3) 26 | WriteEscString(colorName, buffer) 27 | buffer.WriteString(simple__4) 28 | } 29 | buffer.WriteString(simple__2) 30 | 31 | } 32 | -------------------------------------------------------------------------------- /jet/blocks.jet: -------------------------------------------------------------------------------- 1 | {{block header()}} 2 | {{ .Title }}'s Home Page 3 |
    Page Header
    4 | {{end}} 5 | 6 | {{block navigation()}} 7 | 12 | {{end}} 13 | 14 | {{block footer()}} 15 | 16 | {{end}} 17 | -------------------------------------------------------------------------------- /jet/index.jet: -------------------------------------------------------------------------------- 1 | {{extends "layout.jet"}} 2 | {{block Body()}} 3 | 4 |
    5 |
    6 |

    Hello {{ .User.FirstName }}

    7 | 8 |
    {{ .User.RawContent|unsafe }}
    9 |
    {{ .User.EscapedContent }}
    10 |
    11 | 12 | {{range m := .Messages}} 13 | {{if m.Plural}} 14 |

    {{ .User.FirstName }} has {{ m.I }} messages

    15 | {{else}} 16 |

    {{ .User.FirstName }} has {{ m.I }} message

    17 | {{end}} 18 | {{end}} 19 |
    20 | {{end}} 21 | -------------------------------------------------------------------------------- /jet/layout.jet: -------------------------------------------------------------------------------- 1 | {{import "blocks.jet"}} 2 | 3 | 4 | 5 | 6 |
    7 | {{yield header()}} 8 |
    9 | 10 | 13 | 14 |
    15 | {{yield Body()}} 16 |
    17 | 18 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /jet/simple.jet: -------------------------------------------------------------------------------- 1 | 2 | 3 |

    {{ .FirstName }}

    4 | 5 |

    Here's a list of your favorite colors:

    6 | 10 | 11 | -------------------------------------------------------------------------------- /main.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # This file: 3 | # 4 | # - Demos BASH3 Boilerplate (change this for your script) 5 | # 6 | # Usage: 7 | # 8 | # LOG_LEVEL=7 ./main.sh -f /tmp/x -d (change this for your script) 9 | # 10 | # Based on a template by BASH3 Boilerplate v2.4.1 11 | # http://bash3boilerplate.sh/#authors 12 | # 13 | # The MIT License (MIT) 14 | # Copyright (c) 2013 Kevin van Zonneveld and contributors 15 | # You are not obligated to bundle the LICENSE file with your b3bp projects as long 16 | # as you leave these references intact in the header comments of your source files. 17 | 18 | # Exit on error. Append "|| true" if you expect an error. 19 | set -o errexit 20 | # Exit on error inside any functions or subshells. 21 | set -o errtrace 22 | # Do not allow use of undefined vars. Use ${VAR:-} to use an undefined VAR 23 | set -o nounset 24 | # Catch the error in case mysqldump fails (but gzip succeeds) in `mysqldump |gzip` 25 | set -o pipefail 26 | # Turn on traces, useful while debugging but commented out by default 27 | # set -o xtrace 28 | 29 | if [[ "${BASH_SOURCE[0]}" != "${0}" ]]; then 30 | __i_am_main_script="0" # false 31 | 32 | if [[ "${__usage+x}" ]]; then 33 | if [[ "${BASH_SOURCE[1]}" == "${0}" ]]; then 34 | __i_am_main_script="1" # true 35 | fi 36 | 37 | __b3bp_external_usage="true" 38 | __b3bp_tmp_source_idx=1 39 | fi 40 | else 41 | __i_am_main_script="1" # true 42 | [[ "${__usage+x}" ]] && unset -v __usage 43 | [[ "${__helptext+x}" ]] && unset -v __helptext 44 | fi 45 | 46 | # Set magic variables for current file, directory, os, etc. 47 | __dir="$(cd "$(dirname "${BASH_SOURCE[${__b3bp_tmp_source_idx:-0}]}")" && pwd)" 48 | __file="${__dir}/$(basename "${BASH_SOURCE[${__b3bp_tmp_source_idx:-0}]}")" 49 | __base="$(basename "${__file}" .sh)" 50 | # shellcheck disable=SC2034,SC2015 51 | __invocation="$(printf %q "${__file}")$((($#)) && printf ' %q' "$@" || true)" 52 | 53 | # Define the environment variables (and their defaults) that this script depends on 54 | LOG_LEVEL="${LOG_LEVEL:-6}" # 7 = debug -> 0 = emergency 55 | NO_COLOR="${NO_COLOR:-}" # true = disable color. otherwise autodetected 56 | 57 | ### Functions 58 | ############################################################################## 59 | 60 | function __b3bp_log() { 61 | local log_level="${1}" 62 | shift 63 | 64 | # shellcheck disable=SC2034 65 | local color_debug="\\x1b[35m" 66 | # shellcheck disable=SC2034 67 | local color_info="\\x1b[32m" 68 | # shellcheck disable=SC2034 69 | local color_notice="\\x1b[34m" 70 | # shellcheck disable=SC2034 71 | local color_warning="\\x1b[33m" 72 | # shellcheck disable=SC2034 73 | local color_error="\\x1b[31m" 74 | # shellcheck disable=SC2034 75 | local color_critical="\\x1b[1;31m" 76 | # shellcheck disable=SC2034 77 | local color_alert="\\x1b[1;37;41m" 78 | # shellcheck disable=SC2034 79 | local color_emergency="\\x1b[1;4;5;37;41m" 80 | 81 | local colorvar="color_${log_level}" 82 | 83 | local color="${!colorvar:-${color_error}}" 84 | local color_reset="\\x1b[0m" 85 | 86 | if [[ "${NO_COLOR:-}" == "true" ]] || { [[ "${TERM:-}" != "xterm"* ]] && [[ "${TERM:-}" != "screen"* ]]; } || [[ ! -t 2 ]]; then 87 | if [[ "${NO_COLOR:-}" != "false" ]]; then 88 | # Don't use colors on pipes or non-recognized terminals 89 | color="" 90 | color_reset="" 91 | fi 92 | fi 93 | 94 | # all remaining arguments are to be printed 95 | local log_line="" 96 | 97 | while IFS=$'\n' read -r log_line; do 98 | echo -e "$(date -u +"%Y-%m-%d %H:%M:%S UTC") ${color}$(printf "[%9s]" "${log_level}")${color_reset} ${log_line}" 1>&2 99 | done <<<"${@:-}" 100 | } 101 | 102 | function emergency() { 103 | __b3bp_log emergency "${@}" 104 | exit 1 105 | } 106 | function alert() { 107 | [[ "${LOG_LEVEL:-0}" -ge 1 ]] && __b3bp_log alert "${@}" 108 | true 109 | } 110 | function critical() { 111 | [[ "${LOG_LEVEL:-0}" -ge 2 ]] && __b3bp_log critical "${@}" 112 | true 113 | } 114 | function error() { 115 | [[ "${LOG_LEVEL:-0}" -ge 3 ]] && __b3bp_log error "${@}" 116 | true 117 | } 118 | function warning() { 119 | [[ "${LOG_LEVEL:-0}" -ge 4 ]] && __b3bp_log warning "${@}" 120 | true 121 | } 122 | function notice() { 123 | [[ "${LOG_LEVEL:-0}" -ge 5 ]] && __b3bp_log notice "${@}" 124 | true 125 | } 126 | function info() { 127 | [[ "${LOG_LEVEL:-0}" -ge 6 ]] && __b3bp_log info "${@}" 128 | true 129 | } 130 | function debug() { 131 | [[ "${LOG_LEVEL:-0}" -ge 7 ]] && __b3bp_log debug "${@}" 132 | true 133 | } 134 | 135 | function help() { 136 | echo "" 1>&2 137 | echo " ${*}" 1>&2 138 | echo "" 1>&2 139 | echo " ${__usage:-No usage available}" 1>&2 140 | echo "" 1>&2 141 | 142 | if [[ "${__helptext:-}" ]]; then 143 | echo " ${__helptext}" 1>&2 144 | echo "" 1>&2 145 | fi 146 | 147 | exit 1 148 | } 149 | 150 | ### Parse commandline options 151 | ############################################################################## 152 | 153 | # Commandline options. This defines the usage page, and is used to parse cli 154 | # opts & defaults from. The parsing is unforgiving so be precise in your syntax 155 | # - A short option must be preset for every long option; but every short option 156 | # need not have a long option 157 | # - `--` is respected as the separator between options and arguments 158 | # - We do not bash-expand defaults, so setting '~/app' as a default will not resolve to ${HOME}. 159 | # you can use bash variables to work around this (so use ${HOME} instead) 160 | 161 | # shellcheck disable=SC2015 162 | [[ "${__usage+x}" ]] || read -r -d '' __usage <<-'EOF' || true # exits non-zero when EOF encountered 163 | -f --file [arg] Filename to process. Required. 164 | -t --temp [arg] Location of tempfile. Default="/tmp/bar" 165 | -v Enable verbose mode, print script as it is executed 166 | -d --debug Enables debug mode 167 | -h --help This page 168 | -n --no-color Disable color output 169 | -1 --one Do just one thing 170 | -i --input [arg] File to process. Can be repeated. 171 | -x Specify a flag. Can be repeated. 172 | EOF 173 | 174 | # shellcheck disable=SC2015 175 | [[ "${__helptext+x}" ]] || read -r -d '' __helptext <<-'EOF' || true # exits non-zero when EOF encountered 176 | This is Bash3 Boilerplate's help text. Feel free to add any description of your 177 | program or elaborate more on command-line arguments. This section is not 178 | parsed and will be added as-is to the help. 179 | EOF 180 | 181 | # Translate usage string -> getopts arguments, and set $arg_ defaults 182 | while read -r __b3bp_tmp_line; do 183 | if [[ "${__b3bp_tmp_line}" =~ ^- ]]; then 184 | # fetch single character version of option string 185 | __b3bp_tmp_opt="${__b3bp_tmp_line%% *}" 186 | __b3bp_tmp_opt="${__b3bp_tmp_opt:1}" 187 | 188 | # fetch long version if present 189 | __b3bp_tmp_long_opt="" 190 | 191 | if [[ "${__b3bp_tmp_line}" == *"--"* ]]; then 192 | __b3bp_tmp_long_opt="${__b3bp_tmp_line#*--}" 193 | __b3bp_tmp_long_opt="${__b3bp_tmp_long_opt%% *}" 194 | fi 195 | 196 | # map opt long name to+from opt short name 197 | printf -v "__b3bp_tmp_opt_long2short_${__b3bp_tmp_long_opt//-/_}" '%s' "${__b3bp_tmp_opt}" 198 | printf -v "__b3bp_tmp_opt_short2long_${__b3bp_tmp_opt}" '%s' "${__b3bp_tmp_long_opt//-/_}" 199 | 200 | # check if option takes an argument 201 | if [[ "${__b3bp_tmp_line}" =~ \[.*\] ]]; then 202 | __b3bp_tmp_opt="${__b3bp_tmp_opt}:" # add : if opt has arg 203 | __b3bp_tmp_init="" # it has an arg. init with "" 204 | printf -v "__b3bp_tmp_has_arg_${__b3bp_tmp_opt:0:1}" '%s' "1" 205 | elif [[ "${__b3bp_tmp_line}" =~ \{.*\} ]]; then 206 | __b3bp_tmp_opt="${__b3bp_tmp_opt}:" # add : if opt has arg 207 | __b3bp_tmp_init="" # it has an arg. init with "" 208 | # remember that this option requires an argument 209 | printf -v "__b3bp_tmp_has_arg_${__b3bp_tmp_opt:0:1}" '%s' "2" 210 | else 211 | __b3bp_tmp_init="0" # it's a flag. init with 0 212 | printf -v "__b3bp_tmp_has_arg_${__b3bp_tmp_opt:0:1}" '%s' "0" 213 | fi 214 | __b3bp_tmp_opts="${__b3bp_tmp_opts:-}${__b3bp_tmp_opt}" 215 | 216 | if [[ "${__b3bp_tmp_line}" =~ ^Can\ be\ repeated\. ]] || [[ "${__b3bp_tmp_line}" =~ \.\ *Can\ be\ repeated\. ]]; then 217 | # remember that this option can be repeated 218 | printf -v "__b3bp_tmp_is_array_${__b3bp_tmp_opt:0:1}" '%s' "1" 219 | else 220 | printf -v "__b3bp_tmp_is_array_${__b3bp_tmp_opt:0:1}" '%s' "0" 221 | fi 222 | fi 223 | 224 | [[ "${__b3bp_tmp_opt:-}" ]] || continue 225 | 226 | if [[ "${__b3bp_tmp_line}" =~ ^Default= ]] || [[ "${__b3bp_tmp_line}" =~ \.\ *Default= ]]; then 227 | # ignore default value if option does not have an argument 228 | __b3bp_tmp_varname="__b3bp_tmp_has_arg_${__b3bp_tmp_opt:0:1}" 229 | if [[ "${!__b3bp_tmp_varname}" != "0" ]]; then 230 | # take default 231 | __b3bp_tmp_init="${__b3bp_tmp_line##*Default=}" 232 | # strip double quotes from default argument 233 | __b3bp_tmp_re='^"(.*)"$' 234 | if [[ "${__b3bp_tmp_init}" =~ ${__b3bp_tmp_re} ]]; then 235 | __b3bp_tmp_init="${BASH_REMATCH[1]}" 236 | else 237 | # strip single quotes from default argument 238 | __b3bp_tmp_re="^'(.*)'$" 239 | if [[ "${__b3bp_tmp_init}" =~ ${__b3bp_tmp_re} ]]; then 240 | __b3bp_tmp_init="${BASH_REMATCH[1]}" 241 | fi 242 | fi 243 | fi 244 | fi 245 | 246 | if [[ "${__b3bp_tmp_line}" =~ ^Required\. ]] || [[ "${__b3bp_tmp_line}" =~ \.\ *Required\. ]]; then 247 | # remember that this option requires an argument 248 | printf -v "__b3bp_tmp_has_arg_${__b3bp_tmp_opt:0:1}" '%s' "2" 249 | fi 250 | 251 | # Init var with value unless it is an array / a repeatable 252 | __b3bp_tmp_varname="__b3bp_tmp_is_array_${__b3bp_tmp_opt:0:1}" 253 | [[ "${!__b3bp_tmp_varname}" == "0" ]] && printf -v "arg_${__b3bp_tmp_opt:0:1}" '%s' "${__b3bp_tmp_init}" 254 | done <<<"${__usage:-}" 255 | 256 | # run getopts only if options were specified in __usage 257 | if [[ "${__b3bp_tmp_opts:-}" ]]; then 258 | # Allow long options like --this 259 | __b3bp_tmp_opts="${__b3bp_tmp_opts}-:" 260 | 261 | # Reset in case getopts has been used previously in the shell. 262 | OPTIND=1 263 | 264 | # start parsing command line 265 | set +o nounset # unexpected arguments will cause unbound variables 266 | # to be dereferenced 267 | # Overwrite $arg_ defaults with the actual CLI options 268 | while getopts "${__b3bp_tmp_opts}" __b3bp_tmp_opt; do 269 | [[ "${__b3bp_tmp_opt}" == "?" ]] && help "Invalid use of script: ${*} " 270 | 271 | if [[ "${__b3bp_tmp_opt}" == "-" ]]; then 272 | # OPTARG is long-option-name or long-option=value 273 | if [[ "${OPTARG}" =~ .*=.* ]]; then 274 | # --key=value format 275 | __b3bp_tmp_long_opt=${OPTARG/=*/} 276 | # Set opt to the short option corresponding to the long option 277 | __b3bp_tmp_varname="__b3bp_tmp_opt_long2short_${__b3bp_tmp_long_opt//-/_}" 278 | printf -v "__b3bp_tmp_opt" '%s' "${!__b3bp_tmp_varname}" 279 | OPTARG=${OPTARG#*=} 280 | else 281 | # --key value format 282 | # Map long name to short version of option 283 | __b3bp_tmp_varname="__b3bp_tmp_opt_long2short_${OPTARG//-/_}" 284 | printf -v "__b3bp_tmp_opt" '%s' "${!__b3bp_tmp_varname}" 285 | # Only assign OPTARG if option takes an argument 286 | __b3bp_tmp_varname="__b3bp_tmp_has_arg_${__b3bp_tmp_opt}" 287 | __b3bp_tmp_varvalue="${!__b3bp_tmp_varname}" 288 | [[ "${__b3bp_tmp_varvalue}" != "0" ]] && __b3bp_tmp_varvalue="1" 289 | printf -v "OPTARG" '%s' "${@:OPTIND:${__b3bp_tmp_varvalue}}" 290 | # shift over the argument if argument is expected 291 | ((OPTIND += __b3bp_tmp_varvalue)) 292 | fi 293 | # we have set opt/OPTARG to the short value and the argument as OPTARG if it exists 294 | fi 295 | 296 | __b3bp_tmp_value="${OPTARG}" 297 | 298 | __b3bp_tmp_varname="__b3bp_tmp_is_array_${__b3bp_tmp_opt:0:1}" 299 | if [[ "${!__b3bp_tmp_varname}" != "0" ]]; then 300 | # repeatables 301 | # shellcheck disable=SC2016 302 | if [[ -z "${OPTARG}" ]]; then 303 | # repeatable flags, they increcemnt 304 | __b3bp_tmp_varname="arg_${__b3bp_tmp_opt:0:1}" 305 | debug "cli arg ${__b3bp_tmp_varname} = (${__b3bp_tmp_default}) -> ${!__b3bp_tmp_varname}" 306 | __b3bp_tmp_value=$((${!__b3bp_tmp_varname} + 1)) 307 | printf -v "${__b3bp_tmp_varname}" '%s' "${__b3bp_tmp_value}" 308 | else 309 | # repeatable args, they get appended to an array 310 | __b3bp_tmp_varname="arg_${__b3bp_tmp_opt:0:1}[@]" 311 | debug "cli arg ${__b3bp_tmp_varname} append ${__b3bp_tmp_value}" 312 | declare -a "${__b3bp_tmp_varname}"='("${!__b3bp_tmp_varname}" "${__b3bp_tmp_value}")' 313 | fi 314 | else 315 | # non-repeatables 316 | __b3bp_tmp_varname="arg_${__b3bp_tmp_opt:0:1}" 317 | __b3bp_tmp_default="${!__b3bp_tmp_varname}" 318 | 319 | if [[ -z "${OPTARG}" ]]; then 320 | __b3bp_tmp_value=$((__b3bp_tmp_default + 1)) 321 | fi 322 | 323 | printf -v "${__b3bp_tmp_varname}" '%s' "${__b3bp_tmp_value}" 324 | 325 | debug "cli arg ${__b3bp_tmp_varname} = (${__b3bp_tmp_default}) -> ${!__b3bp_tmp_varname}" 326 | fi 327 | done 328 | set -o nounset # no more unbound variable references expected 329 | 330 | shift $((OPTIND - 1)) 331 | 332 | if [[ "${1:-}" == "--" ]]; then 333 | shift 334 | fi 335 | fi 336 | 337 | ### Automatic validation of required option arguments 338 | ############################################################################## 339 | 340 | for __b3bp_tmp_varname in ${!__b3bp_tmp_has_arg_*}; do 341 | # validate only options which required an argument 342 | [[ "${!__b3bp_tmp_varname}" == "2" ]] || continue 343 | 344 | __b3bp_tmp_opt_short="${__b3bp_tmp_varname##*_}" 345 | __b3bp_tmp_varname="arg_${__b3bp_tmp_opt_short}" 346 | [[ "${!__b3bp_tmp_varname}" ]] && continue 347 | 348 | __b3bp_tmp_varname="__b3bp_tmp_opt_short2long_${__b3bp_tmp_opt_short}" 349 | printf -v "__b3bp_tmp_opt_long" '%s' "${!__b3bp_tmp_varname}" 350 | [[ "${__b3bp_tmp_opt_long:-}" ]] && __b3bp_tmp_opt_long=" (--${__b3bp_tmp_opt_long//_/-})" 351 | 352 | help "Option -${__b3bp_tmp_opt_short}${__b3bp_tmp_opt_long:-} requires an argument" 353 | done 354 | 355 | ### Cleanup Environment variables 356 | ############################################################################## 357 | 358 | for __tmp_varname in ${!__b3bp_tmp_*}; do 359 | unset -v "${__tmp_varname}" 360 | done 361 | 362 | unset -v __tmp_varname 363 | 364 | ### Externally supplied __usage. Nothing else to do here 365 | ############################################################################## 366 | 367 | if [[ "${__b3bp_external_usage:-}" == "true" ]]; then 368 | unset -v __b3bp_external_usage 369 | return 370 | fi 371 | 372 | ### Signal trapping and backtracing 373 | ############################################################################## 374 | 375 | function __b3bp_cleanup_before_exit() { 376 | info "Cleaning up. Done" 377 | } 378 | trap __b3bp_cleanup_before_exit EXIT 379 | 380 | # requires `set -o errtrace` 381 | __b3bp_err_report() { 382 | local error_code=${?} 383 | error "Error in ${__file} in function ${1} on line ${2}" 384 | exit ${error_code} 385 | } 386 | # Uncomment the following line for always providing an error backtrace 387 | # trap '__b3bp_err_report "${FUNCNAME:-.}" ${LINENO}' ERR 388 | 389 | ### Command-line argument switches (like -d for debugmode, -h for showing helppage) 390 | ############################################################################## 391 | 392 | # debug mode 393 | if [[ "${arg_d:?}" == "1" ]]; then 394 | set -o xtrace 395 | PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }' 396 | LOG_LEVEL="7" 397 | # Enable error backtracing 398 | trap '__b3bp_err_report "${FUNCNAME:-.}" ${LINENO}' ERR 399 | fi 400 | 401 | # verbose mode 402 | if [[ "${arg_v:?}" == "1" ]]; then 403 | set -o verbose 404 | fi 405 | 406 | # no color mode 407 | if [[ "${arg_n:?}" == "1" ]]; then 408 | NO_COLOR="true" 409 | fi 410 | 411 | # help mode 412 | if [[ "${arg_h:?}" == "1" ]]; then 413 | # Help exists with code 1 414 | help "Help using ${0}" 415 | fi 416 | 417 | ### Validation. Error out if the things required for your script are not present 418 | ############################################################################## 419 | 420 | [[ "${arg_f:-}" ]] || help "Setting a filename with -f or --file is required" 421 | [[ "${LOG_LEVEL:-}" ]] || emergency "Cannot continue without LOG_LEVEL. " 422 | 423 | ### Runtime 424 | ############################################################################## 425 | 426 | info "__i_am_main_script: ${__i_am_main_script}" 427 | info "__file: ${__file}" 428 | info "__dir: ${__dir}" 429 | info "__base: ${__base}" 430 | info "OSTYPE: ${OSTYPE}" 431 | 432 | info "arg_f: ${arg_f}" 433 | info "arg_d: ${arg_d}" 434 | info "arg_v: ${arg_v}" 435 | info "arg_h: ${arg_h}" 436 | 437 | # shellcheck disable=SC2015 438 | if [[ -n "${arg_i:-}" ]] && declare -p arg_i 2>/dev/null | grep -q '^declare \-a'; then 439 | info "arg_i:" 440 | for input_file in "${arg_i[@]}"; do 441 | info " - ${input_file}" 442 | done 443 | elif [[ -n "${arg_i:-}" ]]; then 444 | info "arg_i: ${arg_i}" 445 | else 446 | info "arg_i: 0" 447 | fi 448 | 449 | # shellcheck disable=SC2015 450 | if [[ -n "${arg_x:-}" ]] && declare -p arg_x 2>/dev/null | grep -q '^declare \-a'; then 451 | info "arg_x: ${#arg_x[@]}" 452 | elif [[ -n "${arg_x:-}" ]]; then 453 | info "arg_x: ${arg_x}" 454 | else 455 | info "arg_x: 0" 456 | fi 457 | 458 | info "$(echo -e "multiple lines example - line #1\\nmultiple lines example - line #2\\nimagine logging the output of 'ls -al /path/'")" 459 | 460 | # All of these go to STDERR, so you can use STDOUT for piping machine readable information to other software 461 | debug "Info useful to developers for debugging the application, not useful during operations." 462 | info "Normal operational messages - may be harvested for reporting, measuring throughput, etc. - no action required." 463 | notice "Events that are unusual but not error conditions - might be summarized in an email to developers or admins to spot potential problems - no immediate action required." 464 | warning "Warning messages, not an error, but indication that an error will occur if action is not taken, e.g. file system 85% full - each item must be resolved within a given time. This is a debug message" 465 | error "Non-urgent failures, these should be relayed to developers or admins; each item must be resolved within a given time." 466 | critical "Should be corrected immediately, but indicates failure in a primary system, an example is a loss of a backup ISP connection." 467 | alert "Should be corrected immediately, therefore notify staff who can fix the problem. An example would be the loss of a primary ISP connection." 468 | emergency "A \"panic\" condition usually affecting multiple apps/servers/sites. At this level it would usually notify all tech staff on call." 469 | ­ 470 | -------------------------------------------------------------------------------- /model/data.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type User struct { 4 | FirstName string 5 | Email string 6 | FavoriteColors []string 7 | RawContent string 8 | EscapedContent string 9 | } 10 | 11 | type Navigation struct { 12 | Item string 13 | Link string 14 | } -------------------------------------------------------------------------------- /mustache/base.mustache: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
    6 | {{> header}} 7 |
    8 | 9 | 12 | 13 |
    14 | {{{content}}} 15 |
    16 | 17 |
    18 | {{> footer}} 19 |
    20 | 21 | 22 | -------------------------------------------------------------------------------- /mustache/footer.mustache: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /mustache/header.mustache: -------------------------------------------------------------------------------- 1 | {{ Title }}'s Home Page 2 |
    Page Header
    -------------------------------------------------------------------------------- /mustache/index.mustache: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |

    Hello {{ User.FirstName }}

    4 | 5 |
    {{{User.RawContent}}}
    6 |
    {{ User.EscapedContent }}
    7 |
    8 | {{#Messages}} 9 |

    {{ User.FirstName }} has {{ I }} message{{#Plural}}s{{/Plural}}

    10 | {{/Messages}} 11 |
    -------------------------------------------------------------------------------- /mustache/navigation.mustache: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /mustache/simple.mustache: -------------------------------------------------------------------------------- 1 | 2 | 3 |

    {{FirstName}}

    4 | 5 |

    Here's a list of your favorite colors:

    6 | 11 | 12 | -------------------------------------------------------------------------------- /pongo2/simple.pongo: -------------------------------------------------------------------------------- 1 | 2 | 3 |

    {{ u.FirstName }}

    4 | 5 |

    Here's a list of your favorite colors:

    6 | 11 | 12 | -------------------------------------------------------------------------------- /quicktemplate/footer.qtpl: -------------------------------------------------------------------------------- 1 | {% func Footer() %} 2 | 3 | {% endfunc %} -------------------------------------------------------------------------------- /quicktemplate/footer.qtpl.go: -------------------------------------------------------------------------------- 1 | // Code generated by qtc from "footer.qtpl". DO NOT EDIT. 2 | // See https://github.com/valyala/quicktemplate for details. 3 | 4 | //line quicktemplate/footer.qtpl:1 5 | package quicktemplate 6 | 7 | //line quicktemplate/footer.qtpl:1 8 | import ( 9 | qtio422016 "io" 10 | 11 | qt422016 "github.com/valyala/quicktemplate" 12 | ) 13 | 14 | //line quicktemplate/footer.qtpl:1 15 | var ( 16 | _ = qtio422016.Copy 17 | _ = qt422016.AcquireByteBuffer 18 | ) 19 | 20 | //line quicktemplate/footer.qtpl:1 21 | func StreamFooter(qw422016 *qt422016.Writer) { 22 | //line quicktemplate/footer.qtpl:1 23 | qw422016.N().S(` 24 | 25 | `) 26 | //line quicktemplate/footer.qtpl:3 27 | } 28 | 29 | //line quicktemplate/footer.qtpl:3 30 | func WriteFooter(qq422016 qtio422016.Writer) { 31 | //line quicktemplate/footer.qtpl:3 32 | qw422016 := qt422016.AcquireWriter(qq422016) 33 | //line quicktemplate/footer.qtpl:3 34 | StreamFooter(qw422016) 35 | //line quicktemplate/footer.qtpl:3 36 | qt422016.ReleaseWriter(qw422016) 37 | //line quicktemplate/footer.qtpl:3 38 | } 39 | 40 | //line quicktemplate/footer.qtpl:3 41 | func Footer() string { 42 | //line quicktemplate/footer.qtpl:3 43 | qb422016 := qt422016.AcquireByteBuffer() 44 | //line quicktemplate/footer.qtpl:3 45 | WriteFooter(qb422016) 46 | //line quicktemplate/footer.qtpl:3 47 | qs422016 := string(qb422016.B) 48 | //line quicktemplate/footer.qtpl:3 49 | qt422016.ReleaseByteBuffer(qb422016) 50 | //line quicktemplate/footer.qtpl:3 51 | return qs422016 52 | //line quicktemplate/footer.qtpl:3 53 | } 54 | -------------------------------------------------------------------------------- /quicktemplate/header.qtpl: -------------------------------------------------------------------------------- 1 | {% func Header(title string) %} 2 | {%s title %}'s Home Page 3 |
    Page Header
    4 | {% endfunc %} -------------------------------------------------------------------------------- /quicktemplate/header.qtpl.go: -------------------------------------------------------------------------------- 1 | // Code generated by qtc from "header.qtpl". DO NOT EDIT. 2 | // See https://github.com/valyala/quicktemplate for details. 3 | 4 | //line quicktemplate/header.qtpl:1 5 | package quicktemplate 6 | 7 | //line quicktemplate/header.qtpl:1 8 | import ( 9 | qtio422016 "io" 10 | 11 | qt422016 "github.com/valyala/quicktemplate" 12 | ) 13 | 14 | //line quicktemplate/header.qtpl:1 15 | var ( 16 | _ = qtio422016.Copy 17 | _ = qt422016.AcquireByteBuffer 18 | ) 19 | 20 | //line quicktemplate/header.qtpl:1 21 | func StreamHeader(qw422016 *qt422016.Writer, title string) { 22 | //line quicktemplate/header.qtpl:1 23 | qw422016.N().S(` 24 | `) 25 | //line quicktemplate/header.qtpl:2 26 | qw422016.E().S(title) 27 | //line quicktemplate/header.qtpl:2 28 | qw422016.N().S(`'s Home Page 29 |
    Page Header
    30 | `) 31 | //line quicktemplate/header.qtpl:4 32 | } 33 | 34 | //line quicktemplate/header.qtpl:4 35 | func WriteHeader(qq422016 qtio422016.Writer, title string) { 36 | //line quicktemplate/header.qtpl:4 37 | qw422016 := qt422016.AcquireWriter(qq422016) 38 | //line quicktemplate/header.qtpl:4 39 | StreamHeader(qw422016, title) 40 | //line quicktemplate/header.qtpl:4 41 | qt422016.ReleaseWriter(qw422016) 42 | //line quicktemplate/header.qtpl:4 43 | } 44 | 45 | //line quicktemplate/header.qtpl:4 46 | func Header(title string) string { 47 | //line quicktemplate/header.qtpl:4 48 | qb422016 := qt422016.AcquireByteBuffer() 49 | //line quicktemplate/header.qtpl:4 50 | WriteHeader(qb422016, title) 51 | //line quicktemplate/header.qtpl:4 52 | qs422016 := string(qb422016.B) 53 | //line quicktemplate/header.qtpl:4 54 | qt422016.ReleaseByteBuffer(qb422016) 55 | //line quicktemplate/header.qtpl:4 56 | return qs422016 57 | //line quicktemplate/header.qtpl:4 58 | } 59 | -------------------------------------------------------------------------------- /quicktemplate/index.qtpl: -------------------------------------------------------------------------------- 1 | {% import "github.com/SlinSo/goTemplateBenchmark/model" %} 2 | {% func Index(u *model.User, nav []*model.Navigation, title string) %} 3 | 4 | 5 | 6 | 7 |
    8 | {%= Header(title) %} 9 |
    10 | 11 | 14 | 15 |
    16 |
    17 |
    18 |

    Hello {%s u.FirstName %}

    19 | 20 |
    {%s= u.RawContent %}
    21 |
    {%s u.EscapedContent %}
    22 |
    23 | 24 | {% for i := 1; i <= 5; i++ %} 25 | {% if i == 1 %} 26 |

    {%s u.FirstName %} has {%d i %} message

    27 | {% else %} 28 |

    {%s u.FirstName %} has {%d i %} messages

    29 | {% endif %} 30 | {% endfor %} 31 |
    32 |
    33 | 34 |
    35 | {%= Footer() %} 36 |
    37 | 38 | 39 | 40 | {% endfunc %} -------------------------------------------------------------------------------- /quicktemplate/index.qtpl.go: -------------------------------------------------------------------------------- 1 | // Code generated by qtc from "index.qtpl". DO NOT EDIT. 2 | // See https://github.com/valyala/quicktemplate for details. 3 | 4 | //line quicktemplate/index.qtpl:1 5 | package quicktemplate 6 | 7 | //line quicktemplate/index.qtpl:1 8 | import "github.com/SlinSo/goTemplateBenchmark/model" 9 | 10 | //line quicktemplate/index.qtpl:2 11 | import ( 12 | qtio422016 "io" 13 | 14 | qt422016 "github.com/valyala/quicktemplate" 15 | ) 16 | 17 | //line quicktemplate/index.qtpl:2 18 | var ( 19 | _ = qtio422016.Copy 20 | _ = qt422016.AcquireByteBuffer 21 | ) 22 | 23 | //line quicktemplate/index.qtpl:2 24 | func StreamIndex(qw422016 *qt422016.Writer, u *model.User, nav []*model.Navigation, title string) { 25 | //line quicktemplate/index.qtpl:2 26 | qw422016.N().S(` 27 | 28 | 29 | 30 | 31 |
    32 | `) 33 | //line quicktemplate/index.qtpl:8 34 | StreamHeader(qw422016, title) 35 | //line quicktemplate/index.qtpl:8 36 | qw422016.N().S(` 37 |
    38 | 39 | 46 | 47 |
    48 |
    49 |
    50 |

    Hello `) 51 | //line quicktemplate/index.qtpl:18 52 | qw422016.E().S(u.FirstName) 53 | //line quicktemplate/index.qtpl:18 54 | qw422016.N().S(`

    55 | 56 |
    `) 57 | //line quicktemplate/index.qtpl:20 58 | qw422016.N().S(u.RawContent) 59 | //line quicktemplate/index.qtpl:20 60 | qw422016.N().S(`
    61 |
    `) 62 | //line quicktemplate/index.qtpl:21 63 | qw422016.E().S(u.EscapedContent) 64 | //line quicktemplate/index.qtpl:21 65 | qw422016.N().S(`
    66 |
    67 | 68 | `) 69 | //line quicktemplate/index.qtpl:24 70 | for i := 1; i <= 5; i++ { 71 | //line quicktemplate/index.qtpl:24 72 | qw422016.N().S(` 73 | `) 74 | //line quicktemplate/index.qtpl:25 75 | if i == 1 { 76 | //line quicktemplate/index.qtpl:25 77 | qw422016.N().S(` 78 |

    `) 79 | //line quicktemplate/index.qtpl:26 80 | qw422016.E().S(u.FirstName) 81 | //line quicktemplate/index.qtpl:26 82 | qw422016.N().S(` has `) 83 | //line quicktemplate/index.qtpl:26 84 | qw422016.N().D(i) 85 | //line quicktemplate/index.qtpl:26 86 | qw422016.N().S(` message

    87 | `) 88 | //line quicktemplate/index.qtpl:27 89 | } else { 90 | //line quicktemplate/index.qtpl:27 91 | qw422016.N().S(` 92 |

    `) 93 | //line quicktemplate/index.qtpl:28 94 | qw422016.E().S(u.FirstName) 95 | //line quicktemplate/index.qtpl:28 96 | qw422016.N().S(` has `) 97 | //line quicktemplate/index.qtpl:28 98 | qw422016.N().D(i) 99 | //line quicktemplate/index.qtpl:28 100 | qw422016.N().S(` messages

    101 | `) 102 | //line quicktemplate/index.qtpl:29 103 | } 104 | //line quicktemplate/index.qtpl:29 105 | qw422016.N().S(` 106 | `) 107 | //line quicktemplate/index.qtpl:30 108 | } 109 | //line quicktemplate/index.qtpl:30 110 | qw422016.N().S(` 111 |
    112 |
    113 | 114 |
    115 | `) 116 | //line quicktemplate/index.qtpl:35 117 | StreamFooter(qw422016) 118 | //line quicktemplate/index.qtpl:35 119 | qw422016.N().S(` 120 |
    121 | 122 | 123 | 124 | `) 125 | //line quicktemplate/index.qtpl:40 126 | } 127 | 128 | //line quicktemplate/index.qtpl:40 129 | func WriteIndex(qq422016 qtio422016.Writer, u *model.User, nav []*model.Navigation, title string) { 130 | //line quicktemplate/index.qtpl:40 131 | qw422016 := qt422016.AcquireWriter(qq422016) 132 | //line quicktemplate/index.qtpl:40 133 | StreamIndex(qw422016, u, nav, title) 134 | //line quicktemplate/index.qtpl:40 135 | qt422016.ReleaseWriter(qw422016) 136 | //line quicktemplate/index.qtpl:40 137 | } 138 | 139 | //line quicktemplate/index.qtpl:40 140 | func Index(u *model.User, nav []*model.Navigation, title string) string { 141 | //line quicktemplate/index.qtpl:40 142 | qb422016 := qt422016.AcquireByteBuffer() 143 | //line quicktemplate/index.qtpl:40 144 | WriteIndex(qb422016, u, nav, title) 145 | //line quicktemplate/index.qtpl:40 146 | qs422016 := string(qb422016.B) 147 | //line quicktemplate/index.qtpl:40 148 | qt422016.ReleaseByteBuffer(qb422016) 149 | //line quicktemplate/index.qtpl:40 150 | return qs422016 151 | //line quicktemplate/index.qtpl:40 152 | } 153 | -------------------------------------------------------------------------------- /quicktemplate/navigation.qtpl: -------------------------------------------------------------------------------- 1 | {% import "github.com/SlinSo/goTemplateBenchmark/model" %} 2 | {% func Navigation(nav []*model.Navigation) %} 3 | 8 | {% endfunc %} -------------------------------------------------------------------------------- /quicktemplate/navigation.qtpl.go: -------------------------------------------------------------------------------- 1 | // Code generated by qtc from "navigation.qtpl". DO NOT EDIT. 2 | // See https://github.com/valyala/quicktemplate for details. 3 | 4 | //line quicktemplate/navigation.qtpl:1 5 | package quicktemplate 6 | 7 | //line quicktemplate/navigation.qtpl:1 8 | import "github.com/SlinSo/goTemplateBenchmark/model" 9 | 10 | //line quicktemplate/navigation.qtpl:2 11 | import ( 12 | qtio422016 "io" 13 | 14 | qt422016 "github.com/valyala/quicktemplate" 15 | ) 16 | 17 | //line quicktemplate/navigation.qtpl:2 18 | var ( 19 | _ = qtio422016.Copy 20 | _ = qt422016.AcquireByteBuffer 21 | ) 22 | 23 | //line quicktemplate/navigation.qtpl:2 24 | func StreamNavigation(qw422016 *qt422016.Writer, nav []*model.Navigation) { 25 | //line quicktemplate/navigation.qtpl:2 26 | qw422016.N().S(` 27 | 48 | `) 49 | //line quicktemplate/navigation.qtpl:8 50 | } 51 | 52 | //line quicktemplate/navigation.qtpl:8 53 | func WriteNavigation(qq422016 qtio422016.Writer, nav []*model.Navigation) { 54 | //line quicktemplate/navigation.qtpl:8 55 | qw422016 := qt422016.AcquireWriter(qq422016) 56 | //line quicktemplate/navigation.qtpl:8 57 | StreamNavigation(qw422016, nav) 58 | //line quicktemplate/navigation.qtpl:8 59 | qt422016.ReleaseWriter(qw422016) 60 | //line quicktemplate/navigation.qtpl:8 61 | } 62 | 63 | //line quicktemplate/navigation.qtpl:8 64 | func Navigation(nav []*model.Navigation) string { 65 | //line quicktemplate/navigation.qtpl:8 66 | qb422016 := qt422016.AcquireByteBuffer() 67 | //line quicktemplate/navigation.qtpl:8 68 | WriteNavigation(qb422016, nav) 69 | //line quicktemplate/navigation.qtpl:8 70 | qs422016 := string(qb422016.B) 71 | //line quicktemplate/navigation.qtpl:8 72 | qt422016.ReleaseByteBuffer(qb422016) 73 | //line quicktemplate/navigation.qtpl:8 74 | return qs422016 75 | //line quicktemplate/navigation.qtpl:8 76 | } 77 | -------------------------------------------------------------------------------- /quicktemplate/simple.qtpl: -------------------------------------------------------------------------------- 1 | {% import "github.com/SlinSo/goTemplateBenchmark/model" %} 2 | {% func SimpleQtc(u *model.User) %} 3 | 4 | 5 |

    {%s u.FirstName %}

    6 | 7 |

    Here's a list of your favorite colors:

    8 | 13 | 14 | 15 | {% endfunc %} -------------------------------------------------------------------------------- /quicktemplate/simple.qtpl.go: -------------------------------------------------------------------------------- 1 | // Code generated by qtc from "simple.qtpl". DO NOT EDIT. 2 | // See https://github.com/valyala/quicktemplate for details. 3 | 4 | //line quicktemplate/simple.qtpl:1 5 | package quicktemplate 6 | 7 | //line quicktemplate/simple.qtpl:1 8 | import "github.com/SlinSo/goTemplateBenchmark/model" 9 | 10 | //line quicktemplate/simple.qtpl:2 11 | import ( 12 | qtio422016 "io" 13 | 14 | qt422016 "github.com/valyala/quicktemplate" 15 | ) 16 | 17 | //line quicktemplate/simple.qtpl:2 18 | var ( 19 | _ = qtio422016.Copy 20 | _ = qt422016.AcquireByteBuffer 21 | ) 22 | 23 | //line quicktemplate/simple.qtpl:2 24 | func StreamSimpleQtc(qw422016 *qt422016.Writer, u *model.User) { 25 | //line quicktemplate/simple.qtpl:2 26 | qw422016.N().S(` 27 | 28 | 29 |

    `) 30 | //line quicktemplate/simple.qtpl:5 31 | qw422016.E().S(u.FirstName) 32 | //line quicktemplate/simple.qtpl:5 33 | qw422016.N().S(`

    34 | 35 |

    Here's a list of your favorite colors:

    36 | 53 | 54 | 55 | `) 56 | //line quicktemplate/simple.qtpl:15 57 | } 58 | 59 | //line quicktemplate/simple.qtpl:15 60 | func WriteSimpleQtc(qq422016 qtio422016.Writer, u *model.User) { 61 | //line quicktemplate/simple.qtpl:15 62 | qw422016 := qt422016.AcquireWriter(qq422016) 63 | //line quicktemplate/simple.qtpl:15 64 | StreamSimpleQtc(qw422016, u) 65 | //line quicktemplate/simple.qtpl:15 66 | qt422016.ReleaseWriter(qw422016) 67 | //line quicktemplate/simple.qtpl:15 68 | } 69 | 70 | //line quicktemplate/simple.qtpl:15 71 | func SimpleQtc(u *model.User) string { 72 | //line quicktemplate/simple.qtpl:15 73 | qb422016 := qt422016.AcquireByteBuffer() 74 | //line quicktemplate/simple.qtpl:15 75 | WriteSimpleQtc(qb422016, u) 76 | //line quicktemplate/simple.qtpl:15 77 | qs422016 := string(qb422016.B) 78 | //line quicktemplate/simple.qtpl:15 79 | qt422016.ReleaseByteBuffer(qb422016) 80 | //line quicktemplate/simple.qtpl:15 81 | return qs422016 82 | //line quicktemplate/simple.qtpl:15 83 | } 84 | -------------------------------------------------------------------------------- /raymond/simple.handle: -------------------------------------------------------------------------------- 1 | 2 | 3 |

    {{FirstName}}

    4 | 5 |

    Here's a list of your favorite colors:

    6 | 11 | 12 | -------------------------------------------------------------------------------- /soy/simple.soy: -------------------------------------------------------------------------------- 1 | {namespace soy} 2 | 3 | /** 4 | * Greets a person and optionally a list of other people. 5 | * @param user model.User 6 | */ 7 | {template .simple} 8 | 9 | 10 |

    {$user.firstName}

    11 | 12 |

    Here's a list of your favorite colors:

    13 | 18 | 19 | 20 | {/template} -------------------------------------------------------------------------------- /templates_complex_test.go: -------------------------------------------------------------------------------- 1 | package main_test 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "html" 7 | "html/template" 8 | "path/filepath" 9 | "testing" 10 | text "text/template" 11 | 12 | "github.com/SlinSo/goTemplateBenchmark/golang" 13 | "github.com/SlinSo/goTemplateBenchmark/model" 14 | "github.com/SlinSo/goTemplateBenchmark/templbench" 15 | "github.com/valyala/bytebufferpool" 16 | 17 | "github.com/SlinSo/goTemplateBenchmark/ego" 18 | "github.com/SlinSo/goTemplateBenchmark/ftmpl" 19 | goh "github.com/SlinSo/goTemplateBenchmark/goh" 20 | "github.com/SlinSo/goTemplateBenchmark/gorazor" 21 | herotmpl "github.com/SlinSo/goTemplateBenchmark/hero" 22 | "github.com/SlinSo/goTemplateBenchmark/jade" 23 | "github.com/SlinSo/goTemplateBenchmark/quicktemplate" 24 | "github.com/hoisie/mustache" 25 | ) 26 | 27 | type tmplData struct { 28 | User *model.User 29 | Nav []*model.Navigation 30 | Title string 31 | Messages []struct { 32 | I int 33 | Plural bool 34 | } 35 | } 36 | 37 | var ( 38 | testComplexUser = &model.User{ 39 | FirstName: "Bob", 40 | FavoriteColors: []string{"blue", "green", "mauve"}, 41 | RawContent: "

    Raw Content to be displayed

    ", 42 | EscapedContent: "
    Escaped
    ", 43 | } 44 | 45 | testComplexNav = []*model.Navigation{ 46 | { 47 | Item: "Link 1", 48 | Link: "http://www.mytest.com/", 49 | }, { 50 | Item: "Link 2", 51 | Link: "http://www.mytest.com/", 52 | }, { 53 | Item: "Link 3", 54 | Link: "http://www.mytest.com/", 55 | }, 56 | } 57 | testComplexTitle = testComplexUser.FirstName 58 | 59 | testComplexData = tmplData{ 60 | User: testComplexUser, 61 | Nav: testComplexNav, 62 | Title: testComplexTitle, 63 | Messages: []struct { 64 | I int 65 | Plural bool 66 | }{{1, false}, {2, true}, {3, true}, {4, true}, {5, true}}, 67 | } 68 | 69 | expectedtComplexResult = ` 70 | 71 | 72 | 73 |
    Bob's Home Page 74 |
    Page Header
    75 |
    76 | 77 | 83 | 84 |
    85 | 86 |
    87 |
    88 |

    Hello Bob

    89 | 90 |

    Raw Content to be displayed

    91 |
    <div><div><div>Escaped</div></div></div>
    92 |

    Bob has 1 message

    Bob has 2 messages

    Bob has 3 messages

    Bob has 4 messages

    Bob has 5 messages

    93 |
    94 |
    95 | 96 |
    97 |
    98 | 99 | 100 | ` 101 | 102 | expectedtComplexResultMinified = "

    Bob

    Here's a list of your favorite colors:

    " 103 | ) 104 | 105 | /****************************************************************************** 106 | ** Go 107 | ******************************************************************************/ 108 | func TestComplexGolang(t *testing.T) { 109 | var buf bytes.Buffer 110 | 111 | funcMap := template.FuncMap{ 112 | "safehtml": func(text string) template.HTML { return template.HTML(text) }, 113 | } 114 | 115 | templates := make(map[string]*template.Template) 116 | templatesDir := "go/" 117 | 118 | layouts, err := filepath.Glob(templatesDir + "layout/*.tmpl") 119 | if err != nil { 120 | panic(err) 121 | } 122 | 123 | includes, err := filepath.Glob(templatesDir + "includes/*.tmpl") 124 | if err != nil { 125 | panic(err) 126 | } 127 | 128 | // Generate our templates map from our layouts/ and includes/ directories 129 | for _, layout := range layouts { 130 | files := append(includes, layout) 131 | templates[filepath.Base(layout)] = template.Must(template.New("").Funcs(funcMap).ParseFiles(files...)) 132 | } 133 | templates["index.tmpl"].ExecuteTemplate(&buf, "base", testComplexData) 134 | 135 | if msg, ok := linesEquals(buf.String(), expectedtComplexResult); !ok { 136 | t.Error(msg) 137 | } 138 | } 139 | 140 | func TestComplexGolangText(t *testing.T) { 141 | var buf bytes.Buffer 142 | 143 | funcMap := text.FuncMap{ 144 | "safehtml": func(s string) string { return s }, 145 | } 146 | 147 | templates := make(map[string]*text.Template) 148 | templatesDir := "go/" 149 | 150 | layouts, err := filepath.Glob(templatesDir + "layout/*.tmpl") 151 | if err != nil { 152 | panic(err) 153 | } 154 | 155 | includes, err := filepath.Glob(templatesDir + "includes/*.tmpl") 156 | if err != nil { 157 | panic(err) 158 | } 159 | 160 | tempData := testComplexData.User.EscapedContent 161 | testComplexData.User.EscapedContent = text.HTMLEscapeString(testComplexData.User.EscapedContent) 162 | 163 | // Generate our templates map from our layouts/ and includes/ directories 164 | for _, layout := range layouts { 165 | files := append(includes, layout) 166 | templates[filepath.Base(layout)] = text.Must(text.New("").Funcs(funcMap).ParseFiles(files...)) 167 | } 168 | templates["index.tmpl"].ExecuteTemplate(&buf, "base", testComplexData) 169 | 170 | if msg, ok := linesEquals(buf.String(), expectedtComplexResult); !ok { 171 | t.Error(msg) 172 | } 173 | testComplexData.User.EscapedContent = tempData 174 | } 175 | 176 | func BenchmarkComplexGolang(b *testing.B) { 177 | var buf bytes.Buffer 178 | 179 | funcMap := template.FuncMap{ 180 | "safehtml": func(text string) template.HTML { return template.HTML(text) }, 181 | } 182 | 183 | templates := make(map[string]*template.Template) 184 | templatesDir := "go/" 185 | 186 | layouts, err := filepath.Glob(templatesDir + "layout/*.tmpl") 187 | if err != nil { 188 | panic(err) 189 | } 190 | 191 | includes, err := filepath.Glob(templatesDir + "includes/*.tmpl") 192 | if err != nil { 193 | panic(err) 194 | } 195 | 196 | // Generate our templates map from our layouts/ and includes/ directories 197 | for _, layout := range layouts { 198 | files := append(includes, layout) 199 | templates[filepath.Base(layout)] = template.Must(template.New("").Funcs(funcMap).ParseFiles(files...)) 200 | } 201 | b.ResetTimer() 202 | 203 | for i := 0; i < b.N; i++ { 204 | templates["index.tmpl"].ExecuteTemplate(&buf, "base", testComplexData) 205 | buf.Reset() 206 | } 207 | } 208 | 209 | func BenchmarkComplexGolangText(b *testing.B) { 210 | var buf bytes.Buffer 211 | 212 | funcMap := text.FuncMap{ 213 | "safehtml": func(s string) string { return s }, 214 | } 215 | 216 | templates := make(map[string]*text.Template) 217 | templatesDir := "go/" 218 | 219 | layouts, err := filepath.Glob(templatesDir + "layout/*.tmpl") 220 | if err != nil { 221 | panic(err) 222 | } 223 | 224 | includes, err := filepath.Glob(templatesDir + "includes/*.tmpl") 225 | if err != nil { 226 | panic(err) 227 | } 228 | 229 | tempData := testComplexData.User.EscapedContent 230 | testComplexData.User.EscapedContent = text.HTMLEscapeString(testComplexData.User.EscapedContent) 231 | 232 | // Generate our templates map from our layouts/ and includes/ directories 233 | for _, layout := range layouts { 234 | files := append(includes, layout) 235 | templates[filepath.Base(layout)] = text.Must(text.New("").Funcs(funcMap).ParseFiles(files...)) 236 | } 237 | b.ResetTimer() 238 | 239 | for i := 0; i < b.N; i++ { 240 | templates["index.tmpl"].ExecuteTemplate(&buf, "base", testComplexData) 241 | buf.Reset() 242 | } 243 | testComplexData.User.EscapedContent = tempData 244 | } 245 | 246 | /****************************************************************************** 247 | ** Ego 248 | ******************************************************************************/ 249 | func TestComplexEgo(t *testing.T) { 250 | var buf bytes.Buffer 251 | ego.EgoComplex(&buf, testComplexUser, testComplexNav, testComplexTitle) 252 | 253 | if msg, ok := linesEquals(buf.String(), expectedtComplexResult); !ok { 254 | t.Error(msg) 255 | } 256 | } 257 | 258 | func BenchmarkComplexEgo(b *testing.B) { 259 | var buf bytes.Buffer 260 | 261 | for i := 0; i < b.N; i++ { 262 | ego.EgoComplex(&buf, testComplexUser, testComplexNav, testComplexTitle) 263 | buf.Reset() 264 | } 265 | } 266 | 267 | /****************************************************************************** 268 | ** Quicktemplate 269 | ******************************************************************************/ 270 | func TestComplexQuicktemplate(t *testing.T) { 271 | var buf bytes.Buffer 272 | quicktemplate.WriteIndex(&buf, testComplexUser, testComplexNav, testComplexTitle) 273 | 274 | if msg, ok := linesEquals(buf.String(), expectedtComplexResult); !ok { 275 | t.Error(msg) 276 | } 277 | } 278 | 279 | func BenchmarkComplexQuicktemplate(b *testing.B) { 280 | var buf bytes.Buffer 281 | 282 | for i := 0; i < b.N; i++ { 283 | quicktemplate.WriteIndex(&buf, testComplexUser, testComplexNav, testComplexTitle) 284 | buf.Reset() 285 | } 286 | } 287 | 288 | /****************************************************************************** 289 | ** templ 290 | ******************************************************************************/ 291 | func TestComplexTempl(t *testing.T) { 292 | var buf bytes.Buffer 293 | templbench.Index(testComplexUser, testComplexNav, testComplexTitle).Render(context.Background(), &buf) 294 | 295 | if msg, ok := linesEquals(buf.String(), expectedtComplexResult); !ok { 296 | t.Error(msg) 297 | } 298 | } 299 | 300 | func BenchmarkComplexTempl(b *testing.B) { 301 | var buf bytes.Buffer 302 | 303 | for i := 0; i < b.N; i++ { 304 | templbench.Index(testComplexUser, testComplexNav, testComplexTitle).Render(context.Background(), &buf) 305 | buf.Reset() 306 | } 307 | } 308 | 309 | /****************************************************************************** 310 | ** ftmpl 311 | ******************************************************************************/ 312 | func TestComplexFtmpl(t *testing.T) { 313 | result := ftmpl.TMPLindex(testComplexUser, testComplexNav, testComplexTitle) 314 | 315 | if msg, ok := linesEquals(result, expectedtComplexResult); !ok { 316 | t.Error(msg) 317 | } 318 | } 319 | 320 | func BenchmarkComplexFtmpl(b *testing.B) { 321 | for i := 0; i < b.N; i++ { 322 | _ = ftmpl.TMPLindex(testComplexUser, testComplexNav, testComplexTitle) 323 | } 324 | } 325 | 326 | func TestComplexFtmplInclude(t *testing.T) { 327 | result := ftmpl.TMPLindex2(testComplexUser, testComplexNav, testComplexTitle) 328 | 329 | if msg, ok := linesEquals(result, expectedtComplexResult); !ok { 330 | t.Error(msg) 331 | } 332 | } 333 | 334 | func BenchmarkComplexFtmplInclude(b *testing.B) { 335 | for i := 0; i < b.N; i++ { 336 | _ = ftmpl.TMPLindex2(testComplexUser, testComplexNav, testComplexTitle) 337 | } 338 | } 339 | 340 | /****************************************************************************** 341 | ** Mustache 342 | ******************************************************************************/ 343 | func TestComplexMustache(t *testing.T) { 344 | layoutTmpl, err := mustache.ParseFile("mustache/base.mustache") 345 | if err != nil { 346 | t.Error(err) 347 | } 348 | tmpl, err := mustache.ParseFile("mustache/index.mustache") 349 | if err != nil { 350 | t.Error(err) 351 | } 352 | 353 | result := tmpl.RenderInLayout(layoutTmpl, testComplexData) 354 | 355 | if msg, ok := linesEquals(result, expectedtComplexResult); !ok { 356 | t.Error(msg) 357 | } 358 | } 359 | 360 | func BenchmarkComplexMustache(b *testing.B) { 361 | layoutTmpl, _ := mustache.ParseFile("mustache/base.mustache") 362 | tmpl, _ := mustache.ParseFile("mustache/index.mustache") 363 | 364 | b.ResetTimer() 365 | 366 | for i := 0; i < b.N; i++ { 367 | tmpl.RenderInLayout(layoutTmpl, testComplexData) 368 | } 369 | } 370 | 371 | /****************************************************************************** 372 | ** gorazor 373 | ******************************************************************************/ 374 | func TestComplexGorazor(t *testing.T) { 375 | result := gorazor.Index(testComplexUser, testComplexNav, testComplexTitle) 376 | 377 | if msg, ok := linesEquals(result, expectedtComplexResult); !ok { 378 | t.Error(msg) 379 | } 380 | } 381 | 382 | func BenchmarkComplexGorazor(b *testing.B) { 383 | for i := 0; i < b.N; i++ { 384 | gorazor.Index(testComplexUser, testComplexNav, testComplexTitle) 385 | } 386 | } 387 | 388 | /****************************************************************************** 389 | ** Jet 390 | ******************************************************************************/ 391 | 392 | func TestComplexJetHTML(t *testing.T) { 393 | var buf bytes.Buffer 394 | 395 | tmpl, err := jetSet.GetTemplate("index.jet") 396 | if err != nil { 397 | t.Error(err) 398 | } 399 | err = tmpl.Execute(&buf, nil, testComplexData) 400 | if err != nil { 401 | t.Error(err) 402 | } 403 | 404 | if msg, ok := linesEquals(buf.String(), expectedtComplexResult); !ok { 405 | t.Error(msg) 406 | } 407 | } 408 | 409 | func BenchmarkComplexJetHTML(b *testing.B) { 410 | var buf bytes.Buffer 411 | 412 | tmpl, _ := jetSet.GetTemplate("index.jet") 413 | b.ResetTimer() 414 | 415 | for i := 0; i < b.N; i++ { 416 | err := tmpl.Execute(&buf, nil, testComplexData) 417 | if err != nil { 418 | b.Fatal(err) 419 | } 420 | buf.Reset() 421 | } 422 | } 423 | 424 | /****************************************************************************** 425 | ** Goh 426 | ******************************************************************************/ 427 | func TestComplexGoh(t *testing.T) { 428 | var buf bytes.Buffer 429 | 430 | goh.Index(testComplexUser, testComplexNav, testComplexTitle, &buf) 431 | 432 | if msg, ok := linesEquals(buf.String(), expectedtComplexResult); !ok { 433 | t.Error(msg) 434 | } 435 | } 436 | 437 | func BenchmarkComplexGoh(b *testing.B) { 438 | var buf bytes.Buffer 439 | 440 | for i := 0; i < b.N; i++ { 441 | goh.Index(testComplexUser, testComplexNav, testComplexTitle, &buf) 442 | buf.Reset() 443 | } 444 | } 445 | 446 | /****************************************************************************** 447 | ** Hero 448 | ******************************************************************************/ 449 | func TestComplexHero(t *testing.T) { 450 | var buf bytes.Buffer 451 | 452 | herotmpl.Index(testComplexUser, testComplexNav, testComplexTitle, &buf) 453 | 454 | if msg, ok := linesEquals(buf.String(), expectedtComplexResult); !ok { 455 | t.Error(msg) 456 | } 457 | } 458 | 459 | func BenchmarkComplexHero(b *testing.B) { 460 | var buf bytes.Buffer 461 | 462 | for i := 0; i < b.N; i++ { 463 | herotmpl.Index(testComplexUser, testComplexNav, testComplexTitle, &buf) 464 | buf.Reset() 465 | } 466 | } 467 | 468 | /****************************************************************************** 469 | ** Jade 470 | ******************************************************************************/ 471 | func TestComplexJade(t *testing.T) { 472 | buf := bytebufferpool.Get() 473 | 474 | jade.Index(testComplexUser, testComplexNav, testComplexTitle, buf) 475 | 476 | if msg, ok := linesEquals(buf.String(), expectedtComplexResult); !ok { 477 | t.Error(msg) 478 | } 479 | } 480 | 481 | func BenchmarkComplexJade(b *testing.B) { 482 | buf := bytebufferpool.Get() 483 | 484 | for i := 0; i < b.N; i++ { 485 | jade.Index(testComplexUser, testComplexNav, testComplexTitle, buf) 486 | buf.Reset() 487 | } 488 | } 489 | 490 | /****************************************************************************** 491 | ** Go func 492 | ******************************************************************************/ 493 | func TestComplexGoFunc(t *testing.T) { 494 | bb := bytebufferpool.Get() 495 | 496 | golang.Index(bb, testComplexUser, testComplexNav, testComplexTitle) 497 | 498 | if msg, ok := linesEquals(bb.String(), expectedtComplexResult); !ok { 499 | t.Error(msg) 500 | } 501 | bb.Reset() 502 | 503 | golang.Index2(bb, testComplexUser, testComplexNav, testComplexTitle) 504 | 505 | if msg, ok := linesEquals(bb.String(), expectedtComplexResult); !ok { 506 | t.Error(msg) 507 | } 508 | bb.Reset() 509 | 510 | golang.Index3(bb, testComplexUser, testComplexNav, testComplexTitle) 511 | 512 | if msg, ok := linesEquals(bb.String(), expectedtComplexResult); !ok { 513 | t.Error(msg) 514 | } 515 | bytebufferpool.Put(bb) 516 | } 517 | 518 | func BenchmarkComplexGoDirectBuffer(b *testing.B) { 519 | bb := bytebufferpool.Get() 520 | 521 | for i := 0; i < b.N; i++ { 522 | golang.Index(bb, testComplexUser, testComplexNav, testComplexTitle) 523 | bb.Reset() 524 | } 525 | bytebufferpool.Put(bb) 526 | } 527 | 528 | func BenchmarkComplexGoHyperscript(b *testing.B) { 529 | bb := bytebufferpool.Get() 530 | 531 | for i := 0; i < b.N; i++ { 532 | golang.Index2(bb, testComplexUser, testComplexNav, testComplexTitle) 533 | bb.Reset() 534 | } 535 | bytebufferpool.Put(bb) 536 | } 537 | 538 | func BenchmarkComplexGoStaticString(b *testing.B) { 539 | bb := bytebufferpool.Get() 540 | 541 | for i := 0; i < b.N; i++ { 542 | golang.Index3(bb, testComplexUser, testComplexNav, testComplexTitle) 543 | bb.Reset() 544 | } 545 | bytebufferpool.Put(bb) 546 | } 547 | 548 | func BenchmarkComplexEscapeHTML(b *testing.B) { 549 | bb := bytebufferpool.Get() 550 | 551 | for i := 0; i < b.N; i++ { 552 | golang.EscapeHTML(testComplexData.User.EscapedContent, bb) 553 | bb.Reset() 554 | } 555 | bytebufferpool.Put(bb) 556 | } 557 | 558 | func BenchmarkComplexEscape(b *testing.B) { 559 | bb := bytebufferpool.Get() 560 | 561 | for i := 0; i < b.N; i++ { 562 | golang.Escape(bb, golang.UnsafeStrToBytes(testComplexData.User.EscapedContent)) 563 | bb.Reset() 564 | } 565 | bytebufferpool.Put(bb) 566 | } 567 | 568 | func BenchmarkComplexEscapeGo(b *testing.B) { 569 | bb := bytebufferpool.Get() 570 | 571 | for i := 0; i < b.N; i++ { 572 | bb.WriteString(html.EscapeString(testComplexData.User.EscapedContent)) 573 | bb.Reset() 574 | } 575 | bytebufferpool.Put(bb) 576 | } 577 | 578 | func BenchmarkComplexEscapeHTMLNoop(b *testing.B) { 579 | bb := bytebufferpool.Get() 580 | 581 | for i := 0; i < b.N; i++ { 582 | golang.EscapeHTML(testComplexData.User.FirstName, bb) 583 | bb.Reset() 584 | } 585 | bytebufferpool.Put(bb) 586 | } 587 | 588 | func BenchmarkComplexEscapeNoop(b *testing.B) { 589 | bb := bytebufferpool.Get() 590 | 591 | for i := 0; i < b.N; i++ { 592 | golang.Escape(bb, golang.UnsafeStrToBytes(testComplexData.User.FirstName)) 593 | bb.Reset() 594 | } 595 | bytebufferpool.Put(bb) 596 | } 597 | 598 | func BenchmarkComplexEscapeGoNoop(b *testing.B) { 599 | bb := bytebufferpool.Get() 600 | 601 | for i := 0; i < b.N; i++ { 602 | bb.WriteString(html.EscapeString(testComplexData.User.FirstName)) 603 | bb.Reset() 604 | } 605 | bytebufferpool.Put(bb) 606 | } 607 | -------------------------------------------------------------------------------- /templates_test.go: -------------------------------------------------------------------------------- 1 | package main_test 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "fmt" 7 | "html/template" 8 | "testing" 9 | text "text/template" 10 | 11 | goh "github.com/SlinSo/goTemplateBenchmark/goh" 12 | "github.com/SlinSo/goTemplateBenchmark/golang" 13 | "github.com/SlinSo/goTemplateBenchmark/gomponents" 14 | "github.com/SlinSo/goTemplateBenchmark/htmlbuilder" 15 | "github.com/SlinSo/goTemplateBenchmark/model" 16 | "github.com/SlinSo/goTemplateBenchmark/templbench" 17 | "github.com/valyala/bytebufferpool" 18 | 19 | "github.com/SlinSo/goTemplateBenchmark/ego" 20 | "github.com/SlinSo/goTemplateBenchmark/ftmpl" 21 | "github.com/SlinSo/goTemplateBenchmark/gorazor" 22 | herotmpl "github.com/SlinSo/goTemplateBenchmark/hero" 23 | "github.com/SlinSo/goTemplateBenchmark/jade" 24 | "github.com/SlinSo/goTemplateBenchmark/quicktemplate" 25 | "github.com/aymerick/raymond" 26 | "github.com/eknkc/amber" 27 | "github.com/flosch/pongo2" 28 | "github.com/hoisie/mustache" 29 | "github.com/robfig/soy" 30 | "github.com/robfig/soy/data" 31 | "github.com/yosssi/ace" 32 | 33 | "github.com/CloudyKit/jet" 34 | "github.com/dchest/htmlmin" 35 | ) 36 | 37 | var ( 38 | testData = &model.User{ 39 | FirstName: "Bob", 40 | FavoriteColors: []string{"blue", "green", "mauve"}, 41 | } 42 | 43 | expectedtResult = ` 44 | 45 |

    Bob

    46 | 47 |

    Here's a list of your favorite colors:

    48 | 54 | 55 | ` 56 | 57 | expectedtResultMinified = "

    Bob

    Here's a list of your favorite colors:

    " 58 | ) 59 | 60 | /****************************************************************************** 61 | ** Go 62 | ******************************************************************************/ 63 | func TestGolang(t *testing.T) { 64 | var buf bytes.Buffer 65 | 66 | tmpl, err := template.ParseFiles("go/simple.tmpl") 67 | if err != nil { 68 | t.Error(err) 69 | } 70 | err = tmpl.Execute(&buf, testData) 71 | if err != nil { 72 | t.Error(err) 73 | } 74 | 75 | if msg, ok := linesEquals(buf.String(), expectedtResult); !ok { 76 | t.Error(msg) 77 | } 78 | } 79 | 80 | func TestGolangText(t *testing.T) { 81 | var buf bytes.Buffer 82 | 83 | tmpl, err := text.ParseFiles("go/simple.tmpl") 84 | if err != nil { 85 | t.Error(err) 86 | } 87 | err = tmpl.Execute(&buf, testData) 88 | if err != nil { 89 | t.Error(err) 90 | } 91 | 92 | if msg, ok := linesEquals(buf.String(), expectedtResult); !ok { 93 | t.Error(msg) 94 | } 95 | } 96 | 97 | func BenchmarkGolang(b *testing.B) { 98 | var buf bytes.Buffer 99 | 100 | tmpl, _ := template.ParseFiles("go/simple.tmpl") 101 | b.ResetTimer() 102 | 103 | for i := 0; i < b.N; i++ { 104 | err := tmpl.Execute(&buf, testData) 105 | if err != nil { 106 | b.Fatal(err) 107 | } 108 | buf.Reset() 109 | } 110 | } 111 | 112 | func BenchmarkGolangText(b *testing.B) { 113 | var buf bytes.Buffer 114 | 115 | tmpl, _ := text.ParseFiles("go/simple.tmpl") 116 | b.ResetTimer() 117 | 118 | for i := 0; i < b.N; i++ { 119 | err := tmpl.Execute(&buf, testData) 120 | if err != nil { 121 | b.Fatal(err) 122 | } 123 | buf.Reset() 124 | } 125 | } 126 | 127 | /****************************************************************************** 128 | ** GoFunctions 129 | ******************************************************************************/ 130 | func TestGoFunc(t *testing.T) { 131 | bb := bytebufferpool.Get() 132 | golang.WriteSimpleGolang(bb, testData) 133 | 134 | if msg, ok := linesEquals(bb.String(), expectedtResult); !ok { 135 | t.Error(msg) 136 | } 137 | bb.Reset() 138 | g := golang.NewGoFunc(bb) 139 | 140 | golang.GoFuncElem(g, testData) 141 | if msg, ok := linesEquals(bb.String(), expectedtResult); !ok { 142 | t.Error(msg) 143 | } 144 | bb.Reset() 145 | g = golang.NewGoFunc(bb) 146 | 147 | golang.GoFuncFunc(g, testData) 148 | if msg, ok := linesEquals(bb.String(), expectedtResult); !ok { 149 | t.Error(msg) 150 | } 151 | 152 | bytebufferpool.Put(bb) 153 | } 154 | 155 | func BenchmarkGoDirectBuffer(b *testing.B) { 156 | bb := bytebufferpool.Get() 157 | 158 | for i := 0; i < b.N; i++ { 159 | golang.WriteSimpleGolang(bb, testData) 160 | bb.Reset() 161 | } 162 | } 163 | 164 | func BenchmarkGoCustomHtmlAPI(b *testing.B) { 165 | buf := bytebufferpool.Get() 166 | g := golang.NewGoFunc(buf) 167 | 168 | for i := 0; i < b.N; i++ { 169 | golang.GoFuncElem(g, testData) 170 | buf.Reset() 171 | } 172 | } 173 | 174 | func BenchmarkGoFunc3(b *testing.B) { 175 | buf := bytebufferpool.Get() 176 | g := golang.NewGoFunc(buf) 177 | 178 | for i := 0; i < b.N; i++ { 179 | golang.GoFuncFunc(g, testData) 180 | buf.Reset() 181 | } 182 | } 183 | 184 | /****************************************************************************** 185 | ** Ego 186 | ******************************************************************************/ 187 | func TestEgo(t *testing.T) { 188 | var buf bytes.Buffer 189 | ego.EgoSimple(&buf, testData) 190 | 191 | if msg, ok := linesEquals(buf.String(), expectedtResult); !ok { 192 | t.Error(msg) 193 | } 194 | } 195 | 196 | func BenchmarkEgo(b *testing.B) { 197 | var buf bytes.Buffer 198 | 199 | for i := 0; i < b.N; i++ { 200 | ego.EgoSimple(&buf, testData) 201 | buf.Reset() 202 | } 203 | } 204 | 205 | /****************************************************************************** 206 | ** HB (HTML Builder) 207 | ******************************************************************************/ 208 | func TestHB(t *testing.T) { 209 | var buf bytes.Buffer 210 | htmlbuilder.HbSimple(&buf, testData) 211 | 212 | if msg, ok := linesEquals(buf.String(), expectedtResult); !ok { 213 | t.Error(msg) 214 | } 215 | } 216 | 217 | func BenchmarkHB(b *testing.B) { 218 | var buf bytes.Buffer 219 | 220 | for i := 0; i < b.N; i++ { 221 | htmlbuilder.HbSimple(&buf, testData) 222 | buf.Reset() 223 | } 224 | } 225 | 226 | /****************************************************************************** 227 | ** Quicktemplate 228 | ******************************************************************************/ 229 | func TestQuicktemplate(t *testing.T) { 230 | var buf bytes.Buffer 231 | quicktemplate.WriteSimpleQtc(&buf, testData) 232 | 233 | if msg, ok := linesEquals(buf.String(), expectedtResult); !ok { 234 | t.Error(msg) 235 | } 236 | } 237 | 238 | func BenchmarkQuicktemplate(b *testing.B) { 239 | var buf bytes.Buffer 240 | 241 | for i := 0; i < b.N; i++ { 242 | quicktemplate.WriteSimpleQtc(&buf, testData) 243 | buf.Reset() 244 | } 245 | } 246 | 247 | /****************************************************************************** 248 | ** ftmpl 249 | ******************************************************************************/ 250 | func TestFtmpl(t *testing.T) { 251 | result, err := ftmpl.TMPLERRsimple(testData) 252 | if err != nil { 253 | t.Error(err) 254 | } 255 | 256 | if msg, ok := linesEquals(result, expectedtResult); !ok { 257 | t.Error(msg) 258 | } 259 | } 260 | 261 | func BenchmarkFtmpl(b *testing.B) { 262 | for i := 0; i < b.N; i++ { 263 | _, err := ftmpl.TMPLERRsimple(testData) 264 | if err != nil { 265 | b.Fatal(err) 266 | } 267 | 268 | } 269 | } 270 | 271 | /****************************************************************************** 272 | ** Ace 273 | ******************************************************************************/ 274 | func TestAce(t *testing.T) { 275 | var buf bytes.Buffer 276 | 277 | tpl, err := ace.Load("ace/simple", "", nil) 278 | if err != nil { 279 | t.Error(err) 280 | } 281 | 282 | if err := tpl.Execute(&buf, testData); err != nil { 283 | t.Error(err) 284 | } 285 | 286 | if msg, ok := linesEquals(buf.String(), expectedtResultMinified); !ok { 287 | t.Error(msg) 288 | } 289 | } 290 | 291 | func BenchmarkAce(b *testing.B) { 292 | var buf bytes.Buffer 293 | 294 | tpl, err := ace.Load("ace/simple", "", nil) 295 | if err != nil { 296 | b.Fatal(err) 297 | } 298 | b.ResetTimer() 299 | 300 | for i := 0; i < b.N; i++ { 301 | err := tpl.Execute(&buf, testData) 302 | if err != nil { 303 | b.Fatal(err) 304 | } 305 | buf.Reset() 306 | } 307 | } 308 | 309 | /****************************************************************************** 310 | ** Amber 311 | ******************************************************************************/ 312 | func TestAmber(t *testing.T) { 313 | var buf bytes.Buffer 314 | 315 | tpl, err := amber.CompileFile("amber/simple.amber", amber.DefaultOptions) 316 | if err != nil { 317 | t.Error(err) 318 | } 319 | 320 | if err := tpl.Execute(&buf, testData); err != nil { 321 | t.Error(err) 322 | } 323 | 324 | if msg, ok := linesEquals(buf.String(), expectedtResult); !ok { 325 | t.Error(msg) 326 | } 327 | } 328 | 329 | func BenchmarkAmber(b *testing.B) { 330 | var buf bytes.Buffer 331 | 332 | tpl, _ := amber.CompileFile("amber/simple.amber", amber.DefaultOptions) 333 | b.ResetTimer() 334 | 335 | for i := 0; i < b.N; i++ { 336 | err := tpl.Execute(&buf, testData) 337 | if err != nil { 338 | b.Fatal(err) 339 | } 340 | buf.Reset() 341 | } 342 | } 343 | 344 | /****************************************************************************** 345 | ** Mustache 346 | ******************************************************************************/ 347 | func TestMustache(t *testing.T) { 348 | tpl, err := mustache.ParseFile("mustache/simple.mustache") 349 | if err != nil { 350 | t.Error(err) 351 | } 352 | 353 | result := tpl.Render(testData) 354 | 355 | if msg, ok := linesEquals(result, expectedtResult); !ok { 356 | t.Error(msg) 357 | } 358 | } 359 | 360 | func BenchmarkMustache(b *testing.B) { 361 | tpl, _ := mustache.ParseFile("mustache/simple.mustache") 362 | b.ResetTimer() 363 | 364 | for i := 0; i < b.N; i++ { 365 | tpl.Render(testData) 366 | } 367 | } 368 | 369 | /****************************************************************************** 370 | ** pongo2 371 | ******************************************************************************/ 372 | func TestPongo2(t *testing.T) { 373 | var buf bytes.Buffer 374 | 375 | tpl, err := pongo2.FromFile("pongo2/simple.pongo") 376 | if err != nil { 377 | t.Error(err) 378 | } 379 | 380 | err = tpl.ExecuteWriter(pongo2.Context{"u": testData}, &buf) 381 | if err != nil { 382 | t.Error(err) 383 | } 384 | 385 | if msg, ok := linesEquals(buf.String(), expectedtResult); !ok { 386 | t.Error(msg) 387 | } 388 | } 389 | 390 | func BenchmarkPongo2(b *testing.B) { 391 | var buf bytes.Buffer 392 | 393 | tpl, _ := pongo2.FromFile("pongo2/simple.pongo") 394 | b.ResetTimer() 395 | 396 | for i := 0; i < b.N; i++ { 397 | err := tpl.ExecuteWriter(pongo2.Context{"u": testData}, &buf) 398 | if err != nil { 399 | b.Fatal(err) 400 | } 401 | buf.Reset() 402 | } 403 | } 404 | 405 | /****************************************************************************** 406 | ** Handlebars 407 | ******************************************************************************/ 408 | func TestHandlebars(t *testing.T) { 409 | tpl, err := raymond.ParseFile("raymond/simple.handle") 410 | if err != nil { 411 | t.Error(err) 412 | } 413 | 414 | result, err := tpl.Exec(testData) 415 | if err != nil { 416 | t.Error(err) 417 | } 418 | 419 | if msg, ok := linesEquals(result, expectedtResult); !ok { 420 | t.Error(msg) 421 | } 422 | } 423 | 424 | func BenchmarkHandlebars(b *testing.B) { 425 | tpl, _ := raymond.ParseFile("raymond/simple.handle") 426 | b.ResetTimer() 427 | 428 | for i := 0; i < b.N; i++ { 429 | _, err := tpl.Exec(testData) 430 | if err != nil { 431 | b.Fatal(err) 432 | } 433 | } 434 | } 435 | 436 | /****************************************************************************** 437 | ** gorazor 438 | ******************************************************************************/ 439 | func TestGorazor(t *testing.T) { 440 | result := gorazor.Simple(testData) 441 | 442 | if msg, ok := linesEquals(result, expectedtResult); !ok { 443 | t.Error(msg) 444 | } 445 | } 446 | 447 | func BenchmarkGorazor(b *testing.B) { 448 | for i := 0; i < b.N; i++ { 449 | gorazor.Simple(testData) 450 | } 451 | } 452 | 453 | /****************************************************************************** 454 | ** Soy 455 | ******************************************************************************/ 456 | func TestSoy(t *testing.T) { 457 | var buf bytes.Buffer 458 | 459 | tofu, err := soy.NewBundle().AddTemplateDir("soy").CompileToTofu() 460 | if err != nil { 461 | t.Error(err) 462 | } 463 | 464 | err = tofu.Render(&buf, "soy.simple", map[string]interface{}{ 465 | "user": data.New(testData), 466 | }) 467 | if err != nil { 468 | t.Error(err) 469 | } 470 | 471 | if msg, ok := linesEquals(buf.String(), expectedtResult); !ok { 472 | t.Error(msg) 473 | } 474 | } 475 | 476 | func BenchmarkSoy(b *testing.B) { 477 | var buf bytes.Buffer 478 | 479 | tofu, _ := soy.NewBundle().AddTemplateDir("soy").CompileToTofu() 480 | soyData := map[string]interface{}{ 481 | "user": data.New(testData), 482 | } 483 | b.ResetTimer() 484 | 485 | for i := 0; i < b.N; i++ { 486 | err := tofu.Render(&buf, "soy.simple", soyData) 487 | if err != nil { 488 | b.Fatal(err) 489 | } 490 | buf.Reset() 491 | } 492 | } 493 | 494 | /****************************************************************************** 495 | ** Jet 496 | ******************************************************************************/ 497 | var jetSet = jet.NewHTMLSet("./jet") 498 | 499 | func TestJetHTML(t *testing.T) { 500 | var buf bytes.Buffer 501 | 502 | tmpl, err := jetSet.GetTemplate("simple.jet") 503 | if err != nil { 504 | t.Error(err) 505 | } 506 | err = tmpl.Execute(&buf, nil, testData) 507 | if err != nil { 508 | t.Error(err) 509 | } 510 | 511 | if msg, ok := linesEquals(buf.String(), expectedtResult); !ok { 512 | t.Error(msg) 513 | } 514 | } 515 | 516 | func BenchmarkJetHTML(b *testing.B) { 517 | var buf bytes.Buffer 518 | 519 | tmpl, _ := jetSet.GetTemplate("simple.jet") 520 | b.ResetTimer() 521 | 522 | for i := 0; i < b.N; i++ { 523 | err := tmpl.Execute(&buf, nil, testData) 524 | if err != nil { 525 | b.Fatal(err) 526 | } 527 | buf.Reset() 528 | } 529 | } 530 | 531 | /****************************************************************************** 532 | ** Goh 533 | ******************************************************************************/ 534 | func TestGoh(t *testing.T) { 535 | var buf bytes.Buffer 536 | goh.SimpleQtc(testData, &buf) 537 | 538 | if msg, ok := linesEquals(buf.String(), expectedtResult); !ok { 539 | t.Error(msg) 540 | } 541 | } 542 | 543 | func BenchmarkGoh(b *testing.B) { 544 | var buf bytes.Buffer 545 | 546 | for i := 0; i < b.N; i++ { 547 | goh.SimpleQtc(testData, &buf) 548 | buf.Reset() 549 | } 550 | } 551 | 552 | /****************************************************************************** 553 | ** Hero 554 | ******************************************************************************/ 555 | func TestHero(t *testing.T) { 556 | var buf bytes.Buffer 557 | 558 | herotmpl.SimpleQtc(testData, &buf) 559 | 560 | if msg, ok := linesEquals(buf.String(), expectedtResult); !ok { 561 | t.Error(msg) 562 | } 563 | } 564 | 565 | func BenchmarkHero(b *testing.B) { 566 | var buf bytes.Buffer 567 | 568 | for i := 0; i < b.N; i++ { 569 | herotmpl.SimpleQtc(testData, &buf) 570 | buf.Reset() 571 | } 572 | } 573 | 574 | /****************************************************************************** 575 | ** Jade 576 | ******************************************************************************/ 577 | func TestJade(t *testing.T) { 578 | buf := bytebufferpool.Get() 579 | 580 | jade.Simple(testData, buf) 581 | 582 | if msg, ok := linesEquals(buf.String(), expectedtResult); !ok { 583 | t.Error(msg) 584 | } 585 | } 586 | 587 | func BenchmarkJade(b *testing.B) { 588 | buf := bytebufferpool.Get() 589 | 590 | for i := 0; i < b.N; i++ { 591 | jade.Simple(testData, buf) 592 | buf.Reset() 593 | } 594 | } 595 | 596 | /****************************************************************************** 597 | ** templ 598 | ******************************************************************************/ 599 | func TestTempl(t *testing.T) { 600 | var buf bytes.Buffer 601 | templbench.SimpleTempl(testData).Render(context.Background(), &buf) 602 | 603 | if msg, ok := linesEquals(buf.String(), expectedtResult); !ok { 604 | t.Error(msg) 605 | } 606 | } 607 | 608 | func BenchmarkTempl(b *testing.B) { 609 | var buf bytes.Buffer 610 | 611 | ctx := context.Background() 612 | for i := 0; i < b.N; i++ { 613 | templbench.SimpleTempl(testData).Render(ctx, &buf) 614 | buf.Reset() 615 | } 616 | } 617 | 618 | /****************************************************************************** 619 | ** Gomponents 620 | ******************************************************************************/ 621 | func TestGomponents(t *testing.T) { 622 | buf := bytebufferpool.Get() 623 | 624 | err := gomponents.Page(testData).Render(buf) 625 | if err != nil { 626 | t.Error(err) 627 | } 628 | 629 | if msg, ok := linesEquals(buf.String(), expectedtResult); !ok { 630 | t.Error(msg) 631 | } 632 | } 633 | 634 | func BenchmarkGomponents(b *testing.B) { 635 | buf := bytebufferpool.Get() 636 | 637 | for i := 0; i < b.N; i++ { 638 | gomponents.Page(testData).Render(buf) 639 | buf.Reset() 640 | } 641 | } 642 | 643 | /****************************************************************************** 644 | ** helpers 645 | ******************************************************************************/ 646 | func linesEquals(str1, str2 string) (explanation string, equals bool) { 647 | if str1 == str2 { 648 | return "", true 649 | } 650 | 651 | // Minify removes whitespace infront of the first tag 652 | b1, err := htmlmin.Minify([]byte(str1), nil) 653 | if err != nil { 654 | panic(err) 655 | } 656 | 657 | b2, err := htmlmin.Minify([]byte(str2), nil) 658 | if err != nil { 659 | panic(err) 660 | } 661 | 662 | b1 = bytes.Replace(b1, []byte(" "), []byte("[space]"), -1) 663 | b1 = bytes.Replace(b1, []byte("\t"), []byte("[tab]"), -1) 664 | b1 = bytes.Replace(b1, []byte("\n"), []byte(""), -1) 665 | 666 | b2 = bytes.Replace(b2, []byte(" "), []byte("[space]"), -1) 667 | b2 = bytes.Replace(b2, []byte("\t"), []byte("[tab]"), -1) 668 | b2 = bytes.Replace(b2, []byte("\n"), []byte(""), -1) 669 | 670 | if !bytes.Equal(b1, b2) { 671 | return fmt.Sprintf("Lines don't match \n1:\"%s\"\n2:\"%s\"", b1, b2), false 672 | } 673 | 674 | return "", true 675 | } 676 | -------------------------------------------------------------------------------- /templbench/footer.templ: -------------------------------------------------------------------------------- 1 | package templbench 2 | 3 | templ Footer() { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /templbench/footer_templ.go: -------------------------------------------------------------------------------- 1 | // Code generated by templ - DO NOT EDIT. 2 | 3 | // templ: version: v0.2.778 4 | package templbench 5 | 6 | //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 | 8 | import "github.com/a-h/templ" 9 | import templruntime "github.com/a-h/templ/runtime" 10 | 11 | func Footer() templ.Component { 12 | return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 13 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 14 | if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 15 | return templ_7745c5c3_CtxErr 16 | } 17 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 18 | if !templ_7745c5c3_IsBuffer { 19 | defer func() { 20 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 21 | if templ_7745c5c3_Err == nil { 22 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 23 | } 24 | }() 25 | } 26 | ctx = templ.InitializeContext(ctx) 27 | templ_7745c5c3_Var1 := templ.GetChildren(ctx) 28 | if templ_7745c5c3_Var1 == nil { 29 | templ_7745c5c3_Var1 = templ.NopComponent 30 | } 31 | ctx = templ.ClearChildren(ctx) 32 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
    copyright 2016
    ") 33 | if templ_7745c5c3_Err != nil { 34 | return templ_7745c5c3_Err 35 | } 36 | return templ_7745c5c3_Err 37 | }) 38 | } 39 | 40 | var _ = templruntime.GeneratedTemplate 41 | -------------------------------------------------------------------------------- /templbench/header.templ: -------------------------------------------------------------------------------- 1 | package templbench 2 | 3 | templ Header(title string) { 4 | { title }'s Home Page 5 |
    Page Header
    6 | } 7 | -------------------------------------------------------------------------------- /templbench/header_templ.go: -------------------------------------------------------------------------------- 1 | // Code generated by templ - DO NOT EDIT. 2 | 3 | // templ: version: v0.2.778 4 | package templbench 5 | 6 | //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 | 8 | import "github.com/a-h/templ" 9 | import templruntime "github.com/a-h/templ/runtime" 10 | 11 | func Header(title string) templ.Component { 12 | return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 13 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 14 | if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 15 | return templ_7745c5c3_CtxErr 16 | } 17 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 18 | if !templ_7745c5c3_IsBuffer { 19 | defer func() { 20 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 21 | if templ_7745c5c3_Err == nil { 22 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 23 | } 24 | }() 25 | } 26 | ctx = templ.InitializeContext(ctx) 27 | templ_7745c5c3_Var1 := templ.GetChildren(ctx) 28 | if templ_7745c5c3_Var1 == nil { 29 | templ_7745c5c3_Var1 = templ.NopComponent 30 | } 31 | ctx = templ.ClearChildren(ctx) 32 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") 33 | if templ_7745c5c3_Err != nil { 34 | return templ_7745c5c3_Err 35 | } 36 | var templ_7745c5c3_Var2 string 37 | templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(title) 38 | if templ_7745c5c3_Err != nil { 39 | return templ.Error{Err: templ_7745c5c3_Err, FileName: `templbench/header.templ`, Line: 4, Col: 15} 40 | } 41 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) 42 | if templ_7745c5c3_Err != nil { 43 | return templ_7745c5c3_Err 44 | } 45 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("'s Home Page
    Page Header
    ") 46 | if templ_7745c5c3_Err != nil { 47 | return templ_7745c5c3_Err 48 | } 49 | return templ_7745c5c3_Err 50 | }) 51 | } 52 | 53 | var _ = templruntime.GeneratedTemplate 54 | -------------------------------------------------------------------------------- /templbench/index.templ: -------------------------------------------------------------------------------- 1 | package templbench 2 | 3 | import ( 4 | "context" 5 | "github.com/SlinSo/goTemplateBenchmark/model" 6 | "io" 7 | "strconv" 8 | ) 9 | 10 | func Raw(s string) templ.Component { 11 | return templ.ComponentFunc(func(ctx context.Context, w io.Writer) (err error) { 12 | _, err = io.WriteString(w, s) 13 | return 14 | }) 15 | } 16 | 17 | templ Index(u *model.User, nav []*model.Navigation, title string) { 18 | @Raw("") 19 | 20 | 21 |
    22 | @Header(title) 23 |
    24 | 27 |
    28 |
    29 |
    30 |

    Hello { u.FirstName }

    31 |
    32 | @Raw(u.RawContent) 33 |
    34 |
    { u.EscapedContent }
    35 |
    36 | for i := 1; i <= 5; i++ { 37 | if i == 1 { 38 |

    { u.FirstName } has { strconv.FormatInt(int64(i), 10) } message

    39 | } else { 40 |

    { u.FirstName } has { strconv.FormatInt(int64(i), 10) } messages

    41 | } 42 | } 43 |
    44 |
    45 |
    46 | @Footer() 47 |
    48 | 49 | 50 | } 51 | -------------------------------------------------------------------------------- /templbench/index_templ.go: -------------------------------------------------------------------------------- 1 | // Code generated by templ - DO NOT EDIT. 2 | 3 | // templ: version: v0.2.778 4 | package templbench 5 | 6 | //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 | 8 | import "github.com/a-h/templ" 9 | import templruntime "github.com/a-h/templ/runtime" 10 | 11 | import ( 12 | "context" 13 | "github.com/SlinSo/goTemplateBenchmark/model" 14 | "io" 15 | "strconv" 16 | ) 17 | 18 | func Raw(s string) templ.Component { 19 | return templ.ComponentFunc(func(ctx context.Context, w io.Writer) (err error) { 20 | _, err = io.WriteString(w, s) 21 | return 22 | }) 23 | } 24 | 25 | func Index(u *model.User, nav []*model.Navigation, title string) templ.Component { 26 | return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 27 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 28 | if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 29 | return templ_7745c5c3_CtxErr 30 | } 31 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 32 | if !templ_7745c5c3_IsBuffer { 33 | defer func() { 34 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 35 | if templ_7745c5c3_Err == nil { 36 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 37 | } 38 | }() 39 | } 40 | ctx = templ.InitializeContext(ctx) 41 | templ_7745c5c3_Var1 := templ.GetChildren(ctx) 42 | if templ_7745c5c3_Var1 == nil { 43 | templ_7745c5c3_Var1 = templ.NopComponent 44 | } 45 | ctx = templ.ClearChildren(ctx) 46 | templ_7745c5c3_Err = Raw("").Render(ctx, templ_7745c5c3_Buffer) 47 | if templ_7745c5c3_Err != nil { 48 | return templ_7745c5c3_Err 49 | } 50 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
    ") 51 | if templ_7745c5c3_Err != nil { 52 | return templ_7745c5c3_Err 53 | } 54 | templ_7745c5c3_Err = Header(title).Render(ctx, templ_7745c5c3_Buffer) 55 | if templ_7745c5c3_Err != nil { 56 | return templ_7745c5c3_Err 57 | } 58 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

    Hello ") 67 | if templ_7745c5c3_Err != nil { 68 | return templ_7745c5c3_Err 69 | } 70 | var templ_7745c5c3_Var2 string 71 | templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(u.FirstName) 72 | if templ_7745c5c3_Err != nil { 73 | return templ.Error{Err: templ_7745c5c3_Err, FileName: `templbench/index.templ`, Line: 30, Col: 29} 74 | } 75 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) 76 | if templ_7745c5c3_Err != nil { 77 | return templ_7745c5c3_Err 78 | } 79 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

    ") 80 | if templ_7745c5c3_Err != nil { 81 | return templ_7745c5c3_Err 82 | } 83 | templ_7745c5c3_Err = Raw(u.RawContent).Render(ctx, templ_7745c5c3_Buffer) 84 | if templ_7745c5c3_Err != nil { 85 | return templ_7745c5c3_Err 86 | } 87 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
    ") 88 | if templ_7745c5c3_Err != nil { 89 | return templ_7745c5c3_Err 90 | } 91 | var templ_7745c5c3_Var3 string 92 | templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(u.EscapedContent) 93 | if templ_7745c5c3_Err != nil { 94 | return templ.Error{Err: templ_7745c5c3_Err, FileName: `templbench/index.templ`, Line: 34, Col: 41} 95 | } 96 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) 97 | if templ_7745c5c3_Err != nil { 98 | return templ_7745c5c3_Err 99 | } 100 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
    ") 101 | if templ_7745c5c3_Err != nil { 102 | return templ_7745c5c3_Err 103 | } 104 | for i := 1; i <= 5; i++ { 105 | if i == 1 { 106 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

    ") 107 | if templ_7745c5c3_Err != nil { 108 | return templ_7745c5c3_Err 109 | } 110 | var templ_7745c5c3_Var4 string 111 | templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(u.FirstName) 112 | if templ_7745c5c3_Err != nil { 113 | return templ.Error{Err: templ_7745c5c3_Err, FileName: `templbench/index.templ`, Line: 38, Col: 23} 114 | } 115 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) 116 | if templ_7745c5c3_Err != nil { 117 | return templ_7745c5c3_Err 118 | } 119 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" has ") 120 | if templ_7745c5c3_Err != nil { 121 | return templ_7745c5c3_Err 122 | } 123 | var templ_7745c5c3_Var5 string 124 | templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(strconv.FormatInt(int64(i), 10)) 125 | if templ_7745c5c3_Err != nil { 126 | return templ.Error{Err: templ_7745c5c3_Err, FileName: `templbench/index.templ`, Line: 38, Col: 63} 127 | } 128 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) 129 | if templ_7745c5c3_Err != nil { 130 | return templ_7745c5c3_Err 131 | } 132 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" message

    ") 133 | if templ_7745c5c3_Err != nil { 134 | return templ_7745c5c3_Err 135 | } 136 | } else { 137 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

    ") 138 | if templ_7745c5c3_Err != nil { 139 | return templ_7745c5c3_Err 140 | } 141 | var templ_7745c5c3_Var6 string 142 | templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(u.FirstName) 143 | if templ_7745c5c3_Err != nil { 144 | return templ.Error{Err: templ_7745c5c3_Err, FileName: `templbench/index.templ`, Line: 40, Col: 23} 145 | } 146 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) 147 | if templ_7745c5c3_Err != nil { 148 | return templ_7745c5c3_Err 149 | } 150 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" has ") 151 | if templ_7745c5c3_Err != nil { 152 | return templ_7745c5c3_Err 153 | } 154 | var templ_7745c5c3_Var7 string 155 | templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(strconv.FormatInt(int64(i), 10)) 156 | if templ_7745c5c3_Err != nil { 157 | return templ.Error{Err: templ_7745c5c3_Err, FileName: `templbench/index.templ`, Line: 40, Col: 63} 158 | } 159 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) 160 | if templ_7745c5c3_Err != nil { 161 | return templ_7745c5c3_Err 162 | } 163 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" messages

    ") 164 | if templ_7745c5c3_Err != nil { 165 | return templ_7745c5c3_Err 166 | } 167 | } 168 | } 169 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
    ") 170 | if templ_7745c5c3_Err != nil { 171 | return templ_7745c5c3_Err 172 | } 173 | templ_7745c5c3_Err = Footer().Render(ctx, templ_7745c5c3_Buffer) 174 | if templ_7745c5c3_Err != nil { 175 | return templ_7745c5c3_Err 176 | } 177 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
    ") 178 | if templ_7745c5c3_Err != nil { 179 | return templ_7745c5c3_Err 180 | } 181 | return templ_7745c5c3_Err 182 | }) 183 | } 184 | 185 | var _ = templruntime.GeneratedTemplate 186 | -------------------------------------------------------------------------------- /templbench/navigation.templ: -------------------------------------------------------------------------------- 1 | package templbench 2 | 3 | import "github.com/SlinSo/goTemplateBenchmark/model" 4 | 5 | templ Navigation(nav []*model.Navigation) { 6 | 11 | } 12 | -------------------------------------------------------------------------------- /templbench/navigation_templ.go: -------------------------------------------------------------------------------- 1 | // Code generated by templ - DO NOT EDIT. 2 | 3 | // templ: version: v0.2.778 4 | package templbench 5 | 6 | //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 | 8 | import "github.com/a-h/templ" 9 | import templruntime "github.com/a-h/templ/runtime" 10 | 11 | import "github.com/SlinSo/goTemplateBenchmark/model" 12 | 13 | func Navigation(nav []*model.Navigation) templ.Component { 14 | return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 15 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 16 | if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 17 | return templ_7745c5c3_CtxErr 18 | } 19 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 20 | if !templ_7745c5c3_IsBuffer { 21 | defer func() { 22 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 23 | if templ_7745c5c3_Err == nil { 24 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 25 | } 26 | }() 27 | } 28 | ctx = templ.InitializeContext(ctx) 29 | templ_7745c5c3_Var1 := templ.GetChildren(ctx) 30 | if templ_7745c5c3_Var1 == nil { 31 | templ_7745c5c3_Var1 = templ.NopComponent 32 | } 33 | ctx = templ.ClearChildren(ctx) 34 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") 67 | if templ_7745c5c3_Err != nil { 68 | return templ_7745c5c3_Err 69 | } 70 | return templ_7745c5c3_Err 71 | }) 72 | } 73 | 74 | var _ = templruntime.GeneratedTemplate 75 | -------------------------------------------------------------------------------- /templbench/simple.templ: -------------------------------------------------------------------------------- 1 | package templbench 2 | 3 | import "github.com/SlinSo/goTemplateBenchmark/model" 4 | 5 | templ SimpleTempl(u *model.User) { 6 | 7 | 8 |

    { u.FirstName }

    9 |

    Here's a list of your favorite colors:

    10 | 15 | 16 | 17 | } 18 | -------------------------------------------------------------------------------- /templbench/simple_templ.go: -------------------------------------------------------------------------------- 1 | // Code generated by templ - DO NOT EDIT. 2 | 3 | // templ: version: v0.2.778 4 | package templbench 5 | 6 | //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 | 8 | import "github.com/a-h/templ" 9 | import templruntime "github.com/a-h/templ/runtime" 10 | 11 | import "github.com/SlinSo/goTemplateBenchmark/model" 12 | 13 | func SimpleTempl(u *model.User) templ.Component { 14 | return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 15 | templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 16 | if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 17 | return templ_7745c5c3_CtxErr 18 | } 19 | templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 20 | if !templ_7745c5c3_IsBuffer { 21 | defer func() { 22 | templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 23 | if templ_7745c5c3_Err == nil { 24 | templ_7745c5c3_Err = templ_7745c5c3_BufErr 25 | } 26 | }() 27 | } 28 | ctx = templ.InitializeContext(ctx) 29 | templ_7745c5c3_Var1 := templ.GetChildren(ctx) 30 | if templ_7745c5c3_Var1 == nil { 31 | templ_7745c5c3_Var1 = templ.NopComponent 32 | } 33 | ctx = templ.ClearChildren(ctx) 34 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

    ") 35 | if templ_7745c5c3_Err != nil { 36 | return templ_7745c5c3_Err 37 | } 38 | var templ_7745c5c3_Var2 string 39 | templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(u.FirstName) 40 | if templ_7745c5c3_Err != nil { 41 | return templ.Error{Err: templ_7745c5c3_Err, FileName: `templbench/simple.templ`, Line: 8, Col: 20} 42 | } 43 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) 44 | if templ_7745c5c3_Err != nil { 45 | return templ_7745c5c3_Err 46 | } 47 | _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

    Here's a list of your favorite colors:

    ") 71 | if templ_7745c5c3_Err != nil { 72 | return templ_7745c5c3_Err 73 | } 74 | return templ_7745c5c3_Err 75 | }) 76 | } 77 | 78 | var _ = templruntime.GeneratedTemplate 79 | --------------------------------------------------------------------------------