Browse Source

Fix minify

master
Jan-Lukas Else 1 month ago
parent
commit
f42b3256a4
  1. 13
      activityPub.go
  2. 20
      activityStreams.go
  3. 10
      blogroll.go
  4. 2
      editor.go
  5. 2
      feeds.go
  6. 8
      httpFs.go
  7. 19
      indieAuthServer.go
  8. 7
      micropub.go
  9. 8
      micropub_test.go
  10. 11
      nodeinfo.go
  11. 16
      opensearch.go
  12. 27
      pkgs/minify/minify.go
  13. 7
      render.go
  14. 40
      sitemap.go
  15. 6
      templateAssets.go

13
activityPub.go

@ -22,6 +22,7 @@ import (
"github.com/go-fed/httpsig"
"github.com/google/uuid"
"github.com/spf13/cast"
"go.goblog.app/app/pkgs/bufferpool"
"go.goblog.app/app/pkgs/contenttype"
)
@ -89,7 +90,10 @@ func (a *goBlog) apHandleWebfinger(w http.ResponseWriter, r *http.Request) {
return
}
apIri := a.apIri(blog)
b, _ := json.Marshal(map[string]any{
// Encode
buf := bufferpool.Get()
defer bufferpool.Put(buf)
if err := xml.NewEncoder(buf).Encode(map[string]any{
"subject": a.webfingerAccts[apIri],
"aliases": []string{
a.webfingerAccts[apIri],
@ -107,9 +111,12 @@ func (a *goBlog) apHandleWebfinger(w http.ResponseWriter, r *http.Request) {
"href": apIri,
},
},
})
}); err != nil {
a.serveError(w, r, "Encoding failed", http.StatusInternalServerError)
return
}
w.Header().Set(contentType, "application/jrd+json"+contenttype.CharsetUtf8Suffix)
_, _ = a.min.Write(w, contenttype.JSON, b)
_ = a.min.Get().Minify(contenttype.JSON, w, buf)
}
func (a *goBlog) apHandleInbox(w http.ResponseWriter, r *http.Request) {

20
activityStreams.go

@ -10,6 +10,7 @@ import (
"github.com/araddon/dateparse"
ct "github.com/elnormous/contenttype"
"go.goblog.app/app/pkgs/bufferpool"
"go.goblog.app/app/pkgs/contenttype"
)
@ -90,9 +91,14 @@ type asEndpoints struct {
}
func (a *goBlog) serveActivityStreamsPost(p *post, w http.ResponseWriter) {
b, _ := json.Marshal(a.toASNote(p))
buf := bufferpool.Get()
defer bufferpool.Put(buf)
if err := json.NewEncoder(buf).Encode(a.toASNote(p)); err != nil {
http.Error(w, "Encoding failed", http.StatusInternalServerError)
return
}
w.Header().Set(contentType, contenttype.ASUTF8)
_, _ = a.min.Write(w, contenttype.AS, b)
_ = a.min.Get().Minify(contenttype.AS, w, buf)
}
func (a *goBlog) toASNote(p *post) *asNote {
@ -195,7 +201,13 @@ func (a *goBlog) serveActivityStreams(blog string, w http.ResponseWriter, r *htt
URL: a.cfg.User.Picture,
}
}
jb, _ := json.Marshal(asBlog)
// Encode
buf := bufferpool.Get()
defer bufferpool.Put(buf)
if err := json.NewEncoder(buf).Encode(asBlog); err != nil {
a.serveError(w, r, "Encoding failed", http.StatusInternalServerError)
return
}
w.Header().Set(contentType, contenttype.ASUTF8)
_, _ = a.min.Write(w, contenttype.AS, jb)
a.min.Get().Minify(contenttype.AS, w, buf)
}

10
blogroll.go

@ -3,7 +3,6 @@ package main
import (
"bytes"
"context"
"io"
"log"
"net/http"
"sort"
@ -54,20 +53,17 @@ func (a *goBlog) serveBlogrollExport(w http.ResponseWriter, r *http.Request) {
}
opmlBuf := bufferpool.Get()
defer bufferpool.Put(opmlBuf)
mw := a.min.Writer(contenttype.XML, opmlBuf)
err = opml.Render(mw, &opml.OPML{
if err = opml.Render(opmlBuf, &opml.OPML{
Version: "2.0",
DateCreated: time.Now().UTC(),
Outlines: outlines.([]*opml.Outline),
})
_ = mw.Close()
if err != nil {
}); err != nil {
log.Printf("Failed to render OPML: %v", err)
a.serveError(w, r, "", http.StatusInternalServerError)
return
}
w.Header().Set(contentType, contenttype.XMLUTF8)
_, _ = io.Copy(w, opmlBuf)
_ = a.min.Get().Minify(contenttype.XML, w, opmlBuf)
}
func (a *goBlog) getBlogrollOutlines(blog string) ([]*opml.Outline, error) {

2
editor.go

@ -138,7 +138,7 @@ func (a *goBlog) serveEditorPost(w http.ResponseWriter, r *http.Request) {
a.serveError(w, r, err.Error(), http.StatusBadRequest)
return
}
gpx, err := io.ReadAll(a.min.Reader(contenttype.XML, file))
gpx, err := io.ReadAll(a.min.Get().Reader(contenttype.XML, file))
if err != nil {
a.serveError(w, r, err.Error(), http.StatusBadRequest)
return

2
feeds.go

@ -74,6 +74,6 @@ func (a *goBlog) generateFeed(blog string, f feedType, w http.ResponseWriter, r
_ = pipeWriter.CloseWithError(writeErr)
}()
w.Header().Set(contentType, feedMediaType+contenttype.CharsetUtf8Suffix)
minifyErr := a.min.Minify(feedMediaType, w, pipeReader)
minifyErr := a.min.Get().Minify(feedMediaType, w, pipeReader)
_ = pipeReader.CloseWithError(minifyErr)
}

8
httpFs.go

@ -18,15 +18,15 @@ func (a *goBlog) serveFs(f fs.FS, basePath string) http.HandlerFunc {
a.serve404(w, r)
return
}
var read io.Reader = file
switch path.Ext(fileName) {
case ".js":
w.Header().Set(contentType, contenttype.JSUTF8)
read = a.min.Reader(contenttype.JS, read)
_ = a.min.Get().Minify(contenttype.JS, w, file)
case ".css":
w.Header().Set(contentType, contenttype.CSSUTF8)
read = a.min.Reader(contenttype.CSS, read)
_ = a.min.Get().Minify(contenttype.CSS, w, file)
default:
_, _ = io.Copy(w, file)
}
_, _ = io.Copy(w, read)
}
}

19
indieAuthServer.go

@ -11,6 +11,7 @@ import (
"github.com/google/uuid"
"github.com/hacdias/indieauth/v2"
"go.goblog.app/app/pkgs/bufferpool"
"go.goblog.app/app/pkgs/contenttype"
)
@ -137,9 +138,14 @@ func (a *goBlog) indieAuthVerification(w http.ResponseWriter, r *http.Request, w
resp.Token = token
resp.Scope = strings.Join(data.Scopes, " ")
}
b, _ := json.Marshal(resp)
buf := bufferpool.Get()
defer bufferpool.Put(buf)
if err = json.NewEncoder(buf).Encode(resp); err != nil {
a.serveError(w, r, "Encoding failed", http.StatusInternalServerError)
return
}
w.Header().Set(contentType, contenttype.JSONUTF8)
_, _ = a.min.Write(w, contenttype.JSON, b)
_ = a.min.Get().Minify(contenttype.JSON, w, buf)
}
// Save the authorization request and return the code
@ -196,9 +202,14 @@ func (a *goBlog) indieAuthTokenVerification(w http.ResponseWriter, r *http.Reque
Me: a.getFullAddress("") + "/", // MUST contain a path component / trailing slash
ClientID: data.ClientID,
}
buf := bufferpool.Get()
defer bufferpool.Put(buf)
if err = json.NewEncoder(buf).Encode(res); err != nil {
a.serveError(w, r, "Encoding failed", http.StatusInternalServerError)
return
}
w.Header().Set(contentType, contenttype.JSONUTF8)
b, _ := json.Marshal(res)
_, _ = a.min.Write(w, contenttype.JSON, b)
_ = a.min.Get().Minify(contenttype.JSON, w, buf)
}
// Checks the database for the token and returns the indieAuthData with client and scope.

7
micropub.go

@ -73,15 +73,12 @@ func (a *goBlog) serveMicropubQuery(w http.ResponseWriter, r *http.Request) {
}
buf := bufferpool.Get()
defer bufferpool.Put(buf)
mw := a.min.Writer(contenttype.JSON, buf)
err := json.NewEncoder(mw).Encode(result)
_ = mw.Close()
if err != nil {
if err := json.NewEncoder(buf).Encode(result); err != nil {
a.serveError(w, r, "Failed to encode json", http.StatusInternalServerError)
return
}
w.Header().Set(contentType, contenttype.JSONUTF8)
_, _ = io.Copy(w, buf)
_ = a.min.Get().Minify(contenttype.JSON, w, buf)
}
func (a *goBlog) serveMicropubPost(w http.ResponseWriter, r *http.Request) {

8
micropub_test.go

@ -38,22 +38,22 @@ func Test_micropubQuery(t *testing.T) {
testCases := []testCase{
{
query: "config",
want: "{\"media-endpoint\":\"http://localhost:8080/micropub/media\"}\n",
want: "{\"media-endpoint\":\"http://localhost:8080/micropub/media\"}",
wantStatus: http.StatusOK,
},
{
query: "source&url=http://localhost:8080/test/post",
want: "{\"type\":[\"h-entry\"],\"properties\":{\"published\":[\"\"],\"updated\":[\"\"],\"post-status\":[\"published\"],\"visibility\":[\"public\"],\"category\":[\"test\",\"test2\"],\"content\":[\"---\\nblog: default\\npath: /test/post\\npriority: 0\\npublished: \\\"\\\"\\nsection: \\\"\\\"\\nstatus: published\\ntags:\\n - test\\n - test2\\nupdated: \\\"\\\"\\n---\\nTest post\"],\"url\":[\"http://localhost:8080/test/post\"],\"mp-slug\":[\"\"]}}\n",
want: "{\"type\":[\"h-entry\"],\"properties\":{\"published\":[\"\"],\"updated\":[\"\"],\"post-status\":[\"published\"],\"visibility\":[\"public\"],\"category\":[\"test\",\"test2\"],\"content\":[\"---\\nblog: default\\npath: /test/post\\npriority: 0\\npublished: \\\"\\\"\\nsection: \\\"\\\"\\nstatus: published\\ntags:\\n - test\\n - test2\\nupdated: \\\"\\\"\\n---\\nTest post\"],\"url\":[\"http://localhost:8080/test/post\"],\"mp-slug\":[\"\"]}}",
wantStatus: http.StatusOK,
},
{
query: "source",
want: "{\"items\":[{\"type\":[\"h-entry\"],\"properties\":{\"published\":[\"\"],\"updated\":[\"\"],\"post-status\":[\"published\"],\"visibility\":[\"public\"],\"category\":[\"test\",\"test2\"],\"content\":[\"---\\nblog: default\\npath: /test/post\\npriority: 0\\npublished: \\\"\\\"\\nsection: \\\"\\\"\\nstatus: published\\ntags:\\n - test\\n - test2\\nupdated: \\\"\\\"\\n---\\nTest post\"],\"url\":[\"http://localhost:8080/test/post\"],\"mp-slug\":[\"\"]}}]}\n",
want: "{\"items\":[{\"type\":[\"h-entry\"],\"properties\":{\"published\":[\"\"],\"updated\":[\"\"],\"post-status\":[\"published\"],\"visibility\":[\"public\"],\"category\":[\"test\",\"test2\"],\"content\":[\"---\\nblog: default\\npath: /test/post\\npriority: 0\\npublished: \\\"\\\"\\nsection: \\\"\\\"\\nstatus: published\\ntags:\\n - test\\n - test2\\nupdated: \\\"\\\"\\n---\\nTest post\"],\"url\":[\"http://localhost:8080/test/post\"],\"mp-slug\":[\"\"]}}]}",
wantStatus: http.StatusOK,
},
{
query: "category",
want: "{\"categories\":[\"test\",\"test2\"]}\n",
want: "{\"categories\":[\"test\",\"test2\"]}",
wantStatus: http.StatusOK,
},
{

11
nodeinfo.go

@ -25,7 +25,7 @@ func (a *goBlog) serveNodeInfoDiscover(w http.ResponseWriter, r *http.Request) {
return
}
w.Header().Set(contentType, contenttype.JSONUTF8)
mw := a.min.Writer(contenttype.JSON, w)
mw := a.min.Get().Writer(contenttype.JSON, w)
_, _ = io.Copy(mw, buf)
_ = mw.Close()
}
@ -36,7 +36,7 @@ func (a *goBlog) serveNodeInfo(w http.ResponseWriter, r *http.Request) {
})
buf := bufferpool.Get()
defer bufferpool.Put(buf)
err := json.NewEncoder(buf).Encode(map[string]any{
if err := json.NewEncoder(buf).Encode(map[string]any{
"version": "2.1",
"software": map[string]any{
"name": "goblog",
@ -54,13 +54,10 @@ func (a *goBlog) serveNodeInfo(w http.ResponseWriter, r *http.Request) {
"webmention",
},
"metadata": map[string]any{},
})
if err != nil {
}); err != nil {
a.serveError(w, r, "", http.StatusInternalServerError)
return
}
w.Header().Set(contentType, contenttype.JSONUTF8)
mw := a.min.Writer(contenttype.JSON, w)
_, _ = io.Copy(mw, buf)
_ = mw.Close()
_ = a.min.Get().Minify(contenttype.JSON, w, buf)
}

16
opensearch.go

@ -2,9 +2,9 @@ package main
import (
"encoding/xml"
"io"
"net/http"
"go.goblog.app/app/pkgs/bufferpool"
"go.goblog.app/app/pkgs/contenttype"
)
@ -35,7 +35,6 @@ func (a *goBlog) serveOpenSearch(w http.ResponseWriter, r *http.Request) {
_, b := a.getBlog(r)
title := a.renderMdTitle(b.Title)
sURL := a.getFullAddress(b.getRelativePath(defaultIfEmpty(b.Search.Path, defaultSearchPath)))
w.Header().Set(contentType, "application/opensearchdescription+xml"+contenttype.CharsetUtf8Suffix)
openSearch := &openSearchDescription{
ShortName: title,
Description: title,
@ -50,10 +49,15 @@ func (a *goBlog) serveOpenSearch(w http.ResponseWriter, r *http.Request) {
},
SearchForm: sURL,
}
mw := a.min.Writer(contenttype.XML, w)
_, _ = io.WriteString(mw, xml.Header)
_ = xml.NewEncoder(mw).Encode(openSearch)
_ = mw.Close()
buf := bufferpool.Get()
defer bufferpool.Put(buf)
_, _ = buf.WriteString(xml.Header)
if err := xml.NewEncoder(buf).Encode(openSearch); err != nil {
a.serveError(w, r, "", http.StatusInternalServerError)
return
}
w.Header().Set(contentType, "application/opensearchdescription+xml"+contenttype.CharsetUtf8Suffix)
_ = a.min.Get().Minify(contenttype.XML, w, buf)
}
func openSearchUrl(b *configBlog) string {

27
pkgs/minify/minify.go

@ -1,7 +1,6 @@
package minify
import (
"io"
"sync"
"github.com/tdewolff/minify/v2"
@ -21,12 +20,18 @@ type Minifier struct {
func (m *Minifier) init() {
m.i.Do(func() {
m.m = minify.New()
// HTML
m.m.AddFunc(contenttype.HTML, mHtml.Minify)
// CSS
m.m.AddFunc(contenttype.CSS, mCss.Minify)
m.m.AddFunc(contenttype.XML, mXml.Minify)
// JS
m.m.AddFunc(contenttype.JS, mJs.Minify)
// XML
m.m.AddFunc(contenttype.XML, mXml.Minify)
m.m.AddFunc(contenttype.RSS, mXml.Minify)
m.m.AddFunc(contenttype.ATOM, mXml.Minify)
// JSON
m.m.AddFunc(contenttype.JSON, mJson.Minify)
m.m.AddFunc(contenttype.JSONFeed, mJson.Minify)
m.m.AddFunc(contenttype.AS, mJson.Minify)
})
@ -36,21 +41,3 @@ func (m *Minifier) Get() *minify.M {
m.init()
return m.m
}
func (m *Minifier) Write(w io.Writer, mediatype string, b []byte) (int, error) {
mw := m.Writer(mediatype, w)
defer mw.Close()
return mw.Write(b)
}
func (m *Minifier) Minify(mediatype string, w io.Writer, r io.Reader) error {
return m.Get().Minify(mediatype, w, r)
}
func (m *Minifier) Writer(mediatype string, w io.Writer) io.WriteCloser {
return m.Get().Writer(mediatype, w)
}
func (m *Minifier) Reader(mediatype string, r io.Reader) io.Reader {
return m.Get().Reader(mediatype, r)
}

7
render.go

@ -41,13 +41,10 @@ func (a *goBlog) renderWithStatusCode(w http.ResponseWriter, r *http.Request, st
// Render
pipeReader, pipeWriter := io.Pipe()
go func() {
minifyWriter := a.min.Writer(contenttype.HTML, pipeWriter)
f(newHtmlBuilder(minifyWriter), data)
_ = minifyWriter.Close()
f(newHtmlBuilder(pipeWriter), data)
_ = pipeWriter.Close()
}()
_, readErr := io.Copy(w, pipeReader)
_ = pipeReader.CloseWithError(readErr)
_ = pipeReader.CloseWithError(a.min.Get().Minify(contenttype.HTML, w, pipeReader))
}
func (a *goBlog) checkRenderData(r *http.Request, data *renderData) {

40
sitemap.go

@ -3,12 +3,12 @@ package main
import (
"database/sql"
"encoding/xml"
"io"
"net/http"
"time"
"github.com/araddon/dateparse"
"github.com/snabb/sitemap"
"go.goblog.app/app/pkgs/bufferpool"
"go.goblog.app/app/pkgs/contenttype"
)
@ -20,7 +20,7 @@ const (
sitemapBlogPostsPath = "/sitemap-blog-posts.xml"
)
func (a *goBlog) serveSitemap(w http.ResponseWriter, _ *http.Request) {
func (a *goBlog) serveSitemap(w http.ResponseWriter, r *http.Request) {
// Create sitemap
sm := sitemap.NewSitemapIndex()
// Add blog sitemap indices
@ -32,7 +32,7 @@ func (a *goBlog) serveSitemap(w http.ResponseWriter, _ *http.Request) {
})
}
// Write sitemap
a.writeSitemapXML(w, sm)
a.writeSitemapXML(w, r, sm)
}
func (a *goBlog) serveSitemapBlog(w http.ResponseWriter, r *http.Request) {
@ -54,7 +54,7 @@ func (a *goBlog) serveSitemapBlog(w http.ResponseWriter, r *http.Request) {
LastMod: &now,
})
// Write sitemap
a.writeSitemapXML(w, sm)
a.writeSitemapXML(w, r, sm)
}
func (a *goBlog) serveSitemapBlogFeatures(w http.ResponseWriter, r *http.Request) {
@ -103,7 +103,7 @@ func (a *goBlog) serveSitemapBlogFeatures(w http.ResponseWriter, r *http.Request
})
}
// Write sitemap
a.writeSitemapXML(w, sm)
a.writeSitemapXML(w, r, sm)
}
func (a *goBlog) serveSitemapBlogArchives(w http.ResponseWriter, r *http.Request) {
@ -145,7 +145,7 @@ func (a *goBlog) serveSitemapBlogArchives(w http.ResponseWriter, r *http.Request
})
}
// Write sitemap
a.writeSitemapXML(w, sm)
a.writeSitemapXML(w, r, sm)
}
// Serve sitemap with all the blog's posts
@ -169,24 +169,22 @@ func (a *goBlog) serveSitemapBlogPosts(w http.ResponseWriter, r *http.Request) {
sm.Add(item)
}
// Write sitemap
a.writeSitemapXML(w, sm)
a.writeSitemapXML(w, r, sm)
}
func (a *goBlog) writeSitemapXML(w http.ResponseWriter, sm any) {
func (a *goBlog) writeSitemapXML(w http.ResponseWriter, r *http.Request, sm any) {
buf := bufferpool.Get()
defer bufferpool.Put(buf)
_, _ = buf.WriteString(xml.Header)
_, _ = buf.WriteString(`<?xml-stylesheet type="text/xsl" href="`)
_, _ = buf.WriteString(a.assetFileName("sitemap.xsl"))
_, _ = buf.WriteString(`" ?>`)
if err := xml.NewEncoder(buf).Encode(sm); err != nil {
a.serveError(w, r, "Failed to encode sitemap", http.StatusInternalServerError)
return
}
w.Header().Set(contentType, contenttype.XMLUTF8)
pipeReader, pipeWriter := io.Pipe()
go func() {
mw := a.min.Writer(contenttype.XML, pipeWriter)
_, _ = io.WriteString(mw, xml.Header)
_, _ = io.WriteString(mw, `<?xml-stylesheet type="text/xsl" href="`)
_, _ = io.WriteString(mw, a.assetFileName("sitemap.xsl"))
_, _ = io.WriteString(mw, `" ?>`)
writeErr := xml.NewEncoder(mw).Encode(sm)
_ = mw.Close()
_ = pipeWriter.CloseWithError(writeErr)
}()
_, copyErr := io.Copy(w, pipeReader)
_ = pipeReader.CloseWithError(copyErr)
_ = a.min.Get().Minify(contenttype.XML, w, buf)
}
const sitemapDatePathsSql = `

6
templateAssets.go

@ -53,11 +53,11 @@ func (a *goBlog) compileAsset(name string, read io.Reader) error {
ext := path.Ext(name)
switch ext {
case ".js":
read = a.min.Reader(contenttype.JS, read)
read = a.min.Get().Reader(contenttype.JS, read)
case ".css":
read = a.min.Reader(contenttype.CSS, read)
read = a.min.Get().Reader(contenttype.CSS, read)
case ".xml", ".xsl":
read = a.min.Reader(contenttype.XML, read)
read = a.min.Get().Reader(contenttype.XML, read)
}
// Read file
hash := sha256.New()

Loading…
Cancel
Save