Skip to content

Commit 3f753fa

Browse files
david-itsDavid Itsmaxence-charriere
authored
Avoid using text/template as it disables DCE and increases binary size (#1041)
* Avoid using text/template as it disables DCE and increases binary size See issue #1040. text/template package is using some of reflect functions which lead to DCE (dead code elimination) disabling in Go. It significantly increases WASM binary. After removing text/template one gets ~16MB docs/web/app.wasm file instead of current 22MB. * no need to use templates for manifest.webmanifest templates are totally useless and harmful for generating manifest.webmanifest: 1. problem with DCE disabling when using text/template package 2. generating JSON from structs allows to customize content much easier, e.g. detect icon sizes and report them properly, rather than static. --------- Co-authored-by: David Its <david@david-prof.com> Co-authored-by: Maxence Charriere <charriere@outlook.com>
1 parent 511564a commit 3f753fa

7 files changed

Lines changed: 102 additions & 133 deletions

File tree

pkg/app/gen/manifest.webmanifest

Lines changed: 0 additions & 33 deletions
This file was deleted.

pkg/app/gen/scripts.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,6 @@ func main() {
4747
Var: "appJS",
4848
Filename: "gen/app.js",
4949
},
50-
{
51-
Var: "manifestJSON",
52-
Filename: "gen/manifest.webmanifest",
53-
},
5450
{
5551
Var: "appCSS",
5652
Filename: "gen/app.css",

pkg/app/http.go

Lines changed: 77 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import (
1414
"strconv"
1515
"strings"
1616
"sync"
17-
"text/template"
1817
"time"
1918

2019
"github.com/maxence-charriere/go-app/v10/pkg/errors"
@@ -310,27 +309,14 @@ func (h *Handler) makeAppJS() []byte {
310309
}
311310
}
312311

313-
var b bytes.Buffer
314-
if err := template.
315-
Must(template.New("app.js").Parse(appJS)).
316-
Execute(&b, struct {
317-
Env string
318-
LoadingLabel string
319-
Wasm string
320-
WasmContentLength string
321-
WasmContentLengthHeader string
322-
WorkerJS string
323-
}{
324-
Env: jsonString(h.Env),
325-
LoadingLabel: h.LoadingLabel,
326-
Wasm: h.Resources.Resolve("/web/app.wasm"),
327-
WasmContentLength: h.WasmContentLength,
328-
WasmContentLengthHeader: h.WasmContentLengthHeader,
329-
WorkerJS: h.Resources.Resolve("/app-worker.js"),
330-
}); err != nil {
331-
panic(errors.New("initializing app.js failed").Wrap(err))
332-
}
333-
return b.Bytes()
312+
s := appJS
313+
s = strings.ReplaceAll(s, "{{.Env}}", jsonString(h.Env))
314+
s = strings.ReplaceAll(s, "{{.LoadingLabel}}", h.LoadingLabel)
315+
s = strings.ReplaceAll(s, "{{.Wasm}}", h.Resources.Resolve("/web/app.wasm"))
316+
s = strings.ReplaceAll(s, "{{.WasmContentLength}}", h.WasmContentLength)
317+
s = strings.ReplaceAll(s, "{{.WasmContentLengthHeader}}", h.WasmContentLengthHeader)
318+
s = strings.ReplaceAll(s, "{{.WorkerJS}}", h.Resources.Resolve("/app-worker.js"))
319+
return []byte(s)
334320
}
335321

336322
func (h *Handler) makeAppWorkerJS() []byte {
@@ -364,53 +350,78 @@ func (h *Handler) makeAppWorkerJS() []byte {
364350
return strings.Compare(resourcesTocache[a], resourcesTocache[b]) > 0
365351
})
366352

367-
var b bytes.Buffer
368-
if err := template.
369-
Must(template.New("app-worker.js").Parse(h.ServiceWorkerTemplate)).
370-
Execute(&b, struct {
371-
Version string
372-
ResourcesToCache string
373-
}{
374-
Version: h.Version,
375-
ResourcesToCache: jsonString(resourcesTocache),
376-
}); err != nil {
377-
panic(errors.New("initializing app-worker.js failed").Wrap(err))
378-
}
379-
return b.Bytes()
353+
s := h.ServiceWorkerTemplate
354+
s = strings.ReplaceAll(s, "{{.Version}}", h.Version)
355+
s = strings.ReplaceAll(s, "{{.ResourcesToCache}}", jsonString(resourcesTocache))
356+
return []byte(s)
380357
}
381358

