Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

proposal: would templ generate be faster if it skipped generating files that haven't changed? #80

Closed
a-h opened this issue Apr 30, 2023 · 2 comments

Comments

@a-h
Copy link
Owner

a-h commented Apr 30, 2023

templ generate is pretty fast. It can generate code for 32 templates in 500ms or so.

Would it be even faster if it only parsed and generated files that have changed instead of doing them all? Or would the effort of maintaining the hash or last updated date of each templ file actually reduce the performance overall?

benchmarks/templ/template.templ complete in 1.027709ms
cmd/templ/lspcmd/httpdebug/list.templ complete in 1.050959ms
cmd/templ/visualize/sourcemapvisualisation.templ complete in 1.000875ms
examples/blog/posts.templ complete in 1.015458ms
examples/hello-world-ssr/hello.templ complete in 253.209µs
# snip...
generator/test-text/template.templ complete in 426.833µs
generator/test-templ-element/template.templ complete in 493.25µs
generator/test-void/template.templ complete in 249.834µs
generator/test-text-whitespace/template.templ complete in 996.5µs
storybook/_example/templates.templ complete in 410.458µs
turbo/stream.templ complete in 399.75µs
Generated code for 32 templates with 0 errors in 470.553625ms
@a-h
Copy link
Owner Author

a-h commented Sep 24, 2023

Did a quick test.

package main

import (
	"crypto/sha256"
	"fmt"
	"io"
	"log"
	"os"
	"time"

	"github.com/a-h/templ/generator"
	"github.com/a-h/templ/parser/v2"
)

func main() {
	var err error
	var now time.Time

	now = time.Now()
	err = hashPath()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("hashPath: ms: %d\n", time.Since(now).Milliseconds())

	now = time.Now()
	err = generatePath()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("generatePath: ms: %d\n", time.Since(now).Milliseconds())
}

func hashPath() (err error) {
	f, err := os.Open("template.templ")
	if err != nil {
		return
	}
	defer f.Close()
	h := sha256.New()
	if _, err = io.Copy(h, f); err != nil {
		return err
	}
	fmt.Printf("%x\n", h.Sum(nil))
	return err
}

func generatePath() (err error) {
	t, err := parser.Parse("template.templ")
	if err != nil {
		return
	}
	outputFileName := "template_temp.go"
	outputFile, err := os.Create(outputFileName)
	if err != nil {
		return
	}
	_, err = generator.Generate(t, outputFile)
	return err
}
0 0 /Users/adrian/github.com/a-h/templ/generator/test-complex-attributes % ./hash
0f3bd5fb1a37ce30dce13849dfb40009dda13e742bb10cb394012b73adb4fe9f
hashPath: ms: 0
generatePath: ms: 5

Although there would be a small overhead in maintaining the hash list, it's likely faster overall to skip generating files that haven't changed by recalculating the hash.

But only by around 5ms per file.

@a-h
Copy link
Owner Author

a-h commented Jan 7, 2024

Fixed in #366

@a-h a-h closed this as completed Jan 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant