diff --git a/Makefile b/Makefile
index d1bfb2645f..ebd108d99c 100644
--- a/Makefile
+++ b/Makefile
@@ -111,6 +111,8 @@ WEBPACK_DEST_ENTRIES := public/js public/css public/fonts public/img/webpack pub
 BINDATA_DEST := modules/public/bindata.go modules/options/bindata.go modules/templates/bindata.go
 BINDATA_HASH := $(addsuffix .hash,$(BINDATA_DEST))
 
+GENERATED_GO_DEST := modules/charset/invisible_gen.go modules/charset/ambiguous_gen.go
+
 SVG_DEST_DIR := public/img/svg
 
 AIR_TMP_DIR := .air
@@ -130,9 +132,12 @@ GO_DIRS := cmd tests models modules routers build services tools
 
 GO_SOURCES := $(wildcard *.go)
 GO_SOURCES += $(shell find $(GO_DIRS) -type f -name "*.go" -not -path modules/options/bindata.go -not -path modules/public/bindata.go -not -path modules/templates/bindata.go)
+GO_SOURCES += $(GENERATED_GO_DEST)
+GO_SOURCES_NO_BINDATA := $(GO_SOURCES)
 
 ifeq ($(filter $(TAGS_SPLIT),bindata),bindata)
 	GO_SOURCES += $(BINDATA_DEST)
+	GENERATED_GO_DEST += $(BINDATA_DEST)
 endif
 
 # Force installation of playwright dependencies by setting this flag
@@ -259,7 +264,7 @@ clean:
 fmt:
 	@MISSPELL_PACKAGE=$(MISSPELL_PACKAGE) GOFUMPT_PACKAGE=$(GOFUMPT_PACKAGE) $(GO) run build/code-batch-process.go gitea-fmt -w '{file-list}'
 	$(eval TEMPLATES := $(shell find templates -type f -name '*.tmpl'))
-	@# strip whitespace after '{{' and before `}}` unless there is only whitespace before it 
+	@# strip whitespace after '{{' and before `}}` unless there is only whitespace before it
 	@$(SED_INPLACE) -e 's/{{[ 	]\{1,\}/{{/g' -e '/^[ 	]\{1,\}}}/! s/[ 	]\{1,\}}}/}}/g' $(TEMPLATES)
 
 .PHONY: vet
@@ -278,7 +283,9 @@ TAGS_PREREQ := $(TAGS_EVIDENCE)
 endif
 
 .PHONY: generate-swagger
-generate-swagger:
+generate-swagger: $(SWAGGER_SPEC)
+
+$(SWAGGER_SPEC): $(GO_SOURCES_NO_BINDATA)
 	$(GO) run $(SWAGGER_PACKAGE) generate spec -x "$(SWAGGER_EXCLUDE)" -o './$(SWAGGER_SPEC)'
 	$(SED_INPLACE) '$(SWAGGER_SPEC_S_TMPL)' './$(SWAGGER_SPEC)'
 	$(SED_INPLACE) $(SWAGGER_NEWLINE_COMMAND) './$(SWAGGER_SPEC)'
@@ -398,7 +405,6 @@ unit-test-coverage:
 tidy:
 	$(eval MIN_GO_VERSION := $(shell grep -Eo '^go\s+[0-9]+\.[0-9.]+' go.mod | cut -d' ' -f2))
 	$(GO) mod tidy -compat=$(MIN_GO_VERSION)
-	@$(MAKE) --no-print-directory assets/go-licenses.json
 
 .PHONY: vendor
 vendor: tidy
@@ -702,16 +708,25 @@ install: $(wildcard *.go)
 build: frontend backend
 
 .PHONY: frontend
-frontend: $(WEBPACK_DEST)
+frontend: generate-frontend $(WEBPACK_DEST)
 
 .PHONY: backend
-backend: go-check generate $(EXECUTABLE)
+backend: go-check generate-backend $(EXECUTABLE)
 
+# We generate the backend before the frontend in case we in future we want to generate things in the frontend from generated files in backend
 .PHONY: generate
-generate: $(TAGS_PREREQ)
+generate: generate-backend generate-frontend
+
+.PHONY: generate-backend
+generate-backend: $(TAGS_PREREQ) generate-go
+
+generate-go: $(TAGS_PREREQ)
 	@echo "Running go generate..."
 	@CC= GOOS= GOARCH= $(GO) generate -tags '$(TAGS)' $(GO_PACKAGES)
 
+.PHONY: generate-frontend
+generate-frontend: $(TAGS_PREREQ) go-licenses
+
 $(EXECUTABLE): $(GO_SOURCES) $(TAGS_PREREQ)
 	CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) build $(GOFLAGS) $(EXTRA_GOFLAGS) -tags '$(TAGS)' -ldflags '-s -w $(LDFLAGS)' -o $@
 
diff --git a/modules/charset/ambiguous/generate.go b/modules/charset/ambiguous/generate.go
index 43cdb217a7..7dd2821aae 100644
--- a/modules/charset/ambiguous/generate.go
+++ b/modules/charset/ambiguous/generate.go
@@ -110,6 +110,17 @@ func runTemplate(t *template.Template, filename string, data interface{}) error
 		verbosef("Bad source:\n%s", buf.String())
 		return fmt.Errorf("unable to format source: %w", err)
 	}