382359
func (h *Handler) makeManifestJSON() []byte {
383-
var b bytes.Buffer
384-
if err := template.
385-
Must(template.New("manifest.webmanifest").Parse(manifestJSON)).
386-
Execute(&b, struct {
387-
ShortName string
388-
Name string
389-
Description string
390-
DefaultIcon string
391-
LargeIcon string
392-
SVGIcon string
393-
MaskableIcon string
394-
BackgroundColor string
395-
ThemeColor string
396-
Scope string
397-
StartURL string
398-
}{
399-
ShortName: h.ShortName,
400-
Name: h.Name,
401-
Description: h.Description,
402-
DefaultIcon: h.Resources.Resolve(h.Icon.Default),
403-
LargeIcon: h.Resources.Resolve(h.Icon.Large),
404-
SVGIcon: h.Resources.Resolve(h.Icon.SVG),
405-
MaskableIcon: h.Resources.Resolve(h.Icon.Maskable),
406-
BackgroundColor: h.BackgroundColor,
407-
ThemeColor: h.ThemeColor,
408-
Scope: "/",
409-
StartURL: h.Resources.Resolve("/"),
410-
}); err != nil {
411-
panic(errors.New("initializing manifest.webmanifest failed").Wrap(err))
412-
}
413-
return b.Bytes()
360+
type ManifestIcon struct {
361+
Src string `json:"src"`
362+
Type string `json:"type"`
363+
Purpose string `json:"purpose"`
364+
Sizes string `json:"sizes"`
365+
}
366+
type Manifest struct {
367+
ShortName string `json:"short_name"`
368+
Name string `json:"name"`
369+
Description string `json:"description"`
370+
Scope string `json:"scope"`
371+
StartURL string `json:"start_url"`
372+
BackgroundColor string `json:"background_color"`
373+
ThemeColor string `json:"theme_color"`
374+
Display string `json:"display"`
375+
Icons []ManifestIcon `json:"icons"`
376+
}
377+
378+
m := Manifest{
379+
ShortName: h.ShortName,
380+
Name: h.Name,
381+
Description: h.Description,
382+
Scope: "/",
383+
StartURL: h.Resources.Resolve("/"),
384+
BackgroundColor: h.BackgroundColor,
385+
ThemeColor: h.ThemeColor,
386+
Display: "standalone",
387+
}
388+
389+
if i := h.Resources.Resolve(h.Icon.Maskable); i != "" {
390+
m.Icons = append(m.Icons, ManifestIcon{
391+
Src: i,
392+
Type: "image/png",
393+
Purpose: "maskable",
394+
Sizes: "512x512",
395+
})
396+
}
397+
if i := h.Resources.Resolve(h.Icon.SVG); i != "" {
398+
m.Icons = append(m.Icons, ManifestIcon{
399+
Src: i,
400+
Type: "image/svg+xml",
401+
Sizes: "any",
402+
})
403+
}
404+
if i := h.Resources.Resolve(h.Icon.Large); i != "" {
405+
m.Icons = append(m.Icons, ManifestIcon{
406+
Src: i,
407+
Type: "image/png",
408+
Sizes: "512x512",
409+
})
410+
}
411+
if i := h.Resources.Resolve(h.Icon.Default); i != "" {
412+
m.Icons = append(m.Icons, ManifestIcon{
413+
Src: i,
414+
Type: "image/png",
415+
Sizes: "192x192",
416+
})
417+
}
418+
419+
res, err := json.Marshal(m)
420+
if err != nil {
421+
panic("not possible")
422+
}
423+
424+
return res
414425
}
415426

