Update dynamic manifest implementation
This commit is contained in:
+31
-27
@@ -18,15 +18,19 @@ var (
|
||||
pageTemplate = mustParseTemplate("page.html", "document.html")
|
||||
pageContentTemplate = mustParseTemplate("page-content.html")
|
||||
pageThemeStyleTemplate = mustParseTemplate("theme-style.gotmpl")
|
||||
manifestTemplate = mustParseTemplate("manifest.json")
|
||||
)
|
||||
|
||||
const STATIC_ASSETS_CACHE_DURATION = 24 * time.Hour
|
||||
|
||||
type application struct {
|
||||
Version string
|
||||
CreatedAt time.Time
|
||||
Config config
|
||||
ParsedThemeStyle template.HTML
|
||||
|
||||
parsedManifest []byte
|
||||
|
||||
slugToPage map[string]*page
|
||||
widgetByID map[uint64]widget
|
||||
}
|
||||
@@ -34,6 +38,7 @@ type application struct {
|
||||
func newApplication(config *config) (*application, error) {
|
||||
app := &application{
|
||||
Version: buildVersion,
|
||||
CreatedAt: time.Now(),
|
||||
Config: *config,
|
||||
slugToPage: make(map[string]*page),
|
||||
widgetByID: make(map[uint64]widget),
|
||||
@@ -42,7 +47,7 @@ func newApplication(config *config) (*application, error) {
|
||||
app.slugToPage[""] = &config.Pages[0]
|
||||
|
||||
providers := &widgetProviders{
|
||||
assetResolver: app.AssetPath,
|
||||
assetResolver: app.StaticAssetPath,
|
||||
}
|
||||
|
||||
var err error
|
||||
@@ -89,9 +94,10 @@ func newApplication(config *config) (*application, error) {
|
||||
|
||||
config.Server.BaseURL = strings.TrimRight(config.Server.BaseURL, "/")
|
||||
config.Theme.CustomCSSFile = app.transformUserDefinedAssetPath(config.Theme.CustomCSSFile)
|
||||
config.Branding.LogoURL = app.transformUserDefinedAssetPath(config.Branding.LogoURL)
|
||||
|
||||
if config.Branding.FaviconURL == "" {
|
||||
config.Branding.FaviconURL = app.AssetPath("favicon.png")
|
||||
config.Branding.FaviconURL = app.StaticAssetPath("favicon.png")
|
||||
} else {
|
||||
config.Branding.FaviconURL = app.transformUserDefinedAssetPath(config.Branding.FaviconURL)
|
||||
}
|
||||
@@ -101,14 +107,22 @@ func newApplication(config *config) (*application, error) {
|
||||
}
|
||||
|
||||
if config.Branding.AppIconURL == "" {
|
||||
config.Branding.AppIconURL = app.AssetPath("app-icon.png")
|
||||
config.Branding.AppIconURL = app.StaticAssetPath("app-icon.png")
|
||||
}
|
||||
|
||||
if config.Branding.AppBgColor == "" {
|
||||
config.Branding.AppBgColor = "#151519"
|
||||
if config.Branding.AppBackgroundColor == "" {
|
||||
config.Branding.AppBackgroundColor = ternary(
|
||||
config.Theme.BackgroundColor != nil,
|
||||
config.Theme.BackgroundColor.String(),
|
||||
"hsl(240, 8%, 9%)",
|
||||
)
|
||||
}
|
||||
|
||||
config.Branding.LogoURL = app.transformUserDefinedAssetPath(config.Branding.LogoURL)
|
||||
var manifestWriter bytes.Buffer
|
||||
if err := manifestTemplate.Execute(&manifestWriter, pageTemplateData{App: app}); err != nil {
|
||||
return nil, fmt.Errorf("parsing manifest.json: %v", err)
|
||||
}
|
||||
app.parsedManifest = manifestWriter.Bytes()
|
||||
|
||||
return app, nil
|
||||
}
|
||||
@@ -232,10 +246,15 @@ func (a *application) handleWidgetRequest(w http.ResponseWriter, r *http.Request
|
||||
widget.handleRequest(w, r)
|
||||
}
|
||||
|
||||
func (a *application) AssetPath(asset string) string {
|
||||
func (a *application) StaticAssetPath(asset string) string {
|
||||
return a.Config.Server.BaseURL + "/static/" + staticFSHash + "/" + asset
|
||||
}
|
||||
|
||||
func (a *application) VersionedAssetPath(asset string) string {
|
||||
return a.Config.Server.BaseURL + asset +
|
||||
"?v=" + strconv.FormatInt(a.CreatedAt.Unix(), 10)
|
||||
}
|
||||
|
||||
func (a *application) server() (func() error, func() error) {
|
||||
// TODO: add gzip support, static files must have their gzipped contents cached
|
||||
// TODO: add HTTPS support
|
||||
@@ -258,35 +277,21 @@ func (a *application) server() (func() error, func() error) {
|
||||
),
|
||||
)
|
||||
|
||||
cssBundleCacheControlValue := fmt.Sprintf(
|
||||
assetCacheControlValue := fmt.Sprintf(
|
||||
"public, max-age=%d",
|
||||
int(STATIC_ASSETS_CACHE_DURATION.Seconds()),
|
||||
)
|
||||
|
||||
mux.HandleFunc(fmt.Sprintf("GET /static/%s/css/bundle.css", staticFSHash), func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Add("Cache-Control", cssBundleCacheControlValue)
|
||||
w.Header().Add("Cache-Control", assetCacheControlValue)
|
||||
w.Header().Add("Content-Type", "text/css; charset=utf-8")
|
||||
w.Write(bundledCSSContents)
|
||||
})
|
||||
|
||||
mux.HandleFunc(fmt.Sprintf("GET /static/%s/manifest.json", staticFSHash), func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Add("Cache-Control", cssBundleCacheControlValue)
|
||||
mux.HandleFunc("GET /manifest.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Add("Cache-Control", assetCacheControlValue)
|
||||
w.Header().Add("Content-Type", "application/json")
|
||||
|
||||
template, err := template.New("manifest.json").
|
||||
Funcs(globalTemplateFunctions).
|
||||
ParseFS(templateFS, "manifest.json")
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(fmt.Sprintf("Error parsing manifest.json template: %v", err)))
|
||||
return
|
||||
}
|
||||
|
||||
if err := template.Execute(w, pageTemplateData{App: a}); err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(fmt.Sprintf("Error executing manifest.json template: %v", err)))
|
||||
return
|
||||
}
|
||||
w.Write(a.parsedManifest)
|
||||
})
|
||||
|
||||
var absAssetsPath string
|
||||
@@ -302,7 +307,6 @@ func (a *application) server() (func() error, func() error) {
|
||||
}
|
||||
|
||||
start := func() error {
|
||||
a.Config.Server.StartedAt = time.Now()
|
||||
log.Printf("Starting server on %s:%d (base-url: \"%s\", assets-path: \"%s\")\n",
|
||||
a.Config.Server.Host,
|
||||
a.Config.Server.Port,
|
||||
|
||||
Reference in New Issue
Block a user