Repository: linkerd/linkerd2
Pull request #14243 (2025-07-14 06:47:10)

build(deps): bump tj-actions/changed-files from 5f66af5912c4f9c360c03a612f98606fb0f83790 to 055970845dd036d7345da7399b7e89f2e10f2b04
Bumps [tj-actions/changed-files](https://github.com/tj-actions/changed-files) from 5f66af5912c4f9c360c03a612f98606fb0f83790 to 055970845dd036d7345da7399b7e89f2e10f2b04.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a href="https://github.com/tj-actions/changed-files/blob/main/HISTORY.md">tj-actions/changed-files's changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<h1><a href="https://github.com/tj-actions/changed-files/compare/v46.0.4...v46.0.5">46.0.5</a> - (2025-04-09)</h1>
<h2><!-- raw HTML omitted -->⚙️ Miscellaneous Tasks</h2>
<ul>
<li><strong>deps:</strong> Bump yaml from 2.7.0 to 2.7.1 (<a href="https://redirect.github.com/tj-actions/changed-files/issues/2520">#2520</a>) (<a href="https://github.com/tj-actions/changed-files/commit/ed68ef82c095e0d48ec87eccea555d944a631a4c">ed68ef8</a>)  - (dependabot[bot])</li>
<li><strong>deps-dev:</strong> Bump typescript from 5.8.2 to 5.8.3 (<a href="https://redirect.github.com/tj-actions/changed-files/issues/2516">#2516</a>) (<a href="https://github.com/tj-actions/changed-files/commit/a7bc14b808f23d3b467a4079c69a81f1a4500fd5">a7bc14b</a>)  - (dependabot[bot])</li>
<li><strong>deps-dev:</strong> Bump <code>@​types/node</code> from 22.13.11 to 22.14.0 (<a href="https://redirect.github.com/tj-actions/changed-files/issues/2517">#2517</a>) (<a href="https://github.com/tj-actions/changed-files/commit/3d751f6b6d84071a17e1b9cf4ed79a80a27dd0ab">3d751f6</a>)  - (dependabot[bot])</li>
<li><strong>deps-dev:</strong> Bump eslint-plugin-prettier from 5.2.3 to 5.2.6 (<a href="https://redirect.github.com/tj-actions/changed-files/issues/2519">#2519</a>) (<a href="https://github.com/tj-actions/changed-files/commit/e2fda4ec3cb0bc2a353843cae823430b3124db8f">e2fda4e</a>)  - (dependabot[bot])</li>
<li><strong>deps-dev:</strong> Bump ts-jest from 29.2.6 to 29.3.1 (<a href="https://redirect.github.com/tj-actions/changed-files/issues/2518">#2518</a>) (<a href="https://github.com/tj-actions/changed-files/commit/0bed1b1132ec4879a39a2d624cf82a00d0bcfa48">0bed1b1</a>)  - (dependabot[bot])</li>
<li><strong>deps:</strong> Bump github/codeql-action from 3.28.12 to 3.28.15 (<a href="https://redirect.github.com/tj-actions/changed-files/issues/2530">#2530</a>) (<a href="https://github.com/tj-actions/changed-files/commit/68024587dc36f49685c96d59d3f1081830f968bb">6802458</a>)  - (dependabot[bot])</li>
<li><strong>deps:</strong> Bump tj-actions/branch-names from 8.0.1 to 8.1.0 (<a href="https://redirect.github.com/tj-actions/changed-files/issues/2521">#2521</a>) (<a href="https://github.com/tj-actions/changed-files/commit/cf2e39e86bf842d1f9bc5bca56c0a6b207cca792">cf2e39e</a>)  - (dependabot[bot])</li>
<li><strong>deps:</strong> Bump tj-actions/verify-changed-files from 20.0.1 to 20.0.4 (<a href="https://redirect.github.com/tj-actions/changed-files/issues/2523">#2523</a>) (<a href="https://github.com/tj-actions/changed-files/commit/6abeaa506a419f85fa9e681260b443adbeebb3d4">6abeaa5</a>)  - (dependabot[bot])</li>
</ul>
<h2><!-- raw HTML omitted -->⬆️ Upgrades</h2>
<ul>
<li>Upgraded to v46.0.4 (<a href="https://redirect.github.com/tj-actions/changed-files/issues/2511">#2511</a>)</li>
</ul>
<p>Co-authored-by: github-actions[bot] &lt;41898282+github-actions[bot]<a href="https://github.com/users"><code>@​users</code></a>.noreply.github.com&gt; (<a href="https://github.com/tj-actions/changed-files/commit/6f67ee9ac810f0192ea7b3d2086406f97847bcf9">6f67ee9</a>)  - (github-actions[bot])</p>
<h1><a href="https://github.com/tj-actions/changed-files/compare/v46.0.3...v46.0.4">46.0.4</a> - (2025-04-03)</h1>
<h2><!-- raw HTML omitted -->🐛 Bug Fixes</h2>
<ul>
<li>Bug modified_keys and changed_key outputs not set when no changes detected (<a href="https://redirect.github.com/tj-actions/changed-files/issues/2509">#2509</a>) (<a href="https://github.com/tj-actions/changed-files/commit/6cb76d07bee4c9772c6882c06c37837bf82a04d3">6cb76d0</a>)  - (Tonye Jack)</li>
</ul>
<h2><!-- raw HTML omitted -->📚 Documentation</h2>
<ul>
<li>Update readme (<a href="https://redirect.github.com/tj-actions/changed-files/issues/2508">#2508</a>) (<a href="https://github.com/tj-actions/changed-files/commit/b74df86ccb65173a8e33ba5492ac1a2ca6b216fd">b74df86</a>)  - (Tonye Jack)</li>
</ul>
<h2><!-- raw HTML omitted -->⬆️ Upgrades</h2>
<ul>
<li>Upgraded to v46.0.3 (<a href="https://redirect.github.com/tj-actions/changed-files/issues/2506">#2506</a>)</li>
</ul>
<p>Co-authored-by: github-actions[bot] &lt;41898282+github-actions[bot]<a href="https://github.com/users"><code>@​users</code></a>.noreply.github.com&gt;
Co-authored-by: Tonye Jack <a href="mailto:jtonye@ymail.com">jtonye@ymail.com</a> (<a href="https://github.com/tj-actions/changed-files/commit/27ae6b33eaed7bf87272fdeb9f1c54f9facc9d99">27ae6b3</a>)  - (github-actions[bot])</p>
<h1><a href="https://github.com/tj-actions/changed-files/compare/v46.0.2...v46.0.3">46.0.3</a> - (2025-03-23)</h1>
<h2><!-- raw HTML omitted -->🔄 Update</h2>
<ul>
<li>Updated README.md (<a href="https://redirect.github.com/tj-actions/changed-files/issues/2501">#2501</a>)</li>
</ul>
<p>Co-authored-by: github-actions[bot] &lt;41898282+github-actions[bot]<a href="https://github.com/users"><code>@​users</code></a>.noreply.github.com&gt; (<a href="https://github.com/tj-actions/changed-files/commit/41e0de576a0f2b64d9f06f2773f539109e55a70a">41e0de5</a>)  - (github-actions[bot])</p>
<ul>
<li>Updated README.md (<a href="https://redirect.github.com/tj-actions/changed-files/issues/2499">#2499</a>)</li>
</ul>
<p>Co-authored-by: github-actions[bot] &lt;41898282+github-actions[bot]<a href="https://github.com/users"><code>@​users</code></a>.noreply.github.com&gt; (<a href="https://github.com/tj-actions/changed-files/commit/945787811a795cd840a1157ac590dd7827a05c8e">9457878</a>)  - (github-actions[bot])</p>
<h2><!-- raw HTML omitted -->📚 Documentation</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/tj-actions/changed-files/commit/055970845dd036d7345da7399b7e89f2e10f2b04"><code>0559708</code></a> chore(deps-dev): bump <code>@​types/node</code> from 24.0.12 to 24.0.13 (<a href="https://redirect.github.com/tj-actions/changed-files/issues/2617">#2617</a>)</li>
<li>See full diff in <a href="https://github.com/tj-actions/changed-files/compare/5f66af5912c4f9c360c03a612f98606fb0f83790...055970845dd036d7345da7399b7e89f2e10f2b04">compare view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>


Patch:
diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index 4f480ad29..84ca0598f 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -9,7 +9,7 @@ jobs:
     runs-on: ubuntu-24.04
     steps:
       - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
-      - uses: tj-actions/changed-files@5f66af5912c4f9c360c03a612f98606fb0f83790
+      - uses: tj-actions/changed-files@055970845dd036d7345da7399b7e89f2e10f2b04
         id: changed
         with:
           files: |
diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml
index 8f62a08eb..371acc825 100644
--- a/.github/workflows/integration.yml
+++ b/.github/workflows/integration.yml
@@ -29,7 +29,7 @@ jobs:
       - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
       - id: tag
         run: echo "tag=$(CI_FORCE_CLEAN=1 bin/root-tag)" >> "$GITHUB_OUTPUT"
-      - uses: tj-actions/changed-files@5f66af5912c4f9c360c03a612f98606fb0f83790
+      - uses: tj-actions/changed-files@055970845dd036d7345da7399b7e89f2e10f2b04
         id: core
         with:
           files: |
diff --git a/.gitignore b/.gitignore
index 55ceac7c1..31b2b6d21 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,7 +12,6 @@ web/app/js/locales/_build
 web/app/js/locales/**/*.js
 web/app/yarn-error.log
 vendor
-**/*.gogen*
 **/*.swp
 **/charts/**/charts
 package-lock.json
diff --git a/bin/build-cli-bin b/bin/build-cli-bin
index 892dc6648..44d9500ad 100755
--- a/bin/build-cli-bin
+++ b/bin/build-cli-bin
@@ -17,12 +17,7 @@ rootdir=$( cd "$bindir"/.. && pwd )
     cd "$rootdir"
     cd "$(pwd -P)"
     target=target/cli/$(os)/linkerd
-     # TODO: `go generate` does not honor -mod=readonly
-    GO111MODULE=on go generate -mod=readonly ./pkg/charts/static
-    GO111MODULE=on go generate -mod=readonly ./jaeger/static
-    GO111MODULE=on go generate -mod=readonly ./multicluster/static
-    GO111MODULE=on go generate -mod=readonly ./viz/static
-    
+
     root_tag=$("$bindir"/root-tag)
     GO111MODULE=on CGO_ENABLED=0 go build -o "$target" -tags prod -mod=readonly -ldflags "-s -w -X github.com/linkerd/linkerd2/pkg/version.Version=$root_tag" ./cli
     echo "$target"
diff --git a/charts/templates.go b/charts/templates.go
new file mode 100644
index 000000000..3e5761bbc
--- /dev/null
+++ b/charts/templates.go
@@ -0,0 +1,8 @@
+package charts
+
+import (
+	"embed"
+)
+
+//go:embed linkerd-control-plane linkerd-crds linkerd2-cni all:partials patch
+var Templates embed.FS
diff --git a/cli/Dockerfile b/cli/Dockerfile
index c81073702..e2077eed2 100644
--- a/cli/Dockerfile
+++ b/cli/Dockerfile
@@ -22,13 +22,6 @@ COPY controller/api controller/api
 COPY controller/gen controller/gen
 COPY pkg pkg
 
-# Generate static templates
-# TODO: `go generate` does not honor -mod=readonly
-RUN go generate -mod=readonly ./pkg/charts/static
-RUN go generate -mod=readonly ./jaeger/static
-RUN go generate -mod=readonly ./multicluster/static
-RUN go generate -mod=readonly ./viz/static
-
 RUN mkdir -p /out
 
 FROM go-gen AS linux-amd64-full
diff --git a/cli/cmd/install-cni-plugin.go b/cli/cmd/install-cni-plugin.go
index 1b1906e60..eb8e19698 100644
--- a/cli/cmd/install-cni-plugin.go
+++ b/cli/cmd/install-cni-plugin.go
@@ -6,9 +6,9 @@ import (
 	"os"
 	"strings"
 
-	"github.com/linkerd/linkerd2/pkg/charts"
+	"github.com/linkerd/linkerd2/charts"
+	chartspkg "github.com/linkerd/linkerd2/pkg/charts"
 	cnicharts "github.com/linkerd/linkerd2/pkg/charts/cni"
-	"github.com/linkerd/linkerd2/pkg/charts/static"
 	"github.com/linkerd/linkerd2/pkg/cmd"
 	"github.com/linkerd/linkerd2/pkg/flags"
 	"github.com/linkerd/linkerd2/pkg/version"
@@ -249,13 +249,13 @@ func renderCNIPlugin(w io.Writer, valOpts values.Options, config *cniPluginOptio
 		{Name: "templates/cni-plugin.yaml"},
 	}
 
-	ch := &charts.Chart{
+	ch := &chartspkg.Chart{
 		Name:      helmCNIDefaultChartName,
 		Dir:       helmCNIDefaultChartDir,
 		Namespace: defaultCNINamespace,
 		Values:    mergedValues,
 		Files:     files,
-		Fs:        static.Templates,
+		Fs:        charts.Templates,
 	}
 
 	buf, err := ch.RenderCNI()
diff --git a/cli/cmd/install.go b/cli/cmd/install.go
index 7060b954d..1889368d5 100644
--- a/cli/cmd/install.go
+++ b/cli/cmd/install.go
@@ -13,10 +13,10 @@ import (
 	"text/template"
 	"time"
 
+	"github.com/linkerd/linkerd2/charts"
 	"github.com/linkerd/linkerd2/cli/flag"
-	"github.com/linkerd/linkerd2/pkg/charts"
+	chartspkg "github.com/linkerd/linkerd2/pkg/charts"
 	l5dcharts "github.com/linkerd/linkerd2/pkg/charts/linkerd2"
-	"github.com/linkerd/linkerd2/pkg/charts/static"
 	pkgcmd "github.com/linkerd/linkerd2/pkg/cmd"
 	flagspkg "github.com/linkerd/linkerd2/pkg/flags"
 	"github.com/linkerd/linkerd2/pkg/healthcheck"
@@ -331,14 +331,11 @@ func isRunAsRoot(values map[string]interface{}) bool {
 // them into a buffer. The coalesced values are also returned so that they may be rendered via
 // `renderOverrides` if appropriate.
 func renderChartToBuffer(files []*loader.BufferedFile, values map[string]interface{}, valuesOverrides map[string]interface{}) (*bytes.Buffer, chartutil.Values, error) {
-	// Load the partials in addition to the main chart.
-	var partials []*loader.BufferedFile
-	for _, template := range charts.L5dPartials {
-		partials = append(partials, &loader.BufferedFile{Name: template})
-	}
-	if err := charts.FilesReader(static.Templates, "", partials); err != nil {
+	partials, err := chartspkg.LoadPartials()
+	if err != nil {
 		return nil, nil, err
 	}
+
 	chart, err := loader.LoadFiles(append(files, partials...))
 	if err != nil {
 		return nil, nil, err
@@ -435,13 +432,13 @@ func renderCRDs(ctx context.Context, k *k8s.KubernetesAPI, w io.Writer, options
 	for _, template := range TemplatesCrdFiles {
 		files = append(files, &loader.BufferedFile{Name: template})
 	}
-	if err := charts.FilesReader(static.Templates, l5dcharts.HelmChartDirCrds+"/", files); err != nil {
+	if err := chartspkg.FilesReader(charts.Templates, l5dcharts.HelmChartDirCrds+"/", files); err != nil {
 		return err
 	}
 
 	// Load defaults from values.yaml
 	valuesFile := &loader.BufferedFile{Name: l5dcharts.HelmChartDirCrds + "/values.yaml"}
-	if err := charts.ReadFile(static.Templates, "/", valuesFile); err != nil {
+	if err := chartspkg.ReadFile(charts.Templates, "", valuesFile); err != nil {
 		return err
 	}
 	// Ensure the map is not nil, even if the default `values.yaml` is empty ---
@@ -470,7 +467,7 @@ func renderCRDs(ctx context.Context, k *k8s.KubernetesAPI, w io.Writer, options
 		}
 
 		defaultValues = updateDefaultValues(installed, defaultValues)
-		finalValues := charts.MergeMaps(defaultValues, valuesOverrides)
+		finalValues := chartspkg.MergeMaps(defaultValues, valuesOverrides)
 
 		if err := validateFinalValues(installed, finalValues); err != nil {
 			return err
@@ -492,7 +489,7 @@ func renderControlPlane(w io.Writer, values *l5dcharts.Values, valuesOverrides m
 	for _, template := range TemplatesControlPlane {
 		files = append(files, &loader.BufferedFile{Name: template})
 	}
-	if err := charts.FilesReader(static.Templates, l5dcharts.HelmChartDirCP+"/", files); err != nil {
+	if err := chartspkg.FilesReader(charts.Templates, l5dcharts.HelmChartDirCP+"/", files); err != nil {
 		return err
 	}
 
diff --git a/controller/Dockerfile b/controller/Dockerfile
index 283bd8969..986277143 100644
--- a/controller/Dockerfile
+++ b/controller/Dockerfile
@@ -14,14 +14,12 @@ FROM go-deps AS golang
 WORKDIR /linkerd-build
 COPY controller/gen controller/gen
 COPY pkg pkg
+COPY charts charts
 COPY controller controller
 COPY charts/patch charts/patch
 COPY charts/partials charts/partials
 COPY multicluster multicluster
 
-# Generate static templates
-# TODO: `go generate` does not honor -mod=readonly
-RUN go generate -mod=readonly ./pkg/charts/static
 ARG TARGETARCH
 RUN CGO_ENABLED=0 GOOS=linux GOARCH=$TARGETARCH go build -o /out/controller -tags prod -mod=readonly -ldflags "-s -w" ./controller/cmd
 
diff --git a/jaeger/charts/templates.go b/jaeger/charts/templates.go
new file mode 100644
index 000000000..7a24a2f31
--- /dev/null
+++ b/jaeger/charts/templates.go
@@ -0,0 +1,8 @@
+package charts
+
+import (
+	"embed"
+)
+
+//go:embed linkerd-jaeger
+var Templates embed.FS
diff --git a/jaeger/cmd/install.go b/jaeger/cmd/install.go
index 58f05dc75..d310f5a1e 100644
--- a/jaeger/cmd/install.go
+++ b/jaeger/cmd/install.go
@@ -8,9 +8,8 @@ import (
 	"path"
 	"time"
 
-	"github.com/linkerd/linkerd2/jaeger/static"
-	"github.com/linkerd/linkerd2/pkg/charts"
-	partials "github.com/linkerd/linkerd2/pkg/charts/static"
+	"github.com/linkerd/linkerd2/jaeger/charts"
+	chartspkg "github.com/linkerd/linkerd2/pkg/charts"
 	pkgcmd "github.com/linkerd/linkerd2/pkg/cmd"
 	"github.com/linkerd/linkerd2/pkg/flags"
 	"github.com/linkerd/linkerd2/pkg/healthcheck"
@@ -126,20 +125,13 @@ func render(w io.Writer, valuesOverrides map[string]interface{}, registry string
 		)
 	}
 
-	var partialFiles []*loader.BufferedFile
-	for _, template := range charts.L5dPartials {
-		partialFiles = append(partialFiles,
-			&loader.BufferedFile{Name: template},
-		)
-	}
-
 	// Load all jaeger chart files into buffer
-	if err := charts.FilesReader(static.Templates, "linkerd-jaeger/", files); err != nil {
+	if err := chartspkg.FilesReader(charts.Templates, "linkerd-jaeger/", files); err != nil {
 		return err
 	}
 
-	// Load all partial chart files into buffer
-	if err := charts.FilesReader(partials.Templates, "", partialFiles); err != nil {
+	partialFiles, err := chartspkg.LoadPartials()
+	if err != nil {
 		return err
 	}
 
@@ -154,7 +146,7 @@ func render(w io.Writer, valuesOverrides map[string]interface{}, registry string
 		return err
 	}
 
-	vals, err = charts.InsertVersionValues(vals)
+	vals, err = chartspkg.InsertVersionValues(vals)
 	if err != nil {
 		return err
 	}
diff --git a/jaeger/static/generate.go b/jaeger/static/generate.go
deleted file mode 100644
index cb0637209..000000000
--- a/jaeger/static/generate.go
+++ /dev/null
@@ -1,21 +0,0 @@
-//go:build ignore
-
-package main
-
-import (
-	"github.com/linkerd/linkerd2/jaeger/static"
-	"github.com/shurcooL/vfsgen"
-	log "github.com/sirupsen/logrus"
-)
-
-func main() {
-	err := vfsgen.Generate(static.Templates, vfsgen.Options{
-		Filename:     "generated_jaeger_templates.gogen.go",
-		PackageName:  "static",
-		BuildTags:    "prod",
-		VariableName: "Templates",
-	})
-	if err != nil {
-		log.Fatalln(err)
-	}
-}
diff --git a/jaeger/static/templates.go b/jaeger/static/templates.go
deleted file mode 100644
index a132ddda4..000000000
--- a/jaeger/static/templates.go
+++ /dev/null
@@ -1,15 +0,0 @@
-//go:generate go run generate.go
-//go:build !prod
-
-package static
-
-import (
-	"net/http"
-	"path"
-
-	"github.com/linkerd/linkerd2/pkg/charts/static"
-)
-
-// Templates that will be rendered by `linkerd install`. This is only used on
-// dev builds.
-var Templates http.FileSystem = http.Dir(path.Join(static.GetRepoRoot(), "jaeger/charts"))
diff --git a/multicluster/charts/templates.go b/multicluster/charts/templates.go
new file mode 100644
index 000000000..1c6ee6d1f
--- /dev/null
+++ b/multicluster/charts/templates.go
@@ -0,0 +1,8 @@
+package charts
+
+import (
+	"embed"
+)
+
+//go:embed linkerd-multicluster linkerd-multicluster-link
+var Templates embed.FS
diff --git a/multicluster/cmd/allow.go b/multicluster/cmd/allow.go
index 5d955c879..760593d42 100644
--- a/multicluster/cmd/allow.go
+++ b/multicluster/cmd/allow.go
@@ -5,9 +5,9 @@ import (
 	"errors"
 	"fmt"
 
-	"github.com/linkerd/linkerd2/multicluster/static"
+	"github.com/linkerd/linkerd2/multicluster/charts"
 	mccharts "github.com/linkerd/linkerd2/multicluster/values"
-	"github.com/linkerd/linkerd2/pkg/charts"
+	chartspkg "github.com/linkerd/linkerd2/pkg/charts"
 	pkgcmd "github.com/linkerd/linkerd2/pkg/cmd"
 	"github.com/linkerd/linkerd2/pkg/k8s"
 	"github.com/linkerd/linkerd2/pkg/version"
@@ -59,13 +59,13 @@ func newAllowCommand() *cobra.Command {
 				{Name: "templates/remote-access-service-mirror-rbac.yaml"},
 			}
 
-			chart := &charts.Chart{
-				Name:      helmMulticlusterDefaultChartName,
-				Dir:       helmMulticlusterDefaultChartName,
+			chart := &chartspkg.Chart{
+				Name:      mccharts.HelmDefaultChartDir,
+				Dir:       mccharts.HelmDefaultChartDir,
 				Namespace: opts.namespace,
 				RawValues: rawValues,
 				Files:     files,
-				Fs:        static.Templates,
+				Fs:        charts.Templates,
 			}
 			buf, err := chart.Render()
 			if err != nil {
diff --git a/multicluster/cmd/install.go b/multicluster/cmd/install.go
index 8365b4ccc..a90b0dc96 100644
--- a/multicluster/cmd/install.go
+++ b/multicluster/cmd/install.go
@@ -11,10 +11,9 @@ import (
 	"strings"
 	"time"
 
-	"github.com/linkerd/linkerd2/multicluster/static"
+	"github.com/linkerd/linkerd2/multicluster/charts"
 	multicluster "github.com/linkerd/linkerd2/multicluster/values"
-	"github.com/linkerd/linkerd2/pkg/charts"
-	partials "github.com/linkerd/linkerd2/pkg/charts/static"
+	chartspkg "github.com/linkerd/linkerd2/pkg/charts"
 	pkgcmd "github.com/linkerd/linkerd2/pkg/cmd"
 	"github.com/linkerd/linkerd2/pkg/flags"
 	"github.com/linkerd/linkerd2/pkg/healthcheck"
@@ -137,7 +136,7 @@ func install(ctx context.Context, w io.Writer, options *multiclusterInstallOptio
 	}
 
 	if ha {
-		valuesOverrides, err = charts.OverrideFromFile(valuesOverrides, static.Templates, helmMulticlusterDefaultChartName, "values-ha.yaml")
+		valuesOverrides, err = chartspkg.OverrideFromFile(valuesOverrides, charts.Templates, multicluster.HelmDefaultChartDir, "values-ha.yaml")
 		if err != nil {
 			return err
 		}
@@ -156,20 +155,13 @@ func render(w io.Writer, values *multicluster.Values, valuesOverrides map[string
 		files = append(files, &loader.BufferedFile{Name: template})
 	}
 
-	var partialFiles []*loader.BufferedFile
-	for _, template := range charts.L5dPartials {
-		partialFiles = append(partialFiles,
-			&loader.BufferedFile{Name: template},
-		)
-	}
-
 	// Load all multicluster install chart files into buffer
-	if err := charts.FilesReader(static.Templates, helmMulticlusterDefaultChartName+"/", files); err != nil {
+	if err := chartspkg.FilesReader(charts.Templates, multicluster.HelmDefaultChartDir+"/", files); err != nil {
 		return err
 	}
 
-	// Load all partial chart files into buffer
-	if err := charts.FilesReader(partials.Templates, "", partialFiles); err != nil {
+	partialFiles, err := chartspkg.LoadPartials()
+	if err != nil {
 		return err
 	}
 
diff --git a/multicluster/cmd/link.go b/multicluster/cmd/link.go
index 3511b39db..d21476504 100644
--- a/multicluster/cmd/link.go
+++ b/multicluster/cmd/link.go
@@ -10,10 +10,9 @@ import (
 	"strings"
 
 	"github.com/linkerd/linkerd2/controller/gen/apis/link/v1alpha3"
-	"github.com/linkerd/linkerd2/multicluster/static"
+	"github.com/linkerd/linkerd2/multicluster/charts"
 	multicluster "github.com/linkerd/linkerd2/multicluster/values"
-	"github.com/linkerd/linkerd2/pkg/charts"
-	partials "github.com/linkerd/linkerd2/pkg/charts/static"
+	chartspkg "github.com/linkerd/linkerd2/pkg/charts"
 	pkgcmd "github.com/linkerd/linkerd2/pkg/cmd"
 	"github.com/linkerd/linkerd2/pkg/flags"
 	"github.com/linkerd/linkerd2/pkg/k8s"
@@ -346,10 +345,10 @@ A full list of configurable values can be found at https://github.com/linkerd/li
 			}
 
 			if opts.ha {
-				if valuesOverrides, err = charts.OverrideFromFile(
+				if valuesOverrides, err = chartspkg.OverrideFromFile(
 					valuesOverrides,
-					static.Templates,
-					helmMulticlusterLinkDefaultChartName,
+					charts.Templates,
+					multicluster.HelmDefaultLinkChartDir,
 					"values-ha.yaml",
 				); err != nil {
 					return err
@@ -415,20 +414,13 @@ func renderServiceMirror(values *multicluster.Values, valuesOverrides map[string
 		{Name: "templates/gateway-mirror.yaml"},
 	}
 
-	var partialFiles []*chartloader.BufferedFile
-	for _, template := range charts.L5dPartials {
-		partialFiles = append(partialFiles,
-			&chartloader.BufferedFile{Name: template},
-		)
-	}
-
 	// Load all multicluster link chart files into buffer
-	if err := charts.FilesReader(static.Templates, helmMulticlusterLinkDefaultChartName+"/", files); err != nil {
+	if err := chartspkg.FilesReader(charts.Templates, multicluster.HelmDefaultLinkChartDir+"/", files); err != nil {
 		return nil, err
 	}
 
-	// Load all partial chart files into buffer
-	if err := charts.FilesReader(partials.Templates, "", partialFiles); err != nil {
+	partialFiles, err := chartspkg.LoadPartials()
+	if err != nil {
 		return nil, err
 	}
 
diff --git a/multicluster/cmd/root.go b/multicluster/cmd/root.go
index a420c2842..a2d2e6930 100644
--- a/multicluster/cmd/root.go
+++ b/multicluster/cmd/root.go
@@ -17,7 +17,6 @@ const (
 	defaultLinkerdNamespace              = "linkerd"
 	defaultMulticlusterNamespace         = "linkerd-multicluster"
 	defaultGatewayName                   = "linkerd-gateway"
-	helmMulticlusterDefaultChartName     = "linkerd-multicluster"
 	helmMulticlusterLinkDefaultChartName = "linkerd-multicluster-link"
 	tokenKey                             = "token"
 
@@ -30,6 +29,8 @@ const (
 )
 
 var (
+	HelmMulticlusterDefaultChartName = "linkerd-multicluster"
+
 	apiAddr               string // An empty value means "use the Kubernetes configuration"
 	controlPlaneNamespace string
 	kubeconfigPath        string
diff --git a/multicluster/static/generate.go b/multicluster/static/generate.go
deleted file mode 100644
index cd8049a28..000000000
--- a/multicluster/static/generate.go
+++ /dev/null
@@ -1,21 +0,0 @@
-//go:build ignore
-
-package main
-
-import (
-	"github.com/linkerd/linkerd2/multicluster/static"
-	"github.com/shurcooL/vfsgen"
-	log "github.com/sirupsen/logrus"
-)
-
-func main() {
-	err := vfsgen.Generate(static.Templates, vfsgen.Options{
-		Filename:     "generated_multicluster_templates.gogen.go",
-		PackageName:  "static",
-		BuildTags:    "prod",
-		VariableName: "Templates",
-	})
-	if err != nil {
-		log.Fatalln(err)
-	}
-}
diff --git a/multicluster/static/templates.go b/multicluster/static/templates.go
deleted file mode 100644
index c85a765da..000000000
--- a/multicluster/static/templates.go
+++ /dev/null
@@ -1,15 +0,0 @@
-//go:generate go run generate.go
-//go:build !prod
-
-package static
-
-import (
-	"net/http"
-	"path"
-
-	"github.com/linkerd/linkerd2/pkg/charts/static"
-)
-
-// Templates that will be rendered by `linkerd install`. This is only used on
-// dev builds.
-var Templates http.FileSystem = http.Dir(path.Join(static.GetRepoRoot(), "multicluster/charts"))
diff --git a/multicluster/values/values.go b/multicluster/values/values.go
index 65cd8eabd..84aa6af79 100644
--- a/multicluster/values/values.go
+++ b/multicluster/values/values.go
@@ -3,8 +3,8 @@ package values
 import (
 	"fmt"
 
-	"github.com/linkerd/linkerd2/multicluster/static"
-	"github.com/linkerd/linkerd2/pkg/charts"
+	"github.com/linkerd/linkerd2/multicluster/charts"
+	chartspkg "github.com/linkerd/linkerd2/pkg/charts"
 	"github.com/linkerd/linkerd2/pkg/charts/linkerd2"
 	"github.com/linkerd/linkerd2/pkg/k8s"
 	"helm.sh/helm/v3/pkg/chart/loader"
@@ -13,9 +13,9 @@ import (
 	"sigs.k8s.io/yaml"
 )
 
-const (
-	helmDefaultChartDir     = "linkerd-multicluster"
-	helmDefaultLinkChartDir = "linkerd-multicluster-link"
+var (
+	HelmDefaultChartDir     = "linkerd-multicluster"
+	HelmDefaultLinkChartDir = "linkerd-multicluster-link"
 )
 
 // Values contains the top-level elements in the Helm charts
@@ -113,7 +113,7 @@ type ControllerDefaultsProbe struct {
 
 // NewInstallValues returns a new instance of the Values type.
 func NewInstallValues() (*Values, error) {
-	chartDir := fmt.Sprintf("%s/", helmDefaultChartDir)
+	chartDir := fmt.Sprintf("%s/", HelmDefaultChartDir)
 	v, err := readDefaults(chartDir)
 	if err != nil {
 		return nil, err
@@ -125,7 +125,7 @@ func NewInstallValues() (*Values, error) {
 
 // NewLinkValues returns a new instance of the Values type.
 func NewLinkValues() (*Values, error) {
-	chartDir := fmt.Sprintf("%s/", helmDefaultLinkChartDir)
+	chartDir := fmt.Sprintf("%s/", HelmDefaultLinkChartDir)
 	v, err := readDefaults(chartDir)
 	if err != nil {
 		return nil, err
@@ -141,11 +141,11 @@ func readDefaults(chartDir string) (*Values, error) {
 	file := &loader.BufferedFile{
 		Name: chartutil.ValuesfileName,
 	}
-	if err := charts.ReadFile(static.Templates, chartDir, file); err != nil {
+	if err := chartspkg.ReadFile(charts.Templates, chartDir, file); err != nil {
 		return nil, err
 	}
 	values := Values{}
-	if err := yaml.Unmarshal(charts.InsertVersion(file.Data), &values); err != nil {
+	if err := yaml.Unmarshal(chartspkg.InsertVersion(file.Data), &values); err != nil {
 		return nil, err
 	}
 	return &values, nil
diff --git a/pkg/charts/charts.go b/pkg/charts/charts.go
index 7b7f16e39..9ce576c63 100644
--- a/pkg/charts/charts.go
+++ b/pkg/charts/charts.go
@@ -2,12 +2,12 @@ package charts
 
 import (
 	"bytes"
+	"embed"
 	"errors"
-	"net/http"
 	"path"
 	"strings"
 
-	"github.com/linkerd/linkerd2/pkg/charts/static"
+	"github.com/linkerd/linkerd2/charts"
 	"github.com/linkerd/linkerd2/pkg/version"
 	"helm.sh/helm/v3/pkg/chart/loader"
 	"helm.sh/helm/v3/pkg/chartutil"
@@ -19,25 +19,25 @@ const versionPlaceholder = "linkerdVersionValue"
 
 var (
 	// L5dPartials is the list of templates in partials chart
-	// Keep this slice synced with the contents of /charts/partials
+	// Keep this slice synced with the contents of charts/partials
 	L5dPartials = []string{
-		"charts/partials/" + chartutil.ChartfileName,
-		"charts/partials/templates/_affinity.tpl",
-		"charts/partials/templates/_capabilities.tpl",
-		"charts/partials/templates/_debug.tpl",
-		"charts/partials/templates/_helpers.tpl",
-		"charts/partials/templates/_metadata.tpl",
-		"charts/partials/templates/_nodeselector.tpl",
-		"charts/partials/templates/_network-validator.tpl",
-		"charts/partials/templates/_proxy-config-ann.tpl",
-		"charts/partials/templates/_proxy-init.tpl",
-		"charts/partials/templates/_proxy.tpl",
-		"charts/partials/templates/_pull-secrets.tpl",
-		"charts/partials/templates/_resources.tpl",
-		"charts/partials/templates/_tolerations.tpl",
-		"charts/partials/templates/_trace.tpl",
-		"charts/partials/templates/_validate.tpl",
-		"charts/partials/templates/_volumes.tpl",
+		"partials/" + chartutil.ChartfileName,
+		"partials/templates/_affinity.tpl",
+		"partials/templates/_capabilities.tpl",
+		"partials/templates/_debug.tpl",
+		"partials/templates/_helpers.tpl",
+		"partials/templates/_metadata.tpl",
+		"partials/templates/_nodeselector.tpl",
+		"partials/templates/_network-validator.tpl",
+		"partials/templates/_proxy-config-ann.tpl",
+		"partials/templates/_proxy-init.tpl",
+		"partials/templates/_proxy.tpl",
+		"partials/templates/_pull-secrets.tpl",
+		"partials/templates/_resources.tpl",
+		"partials/templates/_tolerations.tpl",
+		"partials/templates/_trace.tpl",
+		"partials/templates/_validate.tpl",
+		"partials/templates/_volumes.tpl",
 	}
 )
 
@@ -56,7 +56,7 @@ type Chart struct {
 	Values map[string]any
 
 	Files []*loader.BufferedFile
-	Fs    http.FileSystem
+	Fs    embed.FS
 }
 
 func (c *Chart) render(partialsFiles []*loader.BufferedFile) (bytes.Buffer, error) {
@@ -64,11 +64,6 @@ func (c *Chart) render(partialsFiles []*loader.BufferedFile) (bytes.Buffer, erro
 		return bytes.Buffer{}, err
 	}
 
-	// static.Templates is used as partials are always available there
-	if err := FilesReader(static.Templates, "", partialsFiles); err != nil {
-		return bytes.Buffer{}, err
-	}
-
 	// Create chart and render templates
 	chart, err := loader.LoadFiles(append(c.Files, partialsFiles...))
 	if err != nil {
@@ -119,36 +114,40 @@ func (c *Chart) render(partialsFiles []*loader.BufferedFile) (bytes.Buffer, erro
 // Render returns a bytes buffer with the result of rendering a Helm chart
 func (c *Chart) Render() (bytes.Buffer, error) {
 
-	l5dPartials := []*loader.BufferedFile{}
-	for _, template := range L5dPartials {
-		l5dPartials = append(l5dPartials, &loader.BufferedFile{
-			Name: template,
-		})
+	partials, err := LoadPartials()
+	if err != nil {
+		return bytes.Buffer{}, err
 	}
 
-	return c.render(l5dPartials)
+	return c.render(partials)
 }
 
 // RenderCNI returns a bytes buffer with the result of rendering a Helm chart
 func (c *Chart) RenderCNI() (bytes.Buffer, error) {
 	cniPartials := []*loader.BufferedFile{
-		{Name: "charts/partials/" + chartutil.ChartfileName},
-		{Name: "charts/partials/templates/_helpers.tpl"},
-		{Name: "charts/partials/templates/_metadata.tpl"},
-		{Name: "charts/partials/templates/_pull-secrets.tpl"},
-		{Name: "charts/partials/templates/_tolerations.tpl"},
-		{Name: "charts/partials/templates/_resources.tpl"},
+		{Name: "partials/" + chartutil.ChartfileName},
+		{Name: "partials/templates/_helpers.tpl"},
+		{Name: "partials/templates/_metadata.tpl"},
+		{Name: "partials/templates/_pull-secrets.tpl"},
+		{Name: "partials/templates/_tolerations.tpl"},
+		{Name: "partials/templates/_resources.tpl"},
+	}
+
+	// Load all partial chart files into buffer
+	if err := FilesReader(charts.Templates, "", cniPartials); err != nil {
+		return bytes.Buffer{}, err
+	}
+
+	// The partials files must have the "charts/" prefix to be loaded correctly.
+	for i, f := range cniPartials {
+		cniPartials[i].Name = path.Join("charts", f.Name)
 	}
 	return c.render(cniPartials)
 }
 
 // ReadFile updates the buffered file with the data read from disk
-func ReadFile(fs http.FileSystem, dir string, f *loader.BufferedFile) error {
-	filename := dir + f.Name
-	if dir == "" {
-		filename = filename[7:]
-	}
-	file, err := fs.Open(filename)
+func ReadFile(fs embed.FS, dir string, f *loader.BufferedFile) error {
+	file, err := fs.Open(dir + f.Name)
 	if err != nil {
 		return err
 	}
@@ -164,7 +163,7 @@ func ReadFile(fs http.FileSystem, dir string, f *loader.BufferedFile) error {
 }
 
 // FilesReader reads all the files from a directory
-func FilesReader(fs http.FileSystem, dir string, files []*loader.BufferedFile) error {
+func FilesReader(fs embed.FS, dir string, files []*loader.BufferedFile) error {
 	for _, f := range files {
 		if err := ReadFile(fs, dir, f); err != nil {
 			return err
@@ -173,6 +172,26 @@ func FilesReader(fs http.FileSystem, dir string, files []*loader.BufferedFile) e
 	return nil
 }
 
+func LoadPartials() ([]*loader.BufferedFile, error) {
+	var partialFiles []*loader.BufferedFile
+	for _, template := range L5dPartials {
+		partialFiles = append(partialFiles,
+			&loader.BufferedFile{Name: template},
+		)
+	}
+
+	// Load all partial chart files into buffer
+	if err := FilesReader(charts.Templates, "", partialFiles); err != nil {
+		return nil, err
+	}
+
+	// The partials files must have the "charts/" prefix to be loaded correctly.
+	for i, f := range partialFiles {
+		partialFiles[i].Name = path.Join("charts", f.Name)
+	}
+	return partialFiles, nil
+}
+
 // InsertVersion returns the chart values file contents passed in
 // with the version placeholder replaced with the current version
 func InsertVersion(data []byte) []byte {
@@ -191,7 +210,7 @@ func InsertVersionValues(values chartutil.Values) (chartutil.Values, error) {
 }
 
 // OverrideFromFile overrides the given map with the given file from FS
-func OverrideFromFile(values map[string]interface{}, fs http.FileSystem, chartName, name string) (map[string]interface{}, error) {
+func OverrideFromFile(values map[string]interface{}, fs embed.FS, chartName, name string) (map[string]interface{}, error) {
 	// Load Values file
 	valuesOverride := loader.BufferedFile{
 		Name: name,
diff --git a/pkg/charts/cni/values.go b/pkg/charts/cni/values.go
index 935cd331c..46b56d531 100644
--- a/pkg/charts/cni/values.go
+++ b/pkg/charts/cni/values.go
@@ -3,8 +3,8 @@ package cni
 import (
 	"fmt"
 
-	"github.com/linkerd/linkerd2/pkg/charts"
-	"github.com/linkerd/linkerd2/pkg/charts/static"
+	"github.com/linkerd/linkerd2/charts"
+	chartspkg "github.com/linkerd/linkerd2/pkg/charts"
 	"github.com/linkerd/linkerd2/pkg/k8s"
 	"helm.sh/helm/v3/pkg/chart/loader"
 	"helm.sh/helm/v3/pkg/chartutil"
@@ -111,11 +111,11 @@ func readDefaults(chartDir string) (*Values, error) {
 	file := &loader.BufferedFile{
 		Name: chartutil.ValuesfileName,
 	}
-	if err := charts.ReadFile(static.Templates, chartDir, file); err != nil {
+	if err := chartspkg.ReadFile(charts.Templates, chartDir, file); err != nil {
 		return nil, err
 	}
 	values := Values{}
-	if err := yaml.Unmarshal(charts.InsertVersion(file.Data), &values); err != nil {
+	if err := yaml.Unmarshal(chartspkg.InsertVersion(file.Data), &values); err != nil {
 		return nil, err
 	}
 	return &values, nil
diff --git a/pkg/charts/linkerd2/values.go b/pkg/charts/linkerd2/values.go
index 6c7e3c263..48b3f4d56 100644
--- a/pkg/charts/linkerd2/values.go
+++ b/pkg/charts/linkerd2/values.go
@@ -5,8 +5,8 @@ import (
 	"fmt"
 
 	"github.com/imdario/mergo"
-	"github.com/linkerd/linkerd2/pkg/charts"
-	"github.com/linkerd/linkerd2/pkg/charts/static"
+	"github.com/linkerd/linkerd2/charts"
+	chartspkg "github.com/linkerd/linkerd2/pkg/charts"
 	"github.com/linkerd/linkerd2/pkg/k8s"
 	"github.com/linkerd/linkerd2/pkg/version"
 	"helm.sh/helm/v3/pkg/chart/loader"
@@ -15,7 +15,7 @@ import (
 	"sigs.k8s.io/yaml"
 )
 
-const (
+var (
 	// HelmChartDirCrds is the directory name for the linkerd-crds chart
 	HelmChartDirCrds = "linkerd-crds"
 
@@ -443,12 +443,12 @@ func MergeHAValues(values *Values) error {
 // readDefaults read all the default variables from filename.
 func readDefaults(filename string) (*Values, error) {
 	valuesFile := &loader.BufferedFile{Name: filename}
-	if err := charts.ReadFile(static.Templates, "/", valuesFile); err != nil {
+	if err := chartspkg.ReadFile(charts.Templates, "", valuesFile); err != nil {
 		return nil, err
 	}
 
 	var values Values
-	err := yaml.Unmarshal(charts.InsertVersion(valuesFile.Data), &values)
+	err := yaml.Unmarshal(chartspkg.InsertVersion(valuesFile.Data), &values)
 
 	return &values, err
 }
diff --git a/pkg/charts/static/generate.go b/pkg/charts/static/generate.go
deleted file mode 100644
index ae84c0735..000000000
--- a/pkg/charts/static/generate.go
+++ /dev/null
@@ -1,21 +0,0 @@
-//go:build ignore
-
-package main
-
-import (
-	"github.com/linkerd/linkerd2/pkg/charts/static"
-	"github.com/shurcooL/vfsgen"
-	log "github.com/sirupsen/logrus"
-)
-
-func main() {
-	err := vfsgen.Generate(static.Templates, vfsgen.Options{
-		Filename:     "generated_linkerd_templates.gogen.go",
-		PackageName:  "static",
-		BuildTags:    "prod",
-		VariableName: "Templates",
-	})
-	if err != nil {
-		log.Fatalln(err)
-	}
-}
diff --git a/pkg/charts/static/helpers.go b/pkg/charts/static/helpers.go
deleted file mode 100644
index b88dea365..000000000
--- a/pkg/charts/static/helpers.go
+++ /dev/null
@@ -1,23 +0,0 @@
-package static
-
-import (
-	"path"
-	"path/filepath"
-	"runtime"
-)
-
-// GetRepoRoot returns the full path to the root of the repo. We assume this
-// function is only called from the `Templates` var above, and that this source
-// file lives at `pkg/charts/static`, relative to the root of the repo.
-func GetRepoRoot() string {
-	// /foo/bar/linkerd2/pkg/charts/static/templates.go
-	_, filename, _, _ := runtime.Caller(0)
-
-	// /foo/bar/linkerd2/pkg/charts/static
-	dir := filepath.Dir(filename)
-
-	// filepath.Dir returns the parent directory, so that combined with joining
-	// ".." walks 3 levels up the tree:
-	// /foo/bar/linkerd2
-	return filepath.Dir(path.Join(dir, "../.."))
-}
diff --git a/pkg/charts/static/templates.go b/pkg/charts/static/templates.go
deleted file mode 100644
index e613ec36a..000000000
--- a/pkg/charts/static/templates.go
+++ /dev/null
@@ -1,13 +0,0 @@
-//go:generate go run generate.go
-//go:build !prod
-
-package static
-
-import (
-	"net/http"
-	"path"
-)
-
-// Templates that will be rendered by `linkerd install`. This is only used on
-// dev builds.
-var Templates http.FileSystem = http.Dir(path.Join(GetRepoRoot(), "charts"))
diff --git a/pkg/inject/inject.go b/pkg/inject/inject.go
index 28e016c70..2291339f1 100644
--- a/pkg/inject/inject.go
+++ b/pkg/inject/inject.go
@@ -16,9 +16,9 @@ import (
 	"time"
 
 	jsonfilter "github.com/clarketm/json"
-	"github.com/linkerd/linkerd2/pkg/charts"
+	"github.com/linkerd/linkerd2/charts"
+	chartspkg "github.com/linkerd/linkerd2/pkg/charts"
 	l5dcharts "github.com/linkerd/linkerd2/pkg/charts/linkerd2"
-	"github.com/linkerd/linkerd2/pkg/charts/static"
 	"github.com/linkerd/linkerd2/pkg/k8s"
 	"github.com/linkerd/linkerd2/pkg/util"
 	log "github.com/sirupsen/logrus"
@@ -704,13 +704,13 @@ func GetPodPatch(conf *ResourceConfig, injectProxy bool, values *OverriddenValue
 		{Name: "templates/patch.json"},
 	}
 
-	chart := &charts.Chart{
+	chart := &chartspkg.Chart{
 		Name:      "patch",
 		Dir:       "patch",
 		Namespace: conf.namespace,
 		RawValues: rawValues,
 		Files:     files,
-		Fs:        static.Templates,
+		Fs:        charts.Templates,
 	}
 	buf, err := chart.Render()
 	if err != nil {
diff --git a/viz/charts/templates.go b/viz/charts/templates.go
new file mode 100644
index 000000000..7eb9af74a
--- /dev/null
+++ b/viz/charts/templates.go
@@ -0,0 +1,8 @@
+package charts
+
+import (
+	"embed"
+)
+
+//go:embed linkerd-viz
+var Templates embed.FS
diff --git a/viz/cmd/allow-scrapes.go b/viz/cmd/allow-scrapes.go
index 54a8d408e..76922b410 100644
--- a/viz/cmd/allow-scrapes.go
+++ b/viz/cmd/allow-scrapes.go
@@ -121,7 +121,7 @@ func newCmdAllowScrapes() *cobra.Command {
 	output := "yaml"
 	options := templateOptions{
 		ExtensionName: ExtensionName,
-		ChartName:     vizChartName,
+		ChartName:     VizChartName,
 		Version:       version.Version,
 		VizNs:         defaultNamespace,
 	}
diff --git a/viz/cmd/install.go b/viz/cmd/install.go
index 0e07338a3..f4dc2cd0c 100644
--- a/viz/cmd/install.go
+++ b/viz/cmd/install.go
@@ -7,12 +7,11 @@ import (
 	"path"
 	"time"
 
-	"github.com/linkerd/linkerd2/pkg/charts"
-	partials "github.com/linkerd/linkerd2/pkg/charts/static"
+	chartspkg "github.com/linkerd/linkerd2/pkg/charts"
 	pkgcmd "github.com/linkerd/linkerd2/pkg/cmd"
 	"github.com/linkerd/linkerd2/pkg/flags"
 	"github.com/linkerd/linkerd2/pkg/healthcheck"
-	"github.com/linkerd/linkerd2/viz/static"
+	"github.com/linkerd/linkerd2/viz/charts"
 	"github.com/spf13/cobra"
 	"helm.sh/helm/v3/pkg/chart/loader"
 	"helm.sh/helm/v3/pkg/chartutil"
@@ -112,7 +111,7 @@ func install(w io.Writer, options values.Options, ha, cniEnabled bool, format st
 	}
 
 	if ha {
-		valuesOverrides, err = charts.OverrideFromFile(valuesOverrides, static.Templates, vizChartName, "values-ha.yaml")
+		valuesOverrides, err = chartspkg.OverrideFromFile(valuesOverrides, charts.Templates, VizChartName, "values-ha.yaml")
 		if err != nil {
 			return err
 		}
@@ -140,20 +139,13 @@ func render(w io.Writer, valuesOverrides map[string]interface{}, format string)
 		)
 	}
 
-	var partialFiles []*loader.BufferedFile
-	for _, template := range charts.L5dPartials {
-		partialFiles = append(partialFiles,
-			&loader.BufferedFile{Name: template},
-		)
-	}
-
 	// Load all Viz chart files into buffer
-	if err := charts.FilesReader(static.Templates, vizChartName+"/", files); err != nil {
+	if err := chartspkg.FilesReader(charts.Templates, VizChartName+"/", files); err != nil {
 		return err
 	}
 
-	// Load all partial chart files into buffer
-	if err := charts.FilesReader(partials.Templates, "", partialFiles); err != nil {
+	partialFiles, err := chartspkg.LoadPartials()
+	if err != nil {
 		return err
 	}
 
@@ -168,7 +160,7 @@ func render(w io.Writer, valuesOverrides map[string]interface{}, format string)
 		return err
 	}
 
-	vals, err = charts.InsertVersionValues(vals)
+	vals, err = chartspkg.InsertVersionValues(vals)
 	if err != nil {
 		return err
 	}
diff --git a/viz/cmd/root.go b/viz/cmd/root.go
index 5213f5edd..85b273220 100644
--- a/viz/cmd/root.go
+++ b/viz/cmd/root.go
@@ -19,7 +19,6 @@ const (
 	// until 15d1809bd043192bb21cacbc96112cce35bf384f
 	LegacyExtensionName = "linkerd-viz"
 
-	vizChartName            = "linkerd-viz"
 	defaultNamespace        = "linkerd-viz"
 	defaultLinkerdNamespace = "linkerd"
 	maxRps                  = 100.0
@@ -31,6 +30,8 @@ const (
 )
 
 var (
+	VizChartName = "linkerd-viz"
+
 	// special handling for Windows, on all other platforms these resolve to
 	// os.Stdout and os.Stderr, thanks to https://github.com/mattn/go-colorable
 	stdout = color.Output
diff --git a/viz/static/generate.go b/viz/static/generate.go
deleted file mode 100644
index 28785ffbc..000000000
--- a/viz/static/generate.go
+++ /dev/null
@@ -1,21 +0,0 @@
-//go:build ignore
-
-package main
-
-import (
-	"github.com/linkerd/linkerd2/viz/static"
-	"github.com/shurcooL/vfsgen"
-	log "github.com/sirupsen/logrus"
-)
-
-func main() {
-	err := vfsgen.Generate(static.Templates, vfsgen.Options{
-		Filename:     "generated_viz_templates.gogen.go",
-		PackageName:  "static",
-		BuildTags:    "prod",
-		VariableName: "Templates",
-	})
-	if err != nil {
-		log.Fatalln(err)
-	}
-}
diff --git a/viz/static/templates.go b/viz/static/templates.go
deleted file mode 100644
index c240343e5..000000000
--- a/viz/static/templates.go
+++ /dev/null
@@ -1,15 +0,0 @@
-//go:generate go run generate.go
-//go:build !prod
-
-package static
-
-import (
-	"net/http"
-	"path"
-
-	"github.com/linkerd/linkerd2/pkg/charts/static"
-)
-
-// Templates that will be rendered by `linkerd viz install`. This is only used on
-// dev builds.
-var Templates http.FileSystem = http.Dir(path.Join(static.GetRepoRoot(), "viz/charts"))
diff --git a/web/Dockerfile b/web/Dockerfile
index b32abbf03..f557dbf84 100644
--- a/web/Dockerfile
+++ b/web/Dockerfile
@@ -43,6 +43,7 @@ COPY viz/pkg viz/pkg
 COPY viz/tap/gen/tap viz/tap/gen/tap
 COPY viz/tap/pkg viz/tap/pkg
 COPY pkg pkg
+COPY charts charts
 ARG TARGETARCH
 RUN CGO_ENABLED=0 GOOS=linux GOARCH=$TARGETARCH go build -mod=readonly -o web/web -ldflags "-s -w" ./web
 
diff --git a/web/app/package.json b/web/app/package.json
index 96e79af7f..132eade13 100644
--- a/web/app/package.json
+++ b/web/app/package.json
@@ -16,7 +16,7 @@
     "@material-ui/icons": "4.11.3",
     "@material-ui/lab": "^4.0.0-alpha.61",
     "classnames": "2.5.1",
-    "core-js": "^3.43.0",
+    "core-js": "^3.44.0",
     "css-mediaquery": "^0.1.2",
     "d3-drag": "3.0.0",
     "d3-force": "3.0.0",
@@ -29,7 +29,7 @@
     "make-plural": "^7.4.0",
     "path": "0.12.7",
     "prop-types": "15.8.1",
-    "query-string": "^9.2.1",
+    "query-string": "^9.2.2",
     "react": "16.14.0",
     "react-dom": "16.14.0",
     "react-linkify": "1.0.0-alpha",
@@ -44,12 +44,12 @@
     "@babel/core": "^7.28.0",
     "@babel/eslint-parser": "^7.28.0",
     "@babel/plugin-proposal-class-properties": "^7.17.12",
-    "@babel/preset-env": "^7.27.2",
+    "@babel/preset-env": "^7.28.0",
     "@babel/preset-react": "^7.27.1",
     "@babel/runtime": "^7.27.6",
     "@lingui/cli": "3.17.2",
     "babel-core": "^7.0.0-bridge.0",
-    "babel-jest": "^30.0.2",
+    "babel-jest": "^30.0.4",
     "babel-loader": "^10.0.0",
     "babel-plugin-import": "^1.13.8",
     "babel-plugin-macros": "^3.1.0",
diff --git a/web/app/yarn.lock b/web/app/yarn.lock
index eb3e7b014..2d3c782eb 100644
--- a/web/app/yarn.lock
+++ b/web/app/yarn.lock
@@ -35,10 +35,10 @@
     js-tokens "^4.0.0"
     picocolors "^1.1.1"
 
-"@babel/compat-data@^7.22.6", "@babel/compat-data@^7.27.2":
-  version "7.27.2"
-  resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.27.2.tgz#4183f9e642fd84e74e3eea7ffa93a412e3b102c9"
-  integrity sha512-TUtMJYRPyUb/9aU8f3K0mjmjf6M9N5Woshn2CS6nqJSeJtTtQcpLUXjGt9vbF8ZGff0El99sWkLgzwW3VXnxZQ==
+"@babel/compat-data@^7.27.2", "@babel/compat-data@^7.27.7", "@babel/compat-data@^7.28.0":
+  version "7.28.0"
+  resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.28.0.tgz#9fc6fd58c2a6a15243cd13983224968392070790"
+  integrity sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==
 
 "@babel/core@^7.12.3", "@babel/core@^7.23.9", "@babel/core@^7.27.4", "@babel/core@^7.28.0":
   version "7.28.0"
@@ -102,7 +102,14 @@
   dependencies:
     "@babel/types" "^7.27.1"
 
-"@babel/helper-compilation-targets@^7.22.6", "@babel/helper-compilation-targets@^7.27.1", "@babel/helper-compilation-targets@^7.27.2":
+"@babel/helper-annotate-as-pure@^7.27.3":
+  version "7.27.3"
+  resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz#f31fd86b915fc4daf1f3ac6976c59be7084ed9c5"
+  integrity sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==
+  dependencies:
+    "@babel/types" "^7.27.3"
+
+"@babel/helper-compilation-targets@^7.27.1", "@babel/helper-compilation-targets@^7.27.2":
   version "7.27.2"
   resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz#46a0f6efab808d51d29ce96858dd10ce8732733d"
   integrity sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==
@@ -156,27 +163,16 @@
     regexpu-core "^6.2.0"
     semver "^6.3.1"
 
-"@babel/helper-define-polyfill-provider@^0.6.1":
-  version "0.6.1"
-  resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.1.tgz#fadc63f0c2ff3c8d02ed905dcea747c5b0fb74fd"
-  integrity sha512-o7SDgTJuvx5vLKD6SFvkydkSMBvahDKGiNJzG22IZYXhiqoe9efY7zocICBgzHV4IRg5wdgl2nEL/tulKIEIbA==
-  dependencies:
-    "@babel/helper-compilation-targets" "^7.22.6"
-    "@babel/helper-plugin-utils" "^7.22.5"
-    debug "^4.1.1"
-    lodash.debounce "^4.0.8"
-    resolve "^1.14.2"
-
-"@babel/helper-define-polyfill-provider@^0.6.3":
-  version "0.6.3"
-  resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.3.tgz#f4f2792fae2ef382074bc2d713522cf24e6ddb21"
-  integrity sha512-HK7Bi+Hj6H+VTHA3ZvBis7V/6hu9QuTrnMXNybfUf2iiuU/N97I8VjB+KbhFF8Rld/Lx5MzoCwPCpPjfK+n8Cg==
+"@babel/helper-define-polyfill-provider@^0.6.5":
+  version "0.6.5"
+  resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.5.tgz#742ccf1cb003c07b48859fc9fa2c1bbe40e5f753"
+  integrity sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg==
   dependencies:
-    "@babel/helper-compilation-targets" "^7.22.6"
-    "@babel/helper-plugin-utils" "^7.22.5"
-    debug "^4.1.1"
+    "@babel/helper-compilation-targets" "^7.27.2"
+    "@babel/helper-plugin-utils" "^7.27.1"
+    debug "^4.4.1"
     lodash.debounce "^4.0.8"
-    resolve "^1.14.2"
+    resolve "^1.22.10"
 
 "@babel/helper-environment-visitor@^7.18.6":
   version "7.18.6"
@@ -249,7 +245,7 @@
   dependencies:
     "@babel/types" "^7.27.1"
 
-"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.27.1", "@babel/helper-plugin-utils@^7.8.0":
+"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.27.1", "@babel/helper-plugin-utils@^7.8.0":
   version "7.27.1"
   resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz#ddb2f876534ff8013e6c2b299bf4d39b3c51d44c"
   integrity sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==
@@ -537,14 +533,14 @@
   dependencies:
     "@babel/helper-plugin-utils" "^7.27.1"
 
-"@babel/plugin-transform-async-generator-functions@^7.27.1":
-  version "7.27.1"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.27.1.tgz#ca433df983d68e1375398e7ca71bf2a4f6fd89d7"
-  integrity sha512-eST9RrwlpaoJBDHShc+DS2SG4ATTi2MYNb4OxYkf3n+7eb49LWpnS+HSpVfW4x927qQwgk8A2hGNVaajAEw0EA==
+"@babel/plugin-transform-async-generator-functions@^7.28.0":
+  version "7.28.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.28.0.tgz#1276e6c7285ab2cd1eccb0bc7356b7a69ff842c2"
+  integrity sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q==
   dependencies:
     "@babel/helper-plugin-utils" "^7.27.1"
     "@babel/helper-remap-async-to-generator" "^7.27.1"
-    "@babel/traverse" "^7.27.1"
+    "@babel/traverse" "^7.28.0"
 
 "@babel/plugin-transform-async-to-generator@^7.27.1":
   version "7.27.1"
@@ -562,10 +558,10 @@
   dependencies:
     "@babel/helper-plugin-utils" "^7.27.1"
 
-"@babel/plugin-transform-block-scoping@^7.27.1":
-  version "7.27.1"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.27.1.tgz#bc0dbe8ac6de5602981ba58ef68c6df8ef9bfbb3"
-  integrity sha512-QEcFlMl9nGTgh1rn2nIeU5bkfb9BAjaQcWbiP4LvKxUot52ABcTkpcyJ7f2Q2U2RuQ84BNLgts3jRme2dTx6Fw==
+"@babel/plugin-transform-block-scoping@^7.28.0":
+  version "7.28.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.0.tgz#e7c50cbacc18034f210b93defa89638666099451"
+  integrity sha512-gKKnwjpdx5sER/wl0WN0efUBFzF/56YZO0RJrSYP4CljXnP31ByY7fol89AzomdlLNzI36AvOTmYHsnZTCkq8Q==
   dependencies:
     "@babel/helper-plugin-utils" "^7.27.1"
 
@@ -585,17 +581,17 @@
     "@babel/helper-create-class-features-plugin" "^7.27.1"
     "@babel/helper-plugin-utils" "^7.27.1"
 
-"@babel/plugin-transform-classes@^7.27.1":
-  version "7.27.1"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.27.1.tgz#03bb04bea2c7b2f711f0db7304a8da46a85cced4"
-  integrity sha512-7iLhfFAubmpeJe/Wo2TVuDrykh/zlWXLzPNdL0Jqn/Xu8R3QQ8h9ff8FQoISZOsw74/HFqFI7NX63HN7QFIHKA==
+"@babel/plugin-transform-classes@^7.28.0":
+  version "7.28.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.0.tgz#12fa46cffc32a6e084011b650539e880add8a0f8"
+  integrity sha512-IjM1IoJNw72AZFlj33Cu8X0q2XK/6AaVC3jQu+cgQ5lThWD5ajnuUAml80dqRmOhmPkTH8uAwnpMu9Rvj0LTRA==
   dependencies:
-    "@babel/helper-annotate-as-pure" "^7.27.1"
-    "@babel/helper-compilation-targets" "^7.27.1"
+    "@babel/helper-annotate-as-pure" "^7.27.3"
+    "@babel/helper-compilation-targets" "^7.27.2"
+    "@babel/helper-globals" "^7.28.0"
     "@babel/helper-plugin-utils" "^7.27.1"
     "@babel/helper-replace-supers" "^7.27.1"
-    "@babel/traverse" "^7.27.1"
-    globals "^11.1.0"
+    "@babel/traverse" "^7.28.0"
 
 "@babel/plugin-transform-computed-properties@^7.27.1":
   version "7.27.1"
@@ -605,12 +601,13 @@
     "@babel/helper-plugin-utils" "^7.27.1"
     "@babel/template" "^7.27.1"
 
-"@babel/plugin-transform-destructuring@^7.27.1":
-  version "7.27.1"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.27.1.tgz#d5916ef7089cb254df0418ae524533c1b72ba656"
-  integrity sha512-ttDCqhfvpE9emVkXbPD8vyxxh4TWYACVybGkDj+oReOGwnp066ITEivDlLwe0b1R0+evJ13IXQuLNB5w1fhC5Q==
+"@babel/plugin-transform-destructuring@^7.28.0":
+  version "7.28.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.0.tgz#0f156588f69c596089b7d5b06f5af83d9aa7f97a"
+  integrity sha512-v1nrSMBiKcodhsyJ4Gf+Z0U/yawmJDBOTpEB3mcQY52r9RIyPneGyAS/yM6seP/8I+mWI3elOMtT5dB8GJVs+A==
   dependencies:
     "@babel/helper-plugin-utils" "^7.27.1"
+    "@babel/traverse" "^7.28.0"
 
 "@babel/plugin-transform-dotall-regex@^7.27.1":
   version "7.27.1"
@@ -642,6 +639,14 @@
   dependencies:
     "@babel/helper-plugin-utils" "^7.27.1"
 
+"@babel/plugin-transform-explicit-resource-management@^7.28.0":
+  version "7.28.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.0.tgz#45be6211b778dbf4b9d54c4e8a2b42fa72e09a1a"
+  integrity sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.27.1"
+    "@babel/plugin-transform-destructuring" "^7.28.0"
+
 "@babel/plugin-transform-exponentiation-operator@^7.27.1":
   version "7.27.1"
   resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.27.1.tgz#fc497b12d8277e559747f5a3ed868dd8064f83e1"
@@ -764,15 +769,16 @@
   dependencies:
     "@babel/helper-plugin-utils" "^7.27.1"
 
-"@babel/plugin-transform-object-rest-spread@^7.27.2":
-  version "7.27.2"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.27.2.tgz#67f9ab822347aa2bcee91e8996763da79bdea973"
-  integrity sha512-AIUHD7xJ1mCrj3uPozvtngY3s0xpv7Nu7DoUSnzNY6Xam1Cy4rUznR//pvMHOhQ4AvbCexhbqXCtpxGHOGOO6g==
+"@babel/plugin-transform-object-rest-spread@^7.28.0":
+  version "7.28.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.0.tgz#d23021857ffd7cd809f54d624299b8086402ed8d"
+  integrity sha512-9VNGikXxzu5eCiQjdE4IZn8sb9q7Xsk5EXLDBKUYg1e/Tve8/05+KJEtcxGxAgCY5t/BpKQM+JEL/yT4tvgiUA==
   dependencies:
     "@babel/helper-compilation-targets" "^7.27.2"
     "@babel/helper-plugin-utils" "^7.27.1"
-    "@babel/plugin-transform-destructuring" "^7.27.1"
-    "@babel/plugin-transform-parameters" "^7.27.1"
+    "@babel/plugin-transform-destructuring" "^7.28.0"
+    "@babel/plugin-transform-parameters" "^7.27.7"
+    "@babel/traverse" "^7.28.0"
 
 "@babel/plugin-transform-object-super@^7.27.1":
   version "7.27.1"
@@ -797,10 +803,10 @@
     "@babel/helper-plugin-utils" "^7.27.1"
     "@babel/helper-skip-transparent-expression-wrappers" "^7.27.1"
 
-"@babel/plugin-transform-parameters@^7.27.1":
-  version "7.27.1"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.1.tgz#80334b54b9b1ac5244155a0c8304a187a618d5a7"
-  integrity sha512-018KRk76HWKeZ5l4oTj2zPpSh+NbGdt0st5S6x0pga6HgrjBOJb24mMDHorFopOOd6YHkLgOZ+zaCjZGPO4aKg==
+"@babel/plugin-transform-parameters@^7.27.7":
+  version "7.27.7"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz#1fd2febb7c74e7d21cf3b05f7aebc907940af53a"
+  integrity sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==
   dependencies:
     "@babel/helper-plugin-utils" "^7.27.1"
 
@@ -861,10 +867,10 @@
     "@babel/helper-annotate-as-pure" "^7.27.1"
     "@babel/helper-plugin-utils" "^7.27.1"
 
-"@babel/plugin-transform-regenerator@^7.27.1":
-  version "7.27.1"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.27.1.tgz#0a471df9213416e44cd66bf67176b66f65768401"
-  integrity sha512-B19lbbL7PMrKr52BNPjCqg1IyNUIjTcxKj8uX9zHO+PmWN93s19NDr/f69mIkEp2x9nmDJ08a7lgHaTTzvW7mw==
+"@babel/plugin-transform-regenerator@^7.28.0":
+  version "7.28.1"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.1.tgz#bde80603442ff4bb4e910bc8b35485295d556ab1"
+  integrity sha512-P0QiV/taaa3kXpLY+sXla5zec4E+4t4Aqc9ggHlfZ7a2cp8/x/Gv08jfwEtn9gnnYIMvHx6aoOZ8XJL8eU71Dg==
   dependencies:
     "@babel/helper-plugin-utils" "^7.27.1"
 
@@ -950,12 +956,12 @@
     "@babel/helper-create-regexp-features-plugin" "^7.27.1"
     "@babel/helper-plugin-utils" "^7.27.1"
 
-"@babel/preset-env@^7.27.2":
-  version "7.27.2"
-  resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.27.2.tgz#106e6bfad92b591b1f6f76fd4cf13b7725a7bf9a"
-  integrity sha512-Ma4zSuYSlGNRlCLO+EAzLnCmJK2vdstgv+n7aUP+/IKZrOfWHOJVdSJtuub8RzHTj3ahD37k5OKJWvzf16TQyQ==
+"@babel/preset-env@^7.28.0":
+  version "7.28.0"
+  resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.28.0.tgz#d23a6bc17b43227d11db77081a0779c706b5569c"
+  integrity sha512-VmaxeGOwuDqzLl5JUkIRM1X2Qu2uKGxHEQWh+cvvbl7JuJRgKGJSfsEF/bUaxFhJl/XAyxBe7q7qSuTbKFuCyg==
   dependencies:
-    "@babel/compat-data" "^7.27.2"
+    "@babel/compat-data" "^7.28.0"
     "@babel/helper-compilation-targets" "^7.27.2"
     "@babel/helper-plugin-utils" "^7.27.1"
     "@babel/helper-validator-option" "^7.27.1"
@@ -969,19 +975,20 @@
     "@babel/plugin-syntax-import-attributes" "^7.27.1"
     "@babel/plugin-syntax-unicode-sets-regex" "^7.18.6"
     "@babel/plugin-transform-arrow-functions" "^7.27.1"
-    "@babel/plugin-transform-async-generator-functions" "^7.27.1"
+    "@babel/plugin-transform-async-generator-functions" "^7.28.0"
     "@babel/plugin-transform-async-to-generator" "^7.27.1"
     "@babel/plugin-transform-block-scoped-functions" "^7.27.1"
-    "@babel/plugin-transform-block-scoping" "^7.27.1"
+    "@babel/plugin-transform-block-scoping" "^7.28.0"
     "@babel/plugin-transform-class-properties" "^7.27.1"
     "@babel/plugin-transform-class-static-block" "^7.27.1"
-    "@babel/plugin-transform-classes" "^7.27.1"
+    "@babel/plugin-transform-classes" "^7.28.0"
     "@babel/plugin-transform-computed-properties" "^7.27.1"
-    "@babel/plugin-transform-destructuring" "^7.27.1"
+    "@babel/plugin-transform-destructuring" "^7.28.0"
     "@babel/plugin-transform-dotall-regex" "^7.27.1"
     "@babel/plugin-transform-duplicate-keys" "^7.27.1"
     "@babel/plugin-transform-duplicate-named-capturing-groups-regex" "^7.27.1"
     "@babel/plugin-transform-dynamic-import" "^7.27.1"
+    "@babel/plugin-transform-explicit-resource-management" "^7.28.0"
     "@babel/plugin-transform-exponentiation-operator" "^7.27.1"
     "@babel/plugin-transform-export-namespace-from" "^7.27.1"
     "@babel/plugin-transform-for-of" "^7.27.1"
@@ -998,15 +1005,15 @@
     "@babel/plugin-transform-new-target" "^7.27.1"
     "@babel/plugin-transform-nullish-coalescing-operator" "^7.27.1"
     "@babel/plugin-transform-numeric-separator" "^7.27.1"
-    "@babel/plugin-transform-object-rest-spread" "^7.27.2"
+    "@babel/plugin-transform-object-rest-spread" "^7.28.0"
     "@babel/plugin-transform-object-super" "^7.27.1"
     "@babel/plugin-transform-optional-catch-binding" "^7.27.1"
     "@babel/plugin-transform-optional-chaining" "^7.27.1"
-    "@babel/plugin-transform-parameters" "^7.27.1"
+    "@babel/plugin-transform-parameters" "^7.27.7"
     "@babel/plugin-transform-private-methods" "^7.27.1"
     "@babel/plugin-transform-private-property-in-object" "^7.27.1"
     "@babel/plugin-transform-property-literals" "^7.27.1"
-    "@babel/plugin-transform-regenerator" "^7.27.1"
+    "@babel/plugin-transform-regenerator" "^7.28.0"
     "@babel/plugin-transform-regexp-modifiers" "^7.27.1"
     "@babel/plugin-transform-reserved-words" "^7.27.1"
     "@babel/plugin-transform-shorthand-properties" "^7.27.1"
@@ -1019,10 +1026,10 @@
     "@babel/plugin-transform-unicode-regex" "^7.27.1"
     "@babel/plugin-transform-unicode-sets-regex" "^7.27.1"
     "@babel/preset-modules" "0.1.6-no-external-plugins"
-    babel-plugin-polyfill-corejs2 "^0.4.10"
-    babel-plugin-polyfill-corejs3 "^0.11.0"
-    babel-plugin-polyfill-regenerator "^0.6.1"
-    core-js-compat "^3.40.0"
+    babel-plugin-polyfill-corejs2 "^0.4.14"
+    babel-plugin-polyfill-corejs3 "^0.13.0"
+    babel-plugin-polyfill-regenerator "^0.6.5"
+    core-js-compat "^3.43.0"
     semver "^6.3.1"
 
 "@babel/preset-modules@0.1.6-no-external-plugins":
@@ -1469,27 +1476,6 @@
     jest-haste-map "30.0.2"
     slash "^3.0.0"
 
-"@jest/transform@30.0.2":
-  version "30.0.2"
-  resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-30.0.2.tgz#62ba84fcc2389ab751e7ec923958c9b1163d90c3"
-  integrity sha512-kJIuhLMTxRF7sc0gPzPtCDib/V9KwW3I2U25b+lYCYMVqHHSrcZopS8J8H+znx9yixuFv+Iozl8raLt/4MoxrA==
-  dependencies:
-    "@babel/core" "^7.27.4"
-    "@jest/types" "30.0.1"
-    "@jridgewell/trace-mapping" "^0.3.25"
-    babel-plugin-istanbul "^7.0.0"
-    chalk "^4.1.2"
-    convert-source-map "^2.0.0"
-    fast-json-stable-stringify "^2.1.0"
-    graceful-fs "^4.2.11"
-    jest-haste-map "30.0.2"
-    jest-regex-util "30.0.1"
-    jest-util "30.0.2"
-    micromatch "^4.0.8"
-    pirates "^4.0.7"
-    slash "^3.0.0"
-    write-file-atomic "^5.0.1"
-
 "@jest/transform@30.0.4":
   version "30.0.4"
   resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-30.0.4.tgz#a06f8c6fc2a04985241b483096f821bafb99cc93"
@@ -2881,7 +2867,7 @@ babel-core@^7.0.0-bridge.0:
   resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-7.0.0-bridge.0.tgz#95a492ddd90f9b4e9a4a1da14eb335b87b634ece"
   integrity sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==
 
-babel-jest@30.0.4:
+babel-jest@30.0.4, babel-jest@^30.0.4:
   version "30.0.4"
   resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-30.0.4.tgz#63945c1b27227312fc687689073124dba5b28282"
   integrity sha512-UjG2j7sAOqsp2Xua1mS/e+ekddkSu3wpf4nZUSvXNHuVWdaOUXQ77+uyjJLDE9i0atm5x4kds8K9yb5lRsRtcA==
@@ -2894,19 +2880,6 @@ babel-jest@30.0.4:
     graceful-fs "^4.2.11"
     slash "^3.0.0"
 
-babel-jest@^30.0.2:
-  version "30.0.2"
-  resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-30.0.2.tgz#f627dc5afc3bd5795fc84735b4f1d74f9d4b8e91"
-  integrity sha512-A5kqR1/EUTidM2YC2YMEUDP2+19ppgOwK0IAd9Swc3q2KqFb5f9PtRUXVeZcngu0z5mDMyZ9zH2huJZSOMLiTQ==
-  dependencies:
-    "@jest/transform" "30.0.2"
-    "@types/babel__core" "^7.20.5"
-    babel-plugin-istanbul "^7.0.0"
-    babel-preset-jest "30.0.1"
-    chalk "^4.1.2"
-    graceful-fs "^4.2.11"
-    slash "^3.0.0"
-
 babel-loader@^10.0.0:
   version "10.0.0"
   resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-10.0.0.tgz#b9743714c0e1e084b3e4adef3cd5faee33089977"
@@ -2950,29 +2923,29 @@ babel-plugin-macros@^3.0.1, babel-plugin-macros@^3.1.0:
     cosmiconfig "^7.0.0"
     resolve "^1.19.0"
 
-babel-plugin-polyfill-corejs2@^0.4.10:
-  version "0.4.10"
-  resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.10.tgz#276f41710b03a64f6467433cab72cbc2653c38b1"
-  integrity sha512-rpIuu//y5OX6jVU+a5BCn1R5RSZYWAl2Nar76iwaOdycqb6JPxediskWFMMl7stfwNJR4b7eiQvh5fB5TEQJTQ==
+babel-plugin-polyfill-corejs2@^0.4.14:
+  version "0.4.14"
+  resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.14.tgz#8101b82b769c568835611542488d463395c2ef8f"
+  integrity sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==
   dependencies:
-    "@babel/compat-data" "^7.22.6"
-    "@babel/helper-define-polyfill-provider" "^0.6.1"
+    "@babel/compat-data" "^7.27.7"
+    "@babel/helper-define-polyfill-provider" "^0.6.5"
     semver "^6.3.1"
 
-babel-plugin-polyfill-corejs3@^0.11.0:
-  version "0.11.1"
-  resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.11.1.tgz#4e4e182f1bb37c7ba62e2af81d8dd09df31344f6"
-  integrity sha512-yGCqvBT4rwMczo28xkH/noxJ6MZ4nJfkVYdoDaC/utLtWrXxv27HVrzAeSbqR8SxDsp46n0YF47EbHoixy6rXQ==
+babel-plugin-polyfill-corejs3@^0.13.0:
+  version "0.13.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz#bb7f6aeef7addff17f7602a08a6d19a128c30164"
+  integrity sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==
   dependencies:
-    "@babel/helper-define-polyfill-provider" "^0.6.3"
-    core-js-compat "^3.40.0"
+    "@babel/helper-define-polyfill-provider" "^0.6.5"
+    core-js-compat "^3.43.0"
 
-babel-plugin-polyfill-regenerator@^0.6.1:
-  version "0.6.1"
-  resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.1.tgz#4f08ef4c62c7a7f66a35ed4c0d75e30506acc6be"
-  integrity sha512-JfTApdE++cgcTWjsiCQlLyFBMbTUft9ja17saCc93lgV33h4tuCVj7tlvu//qpLwaG+3yEz7/KhahGrUMkVq9g==
+babel-plugin-polyfill-regenerator@^0.6.5:
+  version "0.6.5"
+  resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.5.tgz#32752e38ab6f6767b92650347bf26a31b16ae8c5"
+  integrity sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==
   dependencies:
-    "@babel/helper-define-polyfill-provider" "^0.6.1"
+    "@babel/helper-define-polyfill-provider" "^0.6.5"
 
 babel-plugin-transform-react-remove-prop-types@0.4.24:
   version "0.4.24"
@@ -3104,7 +3077,7 @@ braces@^3.0.1, braces@^3.0.2, braces@^3.0.3, braces@~3.0.2:
   dependencies:
     fill-range "^7.1.1"
 
-browserslist@^4.24.0, browserslist@^4.24.3:
+browserslist@^4.24.0:
   version "4.24.4"
   resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.4.tgz#c6b2865a3f08bcb860a0e827389003b9fe686e4b"
   integrity sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==
@@ -3114,6 +3087,16 @@ browserslist@^4.24.0, browserslist@^4.24.3:
     node-releases "^2.0.19"
     update-browserslist-db "^1.1.1"
 
+browserslist@^4.25.1:
+  version "4.25.1"
+  resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.25.1.tgz#ba9e8e6f298a1d86f829c9b975e07948967bb111"
+  integrity sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==
+  dependencies:
+    caniuse-lite "^1.0.30001726"
+    electron-to-chromium "^1.5.173"
+    node-releases "^2.0.19"
+    update-browserslist-db "^1.1.3"
+
 bser@2.1.1:
   version "2.1.1"
   resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05"
@@ -3254,6 +3237,11 @@ caniuse-lite@^1.0.30001688:
   resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001699.tgz#a102cf330d153bf8c92bfb5be3cd44c0a89c8c12"
   integrity sha512-b+uH5BakXZ9Do9iK+CkDmctUSEqZl+SP056vc5usa0PL+ev5OHw003rZXcnjNDv3L8P5j6rwT6C0BPKSikW08w==
 
+caniuse-lite@^1.0.30001726:
+  version "1.0.30001727"
+  resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001727.tgz#22e9706422ad37aa50556af8c10e40e2d93a8b85"
+  integrity sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q==
+
 chai@4.5.0:
   version "4.5.0"
   resolved "https://registry.yarnpkg.com/chai/-/chai-4.5.0.tgz#707e49923afdd9b13a8b0b47d33d732d13812fd8"
@@ -3576,17 +3564,17 @@ cookie@0.7.1:
   resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.7.1.tgz#2f73c42142d5d5cf71310a74fc4ae61670e5dbc9"
   integrity sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==
 
-core-js-compat@^3.40.0:
-  version "3.40.0"
-  resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.40.0.tgz#7485912a5a4a4315c2fdb2cbdc623e6881c88b38"
-  integrity sha512-0XEDpr5y5mijvw8Lbc6E5AkjrHfp7eEoPlu36SWeAbcL8fn1G1ANe8DBlo2XoNN89oVpxWwOjYIPVzR4ZvsKCQ==
+core-js-compat@^3.43.0:
+  version "3.44.0"
+  resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.44.0.tgz#62b9165b97e4cbdb8bca16b14818e67428b4a0f8"
+  integrity sha512-JepmAj2zfl6ogy34qfWtcE7nHKAJnKsQFRn++scjVS2bZFllwptzw61BZcZFYBPpUznLfAvh0LGhxKppk04ClA==
   dependencies:
-    browserslist "^4.24.3"
+    browserslist "^4.25.1"
 
-core-js@^3.43.0:
-  version "3.43.0"
-  resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.43.0.tgz#f7258b156523208167df35dea0cfd6b6ecd4ee88"
-  integrity sha512-N6wEbTTZSYOY2rYAn85CuvWWkCK6QweMn7/4Nr3w+gDBeBhk/x4EJeY6FPo4QzDoJZxVTv8U7CMvgWk6pOHHqA==
+core-js@^3.44.0:
+  version "3.44.0"
+  resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.44.0.tgz#db4fd4fa07933c1d6898c8b112a1119a9336e959"
+  integrity sha512-aFCtd4l6GvAXwVEh3XbbVqJGHDJt0OZRa+5ePGx3LLwi12WfexqQxcsohb2wgsa/92xtl19Hd66G/L+TaAxDMw==
 
 core-util-is@~1.0.0:
   version "1.0.3"
@@ -3827,7 +3815,7 @@ debug@2.6.9:
   dependencies:
     ms "2.0.0"
 
-debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4:
+debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.4.1:
   version "4.4.1"
   resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.1.tgz#e5a8bc6cbc4c6cd3e64308b0693a3d4fa550189b"
   integrity sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==
@@ -4091,6 +4079,11 @@ ee-first@1.1.1:
   resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
   integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
 
+electron-to-chromium@^1.5.173:
+  version "1.5.182"
+  resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.182.tgz#4ab73104f893938acb3ab9c28d7bec170c116b3e"
+  integrity sha512-Lv65Btwv9W4J9pyODI6EWpdnhfvrve/us5h1WspW8B2Fb0366REPtY3hX7ounk1CkV/TBjWCEvCBBbYbmV0qCA==
+
 electron-to-chromium@^1.5.73:
   version "1.5.96"
   resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.96.tgz#afa3bf1608c897a7c7e33f22d4be1596dd5a4f3e"
@@ -5438,11 +5431,6 @@ glob@^7.0.3, glob@^7.1.3, glob@^7.1.4:
     once "^1.3.0"
     path-is-absolute "^1.0.0"
 
-globals@^11.1.0:
-  version "11.12.0"
-  resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
-  integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
-
 globals@^13.19.0:
   version "13.19.0"
   resolved "https://registry.yarnpkg.com/globals/-/globals-13.19.0.tgz#7a42de8e6ad4f7242fbcca27ea5b23aca367b5c8"
@@ -6016,7 +6004,7 @@ is-callable@^1.1.4, is-callable@^1.1.5, is-callable@^1.2.4:
   resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945"
   integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==
 
-is-core-module@^2.13.0, is-core-module@^2.16.1:
+is-core-module@^2.13.0, is-core-module@^2.16.0, is-core-module@^2.16.1:
   version "2.16.1"
   resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4"
   integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==
@@ -8161,10 +8149,10 @@ query-string@^7.0.0:
     split-on-first "^1.0.0"
     strict-uri-encode "^2.0.0"
 
-query-string@^9.2.1:
-  version "9.2.1"
-  resolved "https://registry.yarnpkg.com/query-string/-/query-string-9.2.1.tgz#67bd95f6e2cb64eafecfb0504be7cc38bcd4dd11"
-  integrity sha512-3jTGGLRzlhu/1ws2zlr4Q+GVMLCQTLFOj8CMX5x44cdZG9FQE07x2mQhaNxaKVPNmIDu0mvJ/cEwtY7Pim7hqA==
+query-string@^9.2.2:
+  version "9.2.2"
+  resolved "https://registry.yarnpkg.com/query-string/-/query-string-9.2.2.tgz#a0104824edfdd2c1db2f18af71cef7abf6a3b20f"
+  integrity sha512-pDSIZJ9sFuOp6VnD+5IkakSVf+rICAuuU88Hcsr6AKL0QtxSIfVuKiVP2oahFI7tk3CRSexwV+Ya6MOoTxzg9g==
   dependencies:
     decode-uri-component "^0.4.1"
     filter-obj "^5.1.0"
@@ -8545,7 +8533,7 @@ resolve-pathname@^3.0.0:
   resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd"
   integrity sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==
 
-resolve@^1.14.2, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.22.4:
+resolve@^1.19.0, resolve@^1.20.0, resolve@^1.22.4:
   version "1.22.8"
   resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d"
   integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==
@@ -8554,6 +8542,15 @@ resolve@^1.14.2, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.22.4:
     path-parse "^1.0.7"
     supports-preserve-symlinks-flag "^1.0.0"
 
+resolve@^1.22.10:
+  version "1.22.10"
+  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.10.tgz#b663e83ffb09bbf2386944736baae803029b8b39"
+  integrity sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==
+  dependencies:
+    is-core-module "^2.16.0"
+    path-parse "^1.0.7"
+    supports-preserve-symlinks-flag "^1.0.0"
+
 resolve@^2.0.0-next.5:
   version "2.0.0-next.5"
   resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.5.tgz#6b0ec3107e671e52b68cd068ef327173b90dc03c"
@@ -9802,6 +9799,14 @@ update-browserslist-db@^1.1.1:
     escalade "^3.2.0"
     picocolors "^1.1.1"
 
+update-browserslist-db@^1.1.3:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz#348377dd245216f9e7060ff50b15a1b740b75420"
+  integrity sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==
+  dependencies:
+    escalade "^3.2.0"
+    picocolors "^1.1.1"
+
 uri-js@^4.2.2:
   version "4.4.1"
   resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"


Test patch:
diff --git a/cli/cmd/install_helm_test.go b/cli/cmd/install_helm_test.go
index c1ee4cdf2..b963460df 100644
--- a/cli/cmd/install_helm_test.go
+++ b/cli/cmd/install_helm_test.go
@@ -5,9 +5,9 @@ import (
 	"path/filepath"
 	"testing"
 
-	"github.com/linkerd/linkerd2/pkg/charts"
+	"github.com/linkerd/linkerd2/charts"
+	chartspkg "github.com/linkerd/linkerd2/pkg/charts"
 	l5dcharts "github.com/linkerd/linkerd2/pkg/charts/linkerd2"
-	"github.com/linkerd/linkerd2/pkg/charts/static"
 	"github.com/linkerd/linkerd2/pkg/k8s"
 	"github.com/linkerd/linkerd2/testutil"
 	"helm.sh/helm/v3/pkg/chart"
@@ -227,7 +227,7 @@ func chartCrds(t *testing.T) *chart.Chart {
 
 	// Load defaults from values.yaml
 	valuesFile := &loader.BufferedFile{Name: l5dcharts.HelmChartDirCrds + "/values.yaml"}
-	if err := charts.ReadFile(static.Templates, "/", valuesFile); err != nil {
+	if err := chartspkg.ReadFile(charts.Templates, "", valuesFile); err != nil {
 		t.Fatal(err)
 	}
 	defaultValues := make(map[string]interface{})