diff --git a/README.md b/README.md index 9a7e58a4a6affea1a3d9ade73227b4ae46555a22..63818376cf5085370d803206ebdf951e17d42b9f 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,7 @@ ```go svc := chrome.NewService(conf, "compare.sr.ht") svc.StyleHref = cssHref // after discovering the hashed stylesheet +svc.Assets = map[string]string{"bundle.js": bundleHref} // any further artefacts t := chrome.MustAttach(template.New("layout").Funcs(chrome.Funcs())) // ... parse the service's own templates into t ... diff --git a/chrome/chrome.go b/chrome/chrome.go index 7e6d1c6e5787c147ce70face07ac5b509dbaa55d..b02c8298c195e9c00009fb4f5b4fc77fc5e2ca60 100644 --- a/chrome/chrome.go +++ b/chrome/chrome.go @@ -135,6 +135,20 @@ HubOrigin string StyleHref string // "" when the binary was built without a stylesheet + // Assets are the hashed hrefs of the extra build artefacts a layout links + // beyond the stylesheet — a vendored chart library, a front-end bundle — + // keyed by names the service picks. Read as {{index .Assets "uplot.js"}}, + // guarded on emptiness exactly like StyleHref. + // + // They belong to the chrome for the reason StyleHref does: the hash in the + // name is a property of this binary, not of any page. A page that had to + // be handed its own asset URLs is a page that can be written without them + // and silently render nothing where the chart was. + // + // The map is the Service's, shared by every Page it builds: written once + // at startup, read-only afterwards. A handler must not write to it. + Assets map[string]string + Environment string // uppercased; banner text ShowBanner bool // true outside production @@ -175,6 +189,9 @@ StyleHref string // ExtraNav holds service-specific switcher entries (e.g. a /tokens link), // rendered after the shared network entries, for authenticated viewers. ExtraNav []NavItem + // Assets holds the extra hashed asset hrefs every Page carries; see + // Page.Assets. Populate it at startup, next to StyleHref. + Assets map[string]string siteName string environment string @@ -250,6 +267,7 @@ MetaOrigin: s.metaOrigin, SelfOrigin: s.selfOrigin, HubOrigin: s.hubOrigin, StyleHref: s.StyleHref, + Assets: s.Assets, Environment: strings.ToUpper(s.environment), ShowBanner: s.environment != "" && s.environment != "production", ContainerClass: "container", diff --git a/chrome/chrome_test.go b/chrome/chrome_test.go index 10190ea7eea8a5ad9ddbb87c3d9800b952e58e24..ab5f5f7911302607cbbd9421ba529438f369ae54 100644 --- a/chrome/chrome_test.go +++ b/chrome/chrome_test.go @@ -201,6 +201,22 @@ assert.Equal(t, "https://meta.example/login?return_to="+ "https%3A%2F%2Fcompare.example%2F~alice%2Fdemo%3Fa%3D1", svc.LoginURLFor(r)) } +// TestPageCarriesTheServiceAssets pins the slot three services grew their own +// copy of: the layout reads an extra hashed artefact off the chrome, not off +// the page's payload. +func TestPageCarriesTheServiceAssets(t *testing.T) { + svc := NewService(testConf(), "bench.sr.ht") + svc.Assets = map[string]string{"uplot.js": "/static/uplot.0badc0de.js"} + p := svc.Page(httptest.NewRequest("GET", "/", nil), "t", "alice") + + assert.Equal(t, "/static/uplot.0badc0de.js", p.Assets["uplot.js"]) + // A name the service never registered reads as empty, which is what the + // layout's {{if}} guard is written against. + assert.Empty(t, p.Assets["missing.js"]) + assert.Empty(t, NewService(testConf(), "bench.sr.ht"). + Page(httptest.NewRequest("GET", "/", nil), "t", "alice").Assets) +} + func TestServiceAccessors(t *testing.T) { svc := NewService(testConf(), "compare.sr.ht") assert.Equal(t, "https://compare.example", svc.SelfOrigin())