+
+	old, err := os.ReadFile(filename)
+	if err != nil && !os.IsNotExist(err) {
+		return fmt.Errorf("failed to read old file %s because %w", filename, err)
+	} else if err == nil {
+		if bytes.Equal(bs, old) {
+			// files are the same don't rewrite it.
+			return nil
+		}
+	}
+
 	file, err := os.Create(filename)
 	if err != nil {
 		return fmt.Errorf("failed to create file %s because %w", filename, err)
diff --git a/modules/charset/invisible/generate.go b/modules/charset/invisible/generate.go
index 230ff0b832..39eddd58dd 100644
--- a/modules/charset/invisible/generate.go
+++ b/modules/charset/invisible/generate.go
@@ -63,6 +63,17 @@ func runTemplate(t *template.Template, filename string, data interface{}) error
 		verbosef("Bad source:\n%s", buf.String())
 		return fmt.Errorf("unable to format source: %w", err)
 	}
+
+	old, err := os.ReadFile(filename)
+	if err != nil && !os.IsNotExist(err) {
+		return fmt.Errorf("failed to read old file %s because %w", filename, err)
+	} else if err == nil {
+		if bytes.Equal(bs, old) {
+			// files are the same don't rewrite it.
+			return nil
+		}
+	}
+
 	file, err := os.Create(filename)
 	if err != nil {
 		return fmt.Errorf("failed to create file %s because %w", filename, err)
diff --git a/services/migrations/dump.go b/services/migrations/dump.go
index 2dc35b9d9f..188f2775e0 100644
--- a/services/migrations/dump.go
+++ b/services/migrations/dump.go
@@ -26,7 +26,6 @@ import (
 	"code.gitea.io/gitea/modules/structs"
 
 	"github.com/google/uuid"
-
 	"gopkg.in/yaml.v2"
 )
 
diff --git a/templates/repo/sub_menu.tmpl b/templates/repo/sub_menu.tmpl
index 7ba234dccf..e63cb50df1 100644
--- a/templates/repo/sub_menu.tmpl
+++ b/templates/repo/sub_menu.tmpl
@@ -39,7 +39,7 @@
 	</div>
 	<a class="ui segment language-stats">
 		{{range .LanguageStats}}
-		<div class="bar tooltip" style="width: {{.Percentage}}%; background-color: {{.Color}}" data-placement="top" data-content={{ .Language }}>&nbsp;</div>
+		<div class="bar tooltip" style="width: {{.Percentage}}%; background-color: {{.Color}}" data-placement="top" data-content={{.Language}}>&nbsp;</div>
 		{{end}}
 	</a>
 	{{end}}
diff --git a/tests/integration/compare_test.go b/tests/integration/compare_test.go
index 7642109dd9..134ae520a8 100644
--- a/tests/integration/compare_test.go
+++ b/tests/integration/compare_test.go
@@ -10,6 +10,7 @@ import (
 	"testing"
 
 	"code.gitea.io/gitea/tests"
+
 	"github.com/stretchr/testify/assert"
 )
 
diff --git a/tests/integration/cors_test.go b/tests/integration/cors_test.go
index f531801627..c702c62e48 100644
--- a/tests/integration/cors_test.go
+++ b/tests/integration/cors_test.go
@@ -9,6 +9,7 @@ import (
 	"testing"
 
 	"code.gitea.io/gitea/tests"
+
 	"github.com/stretchr/testify/assert"
 )
 
diff --git a/tests/integration/nonascii_branches_test.go b/tests/integration/nonascii_branches_test.go
index ae69506f1b..638b9a6164 100644
--- a/tests/integration/nonascii_branches_test.go
+++ b/tests/integration/nonascii_branches_test.go
@@ -11,6 +11,7 @@ import (
 	"testing"
 
 	"code.gitea.io/gitea/tests"
+
 	"github.com/stretchr/testify/assert"
 )
 
diff --git a/tests/integration/pull_compare_test.go b/tests/integration/pull_compare_test.go
index 7934b6e77c..60e69e97eb 100644
--- a/tests/integration/pull_compare_test.go
+++ b/tests/integration/pull_compare_test.go
@@ -9,6 +9,7 @@ import (
 	"testing"
 
 	"code.gitea.io/gitea/tests"
+
 	"github.com/stretchr/testify/assert"
 )
 
diff --git a/tests/integration/pull_create_test.go b/tests/integration/pull_create_test.go
index 24c73ab4e9..b5cb7877bc 100644
--- a/tests/integration/pull_create_test.go
+++ b/tests/integration/pull_create_test.go
@@ -13,6 +13,7 @@ import (
 	"testing"
 
 	"code.gitea.io/gitea/tests"
+
 	"github.com/stretchr/testify/assert"
 )
 
diff --git a/tests/integration/repo_commits_search_test.go b/tests/integration/repo_commits_search_test.go
index 75e692f0ab..83f30758a4 100644
--- a/tests/integration/repo_commits_search_test.go
+++ b/tests/integration/repo_commits_search_test.go
@@ -11,6 +11,7 @@ import (
 	"testing"
 
 	"code.gitea.io/gitea/tests"
+
 	"github.com/stretchr/testify/assert"
 )
 
diff --git a/tests/integration/view_test.go b/tests/integration/view_test.go
index 63544dbe35..f55afb038c 100644
--- a/tests/integration/view_test.go
+++ b/tests/integration/view_test.go
@@ -9,6 +9,7 @@ import (
 	"testing"
 
 	"code.gitea.io/gitea/tests"
+
 	"github.com/stretchr/testify/assert"
 )