416427
func (h *Handler) initProxyResources() {

pkg/app/http_test.go

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -354,13 +354,13 @@ func TestHandlerServeManifestJSONWithLocalDir(t *testing.T) {
354354
body := w.Body.String()
355355
require.Equal(t, http.StatusOK, w.Code)
356356
require.Equal(t, "application/manifest+json", w.Header().Get("Content-Type"))
357-
require.Contains(t, body, `"short_name": "foo"`)
358-
require.Contains(t, body, `"name": "foobar"`)
359-
require.Contains(t, body, `"src": "https://raw.githubusercontent.com/maxence-charriere/go-app/master/docs/web/icon.png"`)
360-
require.Contains(t, body, `"background_color": "#0000f0"`)
361-
require.Contains(t, body, `"theme_color": "#0000ff"`)
362-
require.Contains(t, body, `"scope": "/"`)
363-
require.Contains(t, body, `"start_url": "/"`)
357+
require.Contains(t, body, `"short_name":"foo"`)
358+
require.Contains(t, body, `"name":"foobar"`)
359+
require.Contains(t, body, `"src":"https://raw.githubusercontent.com/maxence-charriere/go-app/master/docs/web/icon.png"`)
360+
require.Contains(t, body, `"background_color":"#0000f0"`)
361+
require.Contains(t, body, `"theme_color":"#0000ff"`)
362+
require.Contains(t, body, `"scope":"/"`)
363+
require.Contains(t, body, `"start_url":"/"`)
364364
}
365365

366366
func TestHandlerServeManifestJSONWithRemoteBucket(t *testing.T) {
@@ -380,13 +380,13 @@ func TestHandlerServeManifestJSONWithRemoteBucket(t *testing.T) {
380380
body := w.Body.String()
381381
require.Equal(t, http.StatusOK, w.Code)
382382
require.Equal(t, "application/manifest+json", w.Header().Get("Content-Type"))
383-
require.Contains(t, body, `"short_name": "foo"`)
384-
require.Contains(t, body, `"name": "foobar"`)
385-
require.Contains(t, body, `"src": "https://raw.githubusercontent.com/maxence-charriere/go-app/master/docs/web/icon.png"`)
386-
require.Contains(t, body, `"background_color": "#0000f0"`)
387-
require.Contains(t, body, `"theme_color": "#0000ff"`)
388-
require.Contains(t, body, `"scope": "/"`)
389-
require.Contains(t, body, `"start_url": "/"`)
383+
require.Contains(t, body, `"short_name":"foo"`)
384+
require.Contains(t, body, `"name":"foobar"`)
385+
require.Contains(t, body, `"src":"https://raw.githubusercontent.com/maxence-charriere/go-app/master/docs/web/icon.png"`)
386+
require.Contains(t, body, `"background_color":"#0000f0"`)
387+
require.Contains(t, body, `"theme_color":"#0000ff"`)
388+
require.Contains(t, body, `"scope":"/"`)
389+
require.Contains(t, body, `"start_url":"/"`)
390390
}
391391

392392
func TestHandlerServeManifestJSONWithGitHubPages(t *testing.T) {
@@ -406,13 +406,13 @@ func TestHandlerServeManifestJSONWithGitHubPages(t *testing.T) {
406406
body := w.Body.String()
407407
require.Equal(t, http.StatusOK, w.Code)
408408
require.Equal(t, "application/manifest+json", w.Header().Get("Content-Type"))
409-
require.Contains(t, body, `"short_name": "foo"`)
410-
require.Contains(t, body, `"name": "foobar"`)
411-
require.Contains(t, body, `"src": "https://raw.githubusercontent.com/maxence-charriere/go-app/master/docs/web/icon.png"`)
412-
require.Contains(t, body, `"background_color": "#0000f0"`)
413-
require.Contains(t, body, `"theme_color": "#0000ff"`)
414-
require.Contains(t, body, `"scope": "/"`)
415-
require.Contains(t, body, `"start_url": "/go-app"`)
409+
require.Contains(t, body, `"short_name":"foo"`)
410+
require.Contains(t, body, `"name":"foobar"`)
411+
require.Contains(t, body, `"src":"https://raw.githubusercontent.com/maxence-charriere/go-app/master/docs/web/icon.png"`)
412+
require.Contains(t, body, `"background_color":"#0000f0"`)
413+
require.Contains(t, body, `"theme_color":"#0000ff"`)
414+
require.Contains(t, body, `"scope":"/"`)
415+
require.Contains(t, body, `"start_url":"/go-app"`)
416416
}
417417

418418
func TestHandlerServeAppCSS(t *testing.T) {

0 commit comments

Comments
 (0)