Skip to content

Commit c3e3d74

Browse files
committed
Add Link preload header for CSS to speed up stylesheet loading
Emit a Link rel=preload header for each CSS file before rendering HTML responses. This lets the browser start fetching the stylesheet as soon as it receives the response headers, before parsing the HTML.
1 parent 4eccf5c commit c3e3d74

2 files changed

Lines changed: 45 additions & 0 deletions

File tree

internal/ui/layout/render.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ func Render(w http.ResponseWriter, r *http.Request, page Page, content templ.Com
1717
page.CanonicalURL = GetBaseURL(r) + canonicalPath
1818
}
1919

20+
for _, file := range page.Manifest.CSS {
21+
w.Header().Add("Link", "<"+file+">; rel=preload; as=style")
22+
}
23+
2024
if err := Base(page, content).Render(r.Context(), w); err != nil {
2125
slog.Error("failed to render page", "error", err)
2226
}

internal/ui/layout/render_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package layout
2+
3+
import (
4+
"net/http"
5+
"net/http/httptest"
6+
"testing"
7+
8+
"github.com/a-h/templ"
9+
)
10+
11+
func TestRender_LinkPreloadHeader(t *testing.T) {
12+
manifest := &Manifest{CSS: []string{"/assets/main-abc123.css"}}
13+
14+
req := httptest.NewRequest(http.MethodGet, "/", nil)
15+
rr := httptest.NewRecorder()
16+
17+
Render(rr, req, Page{Manifest: manifest, NoIndex: true}, templ.NopComponent)
18+
19+
links := rr.Header().Values("Link")
20+
if len(links) != 1 {
21+
t.Fatalf("expected 1 Link header, got %d: %v", len(links), links)
22+
}
23+
24+
expected := "</assets/main-abc123.css>; rel=preload; as=style"
25+
if links[0] != expected {
26+
t.Errorf("Link header = %q, want %q", links[0], expected)
27+
}
28+
}
29+
30+
func TestRender_NoLinkHeaderWithoutCSS(t *testing.T) {
31+
manifest, _ := NewManifest([]byte(`{}`))
32+
33+
req := httptest.NewRequest(http.MethodGet, "/", nil)
34+
rr := httptest.NewRecorder()
35+
36+
Render(rr, req, Page{Manifest: manifest, NoIndex: true}, templ.NopComponent)
37+
38+
if links := rr.Header().Values("Link"); len(links) != 0 {
39+
t.Errorf("expected no Link headers, got %v", links)
40+
}
41+
}

0 commit comments

Comments
 (0)