~bigbes/sr-ht-ecore

9377c43a02cacb37c998bfbe2599c7afeb746692 — Eugene Blikh 9 days ago 6a2cf04
chrome: carry the service's extra hashed assets

bench and cover each grew a pair of UplotCSSHref/UplotJSHref fields beside
the embedded Page, compare a BundleHref, and all three wrote the same
justification next to it: the hash in the name is a property of the binary
rather than of a page, so a page handed its own asset URLs is one that can be
written without them and silently render nothing where the chart was. That
argument is about the chrome, so the slot belongs to the chrome.

A map rather than named fields because ecore has no business knowing that
this instance vendors uPlot; the service names its own artefacts and its
layout reads them back with index, guarded on emptiness the way StyleHref is.
3 files changed, 35 insertions(+), 0 deletions(-)

M README.md
M chrome/chrome.go
M chrome/chrome_test.go
M README.md => README.md +1 -0
@@ 76,6 76,7 @@ copies of the same code.
```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 ...

M chrome/chrome.go => chrome/chrome.go +18 -0
@@ 135,6 135,20 @@ type Page struct {

	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 @@ type Service struct {
	// 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 @@ func (s *Service) Page(r *http.Request, title, username string) Page {
		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",

M chrome/chrome_test.go => chrome/chrome_test.go +16 -0
@@ 201,6 201,22 @@ func TestLoginURLForMatchesTheNav(t *testing.T) {
		"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())