mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-21 20:46:30 -05:00
Fix /static performance regression from Hugo 0.103.0
In `v0.103.0` we added support for `resources.PostProcess` for all file types, not just HTML. We had benchmarks that said we were fine in that department, but those did not consider the static file syncing. This fixes that by: * Making sure that the /static syncer always gets its own file system without any checks for the post process token. * For dynamic files (e.g. rendered HTML files) we add an additional check to make sure that we skip binary files (e.g. images) Fixes #10328
This commit is contained in:
parent
d8aba18e05
commit
29ccb36069
6 changed files with 32 additions and 23 deletions
|
@ -653,10 +653,7 @@ func (c *commandeer) copyStaticTo(sourceFs *filesystems.SourceFilesystem) (uint6
|
||||||
syncer.NoChmod = c.Cfg.GetBool("noChmod")
|
syncer.NoChmod = c.Cfg.GetBool("noChmod")
|
||||||
syncer.ChmodFilter = chmodFilter
|
syncer.ChmodFilter = chmodFilter
|
||||||
syncer.SrcFs = fs
|
syncer.SrcFs = fs
|
||||||
syncer.DestFs = c.Fs.PublishDir
|
|
||||||
if c.renderStaticToDisk {
|
|
||||||
syncer.DestFs = c.Fs.PublishDirStatic
|
syncer.DestFs = c.Fs.PublishDirStatic
|
||||||
}
|
|
||||||
// Now that we are using a unionFs for the static directories
|
// Now that we are using a unionFs for the static directories
|
||||||
// We can effectively clean the publishDir on initial sync
|
// We can effectively clean the publishDir on initial sync
|
||||||
syncer.Delete = c.Cfg.GetBool("cleanDestinationDir")
|
syncer.Delete = c.Cfg.GetBool("cleanDestinationDir")
|
||||||
|
|
22
deps/deps.go
vendored
22
deps/deps.go
vendored
|
@ -2,6 +2,8 @@ package deps
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
@ -246,16 +248,30 @@ func New(cfg DepsCfg) (*Deps, error) {
|
||||||
execHelper := hexec.New(securityConfig)
|
execHelper := hexec.New(securityConfig)
|
||||||
|
|
||||||
var filenameHasPostProcessPrefixMu sync.Mutex
|
var filenameHasPostProcessPrefixMu sync.Mutex
|
||||||
cb := func(name string, match bool) {
|
hashBytesReceiverFunc := func(name string, match bool) {
|
||||||
if !match {
|
if !match {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
filenameHasPostProcessPrefixMu.Lock()
|
filenameHasPostProcessPrefixMu.Lock()
|
||||||
d.FilenameHasPostProcessPrefix = append(d.FilenameHasPostProcessPrefix, name)
|
d.FilenameHasPostProcessPrefix = append(d.FilenameHasPostProcessPrefix, name)
|
||||||
filenameHasPostProcessPrefixMu.Unlock()
|
filenameHasPostProcessPrefixMu.Unlock()
|
||||||
|
|
||||||
}
|
}
|
||||||
fs.PublishDir = hugofs.NewHasBytesReceiver(fs.PublishDir, cb, []byte(postpub.PostProcessPrefix))
|
|
||||||
|
// Skip binary files.
|
||||||
|
hashBytesSHouldCheck := func(name string) bool {
|
||||||
|
ext := strings.TrimPrefix(filepath.Ext(name), ".")
|
||||||
|
mime, _, found := cfg.MediaTypes.GetBySuffix(ext)
|
||||||
|
if !found {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
switch mime.MainType {
|
||||||
|
case "text", "application":
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fs.PublishDir = hugofs.NewHasBytesReceiver(fs.PublishDir, hashBytesSHouldCheck, hashBytesReceiverFunc, []byte(postpub.PostProcessPrefix))
|
||||||
|
|
||||||
ps, err := helpers.NewPathSpec(fs, cfg.Language, logger)
|
ps, err := helpers.NewPathSpec(fs, cfg.Language, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -40,8 +40,7 @@ type Fs struct {
|
||||||
// It's mounted inside publishDir (default /public).
|
// It's mounted inside publishDir (default /public).
|
||||||
PublishDir afero.Fs
|
PublishDir afero.Fs
|
||||||
|
|
||||||
// PublishDirStatic is the file system used for static files when --renderStaticToDisk is set.
|
// PublishDirStatic is the file system used for static files.
|
||||||
// When this is set, PublishDir is set to write to memory.
|
|
||||||
PublishDirStatic afero.Fs
|
PublishDirStatic afero.Fs
|
||||||
|
|
||||||
// PublishDirServer is the file system used for serving the public directory with Hugo's development server.
|
// PublishDirServer is the file system used for serving the public directory with Hugo's development server.
|
||||||
|
@ -142,7 +141,6 @@ func isWrite(flag int) bool {
|
||||||
// MakeReadableAndRemoveAllModulePkgDir makes any subdir in dir readable and then
|
// MakeReadableAndRemoveAllModulePkgDir makes any subdir in dir readable and then
|
||||||
// removes the root.
|
// removes the root.
|
||||||
// TODO(bep) move this to a more suitable place.
|
// TODO(bep) move this to a more suitable place.
|
||||||
//
|
|
||||||
func MakeReadableAndRemoveAllModulePkgDir(fs afero.Fs, dir string) (int, error) {
|
func MakeReadableAndRemoveAllModulePkgDir(fs afero.Fs, dir string) (int, error) {
|
||||||
// Safe guard
|
// Safe guard
|
||||||
if !strings.Contains(dir, "pkg") {
|
if !strings.Contains(dir, "pkg") {
|
||||||
|
|
|
@ -27,12 +27,13 @@ var (
|
||||||
|
|
||||||
type hasBytesFs struct {
|
type hasBytesFs struct {
|
||||||
afero.Fs
|
afero.Fs
|
||||||
|
shouldCheck func(name string) bool
|
||||||
hasBytesCallback func(name string, match bool)
|
hasBytesCallback func(name string, match bool)
|
||||||
pattern []byte
|
pattern []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHasBytesReceiver(delegate afero.Fs, hasBytesCallback func(name string, match bool), pattern []byte) afero.Fs {
|
func NewHasBytesReceiver(delegate afero.Fs, shouldCheck func(name string) bool, hasBytesCallback func(name string, match bool), pattern []byte) afero.Fs {
|
||||||
return &hasBytesFs{Fs: delegate, hasBytesCallback: hasBytesCallback, pattern: pattern}
|
return &hasBytesFs{Fs: delegate, shouldCheck: shouldCheck, hasBytesCallback: hasBytesCallback, pattern: pattern}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *hasBytesFs) UnwrapFilesystem() afero.Fs {
|
func (fs *hasBytesFs) UnwrapFilesystem() afero.Fs {
|
||||||
|
@ -56,6 +57,9 @@ func (fs *hasBytesFs) OpenFile(name string, flag int, perm os.FileMode) (afero.F
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *hasBytesFs) wrapFile(f afero.File) afero.File {
|
func (fs *hasBytesFs) wrapFile(f afero.File) afero.File {
|
||||||
|
if !fs.shouldCheck(f.Name()) {
|
||||||
|
return f
|
||||||
|
}
|
||||||
return &hasBytesFile{
|
return &hasBytesFile{
|
||||||
File: f,
|
File: f,
|
||||||
hbw: &hugio.HasBytesWriter{
|
hbw: &hugio.HasBytesWriter{
|
||||||
|
|
|
@ -67,7 +67,7 @@ type BaseFs struct {
|
||||||
// This usually maps to /my-project/public.
|
// This usually maps to /my-project/public.
|
||||||
PublishFs afero.Fs
|
PublishFs afero.Fs
|
||||||
|
|
||||||
// The filesystem used for renderStaticToDisk.
|
// The filesystem used for static files.
|
||||||
PublishFsStatic afero.Fs
|
PublishFsStatic afero.Fs
|
||||||
|
|
||||||
// A read-only filesystem starting from the project workDir.
|
// A read-only filesystem starting from the project workDir.
|
||||||
|
|
|
@ -35,7 +35,6 @@ func newPagesProcessor(h *HugoSites, sp *source.SourceSpec) *pagesProcessor {
|
||||||
m: s.pageMap,
|
m: s.pageMap,
|
||||||
errorSender: s.h,
|
errorSender: s.h,
|
||||||
itemChan: make(chan interface{}, config.GetNumWorkerMultiplier()*2),
|
itemChan: make(chan interface{}, config.GetNumWorkerMultiplier()*2),
|
||||||
renderStaticToDisk: h.Cfg.GetBool("renderStaticToDisk"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &pagesProcessor{
|
return &pagesProcessor{
|
||||||
|
@ -118,8 +117,6 @@ type sitePagesProcessor struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
itemChan chan any
|
itemChan chan any
|
||||||
itemGroup *errgroup.Group
|
itemGroup *errgroup.Group
|
||||||
|
|
||||||
renderStaticToDisk bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *sitePagesProcessor) Process(item any) error {
|
func (p *sitePagesProcessor) Process(item any) error {
|
||||||
|
@ -164,10 +161,7 @@ func (p *sitePagesProcessor) copyFile(fim hugofs.FileMetaInfo) error {
|
||||||
|
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
fs := s.PublishFs
|
fs := s.PublishFsStatic
|
||||||
if p.renderStaticToDisk {
|
|
||||||
fs = s.PublishFsStatic
|
|
||||||
}
|
|
||||||
|
|
||||||
return s.publish(&s.PathSpec.ProcessingStats.Files, target, f, fs)
|
return s.publish(&s.PathSpec.ProcessingStats.Files, target, f, fs)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue