Node's ESM resolver does not consult NODE_PATH (unlike CJS require), so
an ESM postcss.config.js shipped by a Hugo theme fails when loaded from
the module cache: bare imports like `import x from "postcss-import"`
have no node_modules to walk up to.
Install a synchronous resolver hook (module.registerHooks) via
--import=data:... on every Node invocation. On ERR_MODULE_NOT_FOUND for
a bare specifier it resolves the package from each NODE_PATH entry via
createRequire().resolve(). No-op for relative, absolute, URL-scheme and
non-MODULE_NOT_FOUND failures. Synchronous hooks run on the main thread,
so no --allow-worker is needed under the Node permission model.
Fixes#13987
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Smartcrop can return a crop rectangle that is smaller than the requested dimensions after prescaling and rounding. Expand that rectangle within the source image bounds before applying Hugo's crop/fill pipeline, so smart crops keep the requested size without stretching the image.
Bump the smart crop cache version for crop/fill only.
Fixes#13688
Co-Authored-By: Joe Mooring <joe.mooring@veriphor.com>
A server allowed by security.http.urls could redirect resources.GetRemote
to a host that is not. Re-run the check on each hop via CheckRedirect.
Fixes#14871
When CSS imports assets via the file loader (fonts, images), the emitted
URLs were relative to the CSS output directory. That broke when the CSS
was inlined into HTML, since browsers then resolved the URLs against the
page rather than the CSS file.
Set esbuild's PublicPath to the CSS output directory joined with the
site base path so URLs work whether the CSS is published as a file or
inlined.
Fixes#14849
When the server returns a temporary HTTP error (e.g. 429 or 503)
together with a Retry-After header, use that value as the next sleep
duration instead of the default exponential backoff. The Retry-After
value is also surfaced in the retry-timeout error message.
Fixes#14828
Allow CSS variables to be grouped under sub-paths and imported via
@import "hugo:vars/mobile" (or @use for Dart Sass), so callers can pass
nested dicts like:
{{ dict "primary-color" "blue" "mobile" (dict "primary-color" "red") }}
Top-level "hugo:vars" now skips nested map entries instead of emitting
garbage for them.
Fixes#14705
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add security.node.permissions config to run Node tools (PostCSS, Babel,
TailwindCSS) under Node's permission model, restricting file system access
to the working directory by default.
The binary resolution is simplified to node_modules/.bin → PATH (npx removed).
For both locations, the actual JS entry point is resolved via symlinks (macOS/Linux)
or by parsing npm wrapper scripts (Windows .cmd), then executed as
"node --permission --allow-fs-read=<path> --allow-fs-write=<path> <script>".
Users can opt out by removing "node" from security.exec.allow.
Closes#7287
This is some logic that's left behind from when we had only one dimension (language) where the common case would be to have one resource set (e.g. an image) and many content translation.
After this commit:
* For sites matrix defined in the content filename (e.g. data.en.js) or in its mount definition, we may use that as a fallback for e.g. German languages if we don't find a better match.
* For content adapters, this is not relevant: Here you must be explicit about this.
* We never auto-fallback on resources from a role/version to another.
* When a page bundle spans multiple roles (e.g. via roles = "*"), we clone its resources to all roles so each gets role-specific paths.
Fixes#14749Fixes#14752
When a resource transformation result was served from cache (same
options as a previous build), the output file was not re-written to
disk. This caused incorrect output when toggling transformation
options (e.g. minify) back to a previously seen value in server mode.
Fixes#14629
The per-request timeout context was cancelled via defer in the getRes
closure, before io.ReadAll(res.Body) in the outer scope could read
the response body. Fix this by returning the cancel function from
getRes so each caller manages its own cancel lifecycle.
Fixes#14611
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Add AVIF, HEIF and HEIC partial support
* Add them as media types.
* Support reading metadata (Width, Height, Exif, etc.) from these formats.
* Add a new template function IsImageResourceMeta to check if a resource supports image metadata operations, which will return true for AVIF, HEIF and HEIC resources even if they don't support full image operations yet.
Fixes#14549
This moves Site.Data to the hugo namespace as hugo.Data, following the
same pattern used for hugo.Sites. Also deprecate Site.AllPages,
Site.BuildDrafts, and Site.Languages.
Closes#14521
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* This break the circular dependency between hugolib and resources/page, and allow HugoInfo to use the proper Page ans Site interfaces.
* It's a little misplaced, but it makes everything easier to maintain and test, so that's well worth it.
Changes:
- Add hugo.Sites to return all sites for all dimensions
- Modify .Site.Sites to return all sites for all dimensions
- Deprecate .Site.Sites in favor of hugo.Sites
- Add .Site.IsDefault() to report whether the current site is the
default site across all dimensions
- Consolidate tests
Closes#14479Closes#14481
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Running `mage check` takes too long time for user (and agent) iterations. That will eventualy run on CI.
This is a faster version that:
* Checks gofmt.
* Runs go vet.
* Runs staticcheck.
* Runs unit tests without the race flag.
It assumes that Go is installed, but will check if staticcheck is available and install it if not with go install.
It takes an optional argument to specify packages to check, otherwise it checks all packages.
This commit also enable local runs of the image golden tests.
Since the meta config is new (and exif config is deprecated), remove
these options from MetaConfig. The fields filter controls which metadata
is extracted, including Date and GPS fields.
The existing exif config options are preserved for backward compatibility.
Closes#14437
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The fetchResourceForSpec function was reusing a single ReadSeekCloser
across multiple goroutines, causing a race condition when
TestImageTransformConcurrent runs with imageProcWorkers > 1.
This was exposed by commit e569dd59a ("Misc webp performance work")
which increased imageProcWorkers from 1 to 2.
Fix by creating a new reader on each call to the open function.
Fixes race condition causing segfault on Apple Silicon.
Co-authored-by: Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
This adds a new file cache named 'modulequeries' with a 24h maxAge
that caches JSON responses from 'go mod download -json' when querying
module versions with constraints (e.g., version = "<v3.0.0").
On subsequent builds, if the cached JSON exists and the module
directory it references is non-empty, the cached result is used
directly, skipping the costly VCS interaction entirely.
Fixes#14417
There are 2 fundamental changes related to alias handling in this PR:
1. the `Page.Aliases`` method returns a ready-to-use list of aliases, not the raw input data. This means that it's prefixed with correct dimension values (e.g. language code) and output format paths, and ready to use in e.g. Netlify's _redirects file.
2. We only render aliases for output formats that is both defined as `IsHTML` and `Permalinkable`.
See #14402
*- Dynamic pool sizing for WebP and Katex based on CPU count
- WebP decode: use RGB (3 bytes) for opaque images instead of RGBA (4 bytes)
- Add new imaging.config with new encoder method option; this is default 4 (what we had before), if have tested with value 2 for a 30% speedup on my MacBook, but that does sacrifice quality in some cases (quality/speed trade-off 0-6)
- Track hasAlpha in decode response to enable RGB optimization
- Scale image processing workers (1->2) on high-core machines
- Add WebP benchmark test
On my MacBook Pro M1 Pro, I now get these numbers compared to Hugo v0.152.0:
```
goos: darwin
goarch: arm64
pkg: github.com/gohugoio/hugo/internal/warpc
cpu: Apple M1 Pro
│ cmp152.bench │ fix-webpbench.bench │
│ sec/op │ sec/op vs base │
Webp-10 162.6m ± 32% 145.3m ± 21% -10.60% (p=0.026 n=6)
│ cmp152.bench │ fix-webpbench.bench │
│ B/op │ B/op vs base │
Webp-10 41.69Mi ± 0% 123.79Mi ± 0% +196.92% (p=0.002 n=6)
│ cmp152.bench │ fix-webpbench.bench │
│ allocs/op │ allocs/op vs base │
Webp-10 9.963k ± 3% 18.797k ± 2% +88.67% (p=0.002 n=6)
```
For general image resize benchmarks compared to Hugo v0.152.0 (note that that's not the result of this branch):
```bash
goos: darwin
goarch: arm64
pkg: github.com/gohugoio/hugo/resources/images
cpu: Apple M1 Pro
│ cmp152.bench │ fix-webpbench.bench │
│ sec/op │ sec/op vs base │
ImageResize-10 84.12m ± ∞ ¹ 40.70m ± ∞ ¹ -51.61% (p=0.029 n=4)
¹ need >= 6 samples for confidence interval at level 0.95
│ cmp152.bench │ fix-webpbench.bench │
│ B/op │ B/op vs base │
ImageResize-10 32.37Mi ± ∞ ¹ 29.25Mi ± ∞ ¹ -9.64% (p=0.029 n=4)
¹ need >= 6 samples for confidence interval at level 0.95
│ cmp152.bench │ fix-webpbench.bench │
│ allocs/op │ allocs/op vs base │
ImageResize-10 11.34k ± ∞ ¹ 12.03k ± ∞ ¹ +6.07% (p=0.029 n=4)
¹ need >= 6 samples for confidence interval at level 0.95
```
Closes#14370