Compare commits

..

73 Commits

Author SHA1 Message Date
hugoreleaser 76a5e1880a releaser: Bump versions for release of 0.165.0
[ci skip]
2026-08-12 14:26:28 +00:00
dependabot[bot] 0bb337b22a build(deps): bump github.com/bep/imagemeta from 0.17.3 to 1.0.0
Bumps [github.com/bep/imagemeta](https://github.com/bep/imagemeta) from 0.17.3 to 1.0.0.
- [Release notes](https://github.com/bep/imagemeta/releases)
- [Commits](https://github.com/bep/imagemeta/compare/v0.17.3...v1.0.0)

---
updated-dependencies:
- dependency-name: github.com/bep/imagemeta
  dependency-version: 1.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-12 13:49:11 +02:00
dependabot[bot] 03dc9170b3 build(deps): bump github.com/evanw/esbuild from 0.28.1 to 0.28.2
Bumps [github.com/evanw/esbuild](https://github.com/evanw/esbuild) from 0.28.1 to 0.28.2.
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.28.1...v0.28.2)

---
updated-dependencies:
- dependency-name: github.com/evanw/esbuild
  dependency-version: 0.28.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-12 13:48:55 +02:00
dependabot[bot] c829b736cc build(deps): bump github.com/tdewolff/minify/v2 from 2.24.14 to 2.24.16
Bumps [github.com/tdewolff/minify/v2](https://github.com/tdewolff/minify) from 2.24.14 to 2.24.16.
- [Release notes](https://github.com/tdewolff/minify/releases)
- [Commits](https://github.com/tdewolff/minify/compare/v2.24.14...v2.24.16)

---
updated-dependencies:
- dependency-name: github.com/tdewolff/minify/v2
  dependency-version: 2.24.16
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-12 11:38:40 +02:00
Bjørn Erik Pedersen 995a2159e5 resources: Resume chained resource transformations
This is a follow up the bug fix in #15189. With the example given in that issue, the `css.Build` would be performed twice, which was unfortunate.

This commit fixes that by resuming the transformation from the last executed transformation.

See #15189
2026-08-11 19:12:24 +02:00
Bjørn Erik Pedersen f88f0a9f59 resources/jsconfig: Drop source root mapping for the current source root
* Intellisense doesn't need it to do its work.
* This also avoids creating a jsconfig.js file in the common cases.

Fixes #15169
2026-08-11 15:57:03 +02:00
Bjørn Erik Pedersen dd3f2731e0 Remove Star History from README
Removed Star History section from README.

Closes #15190
2026-08-10 23:08:30 +02:00
Bjørn Erik Pedersen f772998fa3 Fix resource transformation chaining after content access
When a transformed resource had been initialized (e.g. via .Data, .Content
or .RelPermalink) before chaining another transformation, the new chain
would run on the transformed output instead of the original source,
re-running all transformations on their own output.

Fixes #15189

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-10 18:10:06 +02:00
Bjørn Erik Pedersen 8a55df7af2 Remove tailwindcss from the default security.exec.allow list (note)
Fixes #15178
Closes #15171
2026-08-10 15:59:57 +02:00
Bjørn Erik Pedersen 52c9bd7908 circleci: Upgrade to Go 1.26.5 2026-08-09 21:38:57 +02:00
Bjørn Erik Pedersen 44da086082 Add Data.Artifacts to css.Build and js.Build
Artifacts are the additional output files published as part of the build:
source maps and files emitted by ESBuild's file loader (e.g. fonts). Each
artifact provides Permalink, RelPermalink and MediaType, so e.g. font
preload links can be constructed in templates.

Also add media type definitions for source maps (application/source-map),
font/woff and font/woff2.

Fixes #15173

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-08 19:51:42 +02:00
Bjørn Erik Pedersen 2ffaf1fc1e Fix server static file detection for deleted files/directories in the static syncer
Related to #15174
2026-08-08 18:08:03 +02:00
Bjørn Erik Pedersen a808f6e40d Fix server errors when deleting static files or directories
Fixes #15174
2026-08-08 18:08:03 +02:00
dependabot[bot] 94f3908ec6 build(deps): bump github.com/getkin/kin-openapi from 0.145.0 to 0.146.0
Bumps [github.com/getkin/kin-openapi](https://github.com/getkin/kin-openapi) from 0.145.0 to 0.146.0.
- [Release notes](https://github.com/getkin/kin-openapi/releases)
- [Commits](https://github.com/getkin/kin-openapi/compare/v0.145.0...v0.146.0)

---
updated-dependencies:
- dependency-name: github.com/getkin/kin-openapi
  dependency-version: 0.146.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-07 11:31:51 +02:00
dependabot[bot] 75fcc7524a build(deps): bump github.com/rogpeppe/go-internal from 1.15.0 to 1.16.0
Bumps [github.com/rogpeppe/go-internal](https://github.com/rogpeppe/go-internal) from 1.15.0 to 1.16.0.
- [Release notes](https://github.com/rogpeppe/go-internal/releases)
- [Commits](https://github.com/rogpeppe/go-internal/compare/v1.15.0...v1.16.0)

---
updated-dependencies:
- dependency-name: github.com/rogpeppe/go-internal
  dependency-version: 1.16.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-07 11:31:37 +02:00
Bjørn Erik Pedersen 33d1f2c853 css: Add classDark and classLight options to css.ChromaStyles and gen chromastyles
Closes #15167
2026-08-05 16:04:48 +02:00
Bjørn Erik Pedersen 64da6d7c62 markup/highlight: Re-emit token colors dropped by Chroma's minifier
Chroma drops token rules whose color equals the style's default foreground
(e.g. .nx in github-dark). In a paired light/dark setup the other sheet's
explicit rule then leaks in, since an explicit declaration beats inheritance
from .chroma. Apply the chromaCSSOverrides custom CSS unconditionally so
these rules survive in modeSelector sheets too.

Updates #15161
2026-08-04 16:10:27 +02:00
Bjørn Erik Pedersen 70db201ed4 Add importContext option to css.Build, js.Build, css.Sass and css.TailwindCSS
This allows @import statements to be resolved in a set of user provided resources (e.g. from resources.FromString or css.ChromaStyles) before the assets filesystem.

The option also applies to css.PostCSS via the shared import inlining, and css.Sass requires the dartsass transpiler. The import context is part of the transformation cache key.

Fixes #15103

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-03 21:20:06 +02:00
Bjørn Erik Pedersen 8a468df065 Remove some old deprecations 2026-07-29 20:48:47 +02:00
dependabot[bot] b5fa03d3aa build(deps): bump github.com/mattn/go-isatty from 0.0.22 to 0.0.24
Bumps [github.com/mattn/go-isatty](https://github.com/mattn/go-isatty) from 0.0.22 to 0.0.24.
- [Commits](https://github.com/mattn/go-isatty/compare/v0.0.22...v0.0.24)

---
updated-dependencies:
- dependency-name: github.com/mattn/go-isatty
  dependency-version: 0.0.24
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-29 18:42:01 +02:00
dependabot[bot] 9da472dd3b build(deps): bump github.com/yuin/goldmark from 1.8.4 to 1.8.5
Bumps [github.com/yuin/goldmark](https://github.com/yuin/goldmark) from 1.8.4 to 1.8.5.
- [Release notes](https://github.com/yuin/goldmark/releases)
- [Commits](https://github.com/yuin/goldmark/compare/v1.8.4...v1.8.5)

---
updated-dependencies:
- dependency-name: github.com/yuin/goldmark
  dependency-version: 1.8.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-29 18:41:48 +02:00
Bjørn Erik Pedersen 615e45d6e8 Add css.ChromaStyles
Move the stylesheet generation from the gen chromastyles command into
markup/highlight and share it with the new template function.

Fixes #15112

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-29 18:41:31 +02:00
dependabot[bot] 635532a20f build(deps): bump golang.org/x/tools from 0.47.0 to 0.48.0
Bumps [golang.org/x/tools](https://github.com/golang/tools) from 0.47.0 to 0.48.0.
- [Release notes](https://github.com/golang/tools/releases)
- [Commits](https://github.com/golang/tools/compare/v0.47.0...v0.48.0)

---
updated-dependencies:
- dependency-name: golang.org/x/tools
  dependency-version: 0.48.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-29 11:52:08 +02:00
Shantanav Mukherjee a243a6154c check.sh: Handle staticcheck not installed/in PATH 2026-07-28 12:31:02 +02:00
dependabot[bot] 9c71f600bf build(deps): bump github.com/kyokomi/emoji/v2 from 2.2.13 to 2.2.14
Bumps [github.com/kyokomi/emoji/v2](https://github.com/kyokomi/emoji) from 2.2.13 to 2.2.14.
- [Release notes](https://github.com/kyokomi/emoji/releases)
- [Commits](https://github.com/kyokomi/emoji/compare/v2.2.13...v2.2.14)

---
updated-dependencies:
- dependency-name: github.com/kyokomi/emoji/v2
  dependency-version: 2.2.14
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-28 12:29:19 +02:00
dependabot[bot] 420527fc6b build(deps): bump github.com/getkin/kin-openapi from 0.144.0 to 0.145.0
Bumps [github.com/getkin/kin-openapi](https://github.com/getkin/kin-openapi) from 0.144.0 to 0.145.0.
- [Release notes](https://github.com/getkin/kin-openapi/releases)
- [Commits](https://github.com/getkin/kin-openapi/compare/v0.144.0...v0.145.0)

---
updated-dependencies:
- dependency-name: github.com/getkin/kin-openapi
  dependency-version: 0.145.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-28 12:28:40 +02:00
dependabot[bot] 7fe786e3b0 build(deps): bump golang.org/x/image from 0.43.0 to 0.44.0
Bumps [golang.org/x/image](https://github.com/golang/image) from 0.43.0 to 0.44.0.
- [Commits](https://github.com/golang/image/compare/v0.43.0...v0.44.0)

---
updated-dependencies:
- dependency-name: golang.org/x/image
  dependency-version: 0.44.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-27 17:44:56 +02:00
dependabot[bot] 03b244fc0b build(deps): bump github.com/bep/imagemeta from 0.17.2 to 0.17.3
Bumps [github.com/bep/imagemeta](https://github.com/bep/imagemeta) from 0.17.2 to 0.17.3.
- [Release notes](https://github.com/bep/imagemeta/releases)
- [Commits](https://github.com/bep/imagemeta/compare/v0.17.2...v0.17.3)

---
updated-dependencies:
- dependency-name: github.com/bep/imagemeta
  dependency-version: 0.17.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-27 17:44:44 +02:00
dependabot[bot] 961181334f build(deps): bump github.com/tdewolff/minify/v2 from 2.24.13 to 2.24.14
Bumps [github.com/tdewolff/minify/v2](https://github.com/tdewolff/minify) from 2.24.13 to 2.24.14.
- [Release notes](https://github.com/tdewolff/minify/releases)
- [Commits](https://github.com/tdewolff/minify/compare/v2.24.13...v2.24.14)

---
updated-dependencies:
- dependency-name: github.com/tdewolff/minify/v2
  dependency-version: 2.24.14
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-27 17:44:32 +02:00
dependabot[bot] e35b7f049d build(deps): bump github.com/yuin/goldmark from 1.8.2 to 1.8.4
Bumps [github.com/yuin/goldmark](https://github.com/yuin/goldmark) from 1.8.2 to 1.8.4.
- [Release notes](https://github.com/yuin/goldmark/releases)
- [Commits](https://github.com/yuin/goldmark/compare/v1.8.2...v1.8.4)

---
updated-dependencies:
- dependency-name: github.com/yuin/goldmark
  dependency-version: 1.8.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-27 17:44:14 +02:00
Bjørn Erik Pedersen 7d90277a28 warpc: Improve AVIF error message on memory allocation failure
See https://discourse.gohugo.io/t/avif-conversion-fails-for-jpg-files-with-embedded-colour-profiles-when-not-resizing/57392/4
2026-07-27 17:44:01 +02:00
dependabot[bot] 0796fa7ace build(deps): bump golang.org/x/net from 0.56.0 to 0.57.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.56.0 to 0.57.0.
- [Commits](https://github.com/golang/net/compare/v0.56.0...v0.57.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-version: 0.57.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-26 17:03:18 +02:00
Bjørn Erik Pedersen 6bf15241a1 Fix panic on server atomic save edits on MacOS
An atomic save (write temp file, rename into place) unlinks the inode the
watcher holds, so kqueue reports Remove for a file that's still on disk.
That took the delete branch and wiped the entire taxonomy subtree; the
following assemble then panicked in createMissingTaxonomies, where the
shifting tree.Get hit a not yet assembled *pageMetaSource.

Treat Remove of a path that still exists as an update, and use the
non-shifting GetRaw when checking for the auto created taxonomy node.

Fixes #15130

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:00:32 +02:00
Bjørn Erik Pedersen 861ede6d10 cache/filecache: Don't prune used cache entries with mixed-case dir names
On case-insensitive filesystems, entries created before we started lowercasing
the content paths in v0.123 are the same file as today's lowercased cache key,
and were removed on every hugo --gc.

Fixes #15101

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-07-26 11:40:27 +02:00
Bjørn Erik Pedersen f228c87d41 Drop symlinks in parent directories
Lstat only refrains from following the last element of a path, so a symlink
in an intermediate directory was still resolved, and reads could escape the
mount via e.g. resources.Get "symlinkdir/secret.txt".

Walk the directories up to the mount root and reject any that is a symlink.

Follow-up to cf9c8f93c and f8b5fa09a.
2026-07-25 18:17:06 +02:00
dependabot[bot] 1b701b72ca build(deps): bump golang.org/x/text from 0.38.0 to 0.40.0
Bumps [golang.org/x/text](https://github.com/golang/text) from 0.38.0 to 0.40.0.
- [Release notes](https://github.com/golang/text/releases)
- [Commits](https://github.com/golang/text/compare/v0.38.0...v0.40.0)

---
updated-dependencies:
- dependency-name: golang.org/x/text
  dependency-version: 0.40.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-25 18:14:11 +02:00
dependabot[bot] a32d70b712 build(deps): bump github.com/getkin/kin-openapi from 0.140.0 to 0.144.0
Bumps [github.com/getkin/kin-openapi](https://github.com/getkin/kin-openapi) from 0.140.0 to 0.144.0.
- [Release notes](https://github.com/getkin/kin-openapi/releases)
- [Commits](https://github.com/getkin/kin-openapi/compare/v0.140.0...v0.144.0)

---
updated-dependencies:
- dependency-name: github.com/getkin/kin-openapi
  dependency-version: 0.144.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-25 18:13:45 +02:00
dependabot[bot] 948cfb98f9 build(deps): bump google.golang.org/grpc from 1.80.0 to 1.82.1
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.80.0 to 1.82.1.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.80.0...v1.82.1)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-version: 1.82.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-25 18:12:39 +02:00
dependabot[bot] 8930802ef2 build(deps): bump golang.org/x/mod from 0.37.0 to 0.38.0
Bumps [golang.org/x/mod](https://github.com/golang/mod) from 0.37.0 to 0.38.0.
- [Commits](https://github.com/golang/mod/compare/v0.37.0...v0.38.0)

---
updated-dependencies:
- dependency-name: golang.org/x/mod
  dependency-version: 0.38.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-25 16:45:18 +02:00
Bjørn Erik Pedersen 7df45f615a Delete .gemini 2026-07-25 11:30:55 +02:00
Joe Mooring f961093ea9 markup/asciidocext: Fix TOC parsing for asciidoctor-html5s
Closes #15121

Co-authored-by: mike.szewil <szewil_michael@bah.com>
2026-07-22 19:32:19 +02:00
Joe Mooring 89b8c32200 common/hugo: Include non-go dependencies in go env output
Closes #15116

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-13 10:58:38 +02:00
Joe Mooring 984358f047 snap: Fix snap home environment
Closes #15114
2026-07-13 10:57:03 +02:00
Joe Mooring d1f191c58d Update README.md
- Remove Go Report Card badge (services has been sunset)
- Updated dependencies section
2026-07-13 10:56:09 +02:00
hugoreleaser a198116669 releaser: Prepare repository for 0.165.0-DEV
[ci skip]
2026-07-06 17:47:51 +00:00
hugoreleaser ce2470e701 releaser: Bump versions for release of 0.164.0
[ci skip]
2026-07-06 16:39:30 +00:00
dependabot[bot] 921db7b52c build(deps): bump github.com/JohannesKaufmann/html-to-markdown/v2
Bumps [github.com/JohannesKaufmann/html-to-markdown/v2](https://github.com/JohannesKaufmann/html-to-markdown) from 2.5.1 to 2.5.2.
- [Release notes](https://github.com/JohannesKaufmann/html-to-markdown/releases)
- [Commits](https://github.com/JohannesKaufmann/html-to-markdown/compare/v2.5.1...v2.5.2)

---
updated-dependencies:
- dependency-name: github.com/JohannesKaufmann/html-to-markdown/v2
  dependency-version: 2.5.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-06 15:21:13 +02:00
dependabot[bot] 786ce71e59 build(deps): bump golang.org/x/tools from 0.45.0 to 0.47.0
Bumps [golang.org/x/tools](https://github.com/golang/tools) from 0.45.0 to 0.47.0.
- [Release notes](https://github.com/golang/tools/releases)
- [Commits](https://github.com/golang/tools/compare/v0.45.0...v0.47.0)

---
updated-dependencies:
- dependency-name: golang.org/x/tools
  dependency-version: 0.47.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-06 13:34:38 +02:00
dependabot[bot] 5ad2846161 build(deps): bump golang.org/x/image from 0.42.0 to 0.43.0
Bumps [golang.org/x/image](https://github.com/golang/image) from 0.42.0 to 0.43.0.
- [Commits](https://github.com/golang/image/compare/v0.42.0...v0.43.0)

---
updated-dependencies:
- dependency-name: golang.org/x/image
  dependency-version: 0.43.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-06 13:33:50 +02:00
dependabot[bot] 36ad9f583a build(deps): bump golang.org/x/net from 0.55.0 to 0.56.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.55.0 to 0.56.0.
- [Commits](https://github.com/golang/net/compare/v0.55.0...v0.56.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-version: 0.56.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-06 11:50:17 +02:00
dependabot[bot] 7c0a0bc979 build(deps): bump github.com/pelletier/go-toml/v2 from 2.4.2 to 2.4.3
Bumps [github.com/pelletier/go-toml/v2](https://github.com/pelletier/go-toml) from 2.4.2 to 2.4.3.
- [Release notes](https://github.com/pelletier/go-toml/releases)
- [Commits](https://github.com/pelletier/go-toml/compare/v2.4.2...v2.4.3)

---
updated-dependencies:
- dependency-name: github.com/pelletier/go-toml/v2
  dependency-version: 2.4.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-06 11:49:16 +02:00
Bjørn Erik Pedersen d83ce27ae0 tpl/tplimpl: Support sub paths in layouts passed to .Render
E.g. {{ .Render "foo/mylayout" }} matches mylayout templates in
<dir>/foo for every dir from the page's layout path up to the layouts root.

Closes #15056

Co-authored-by: Joe Mooring <joe.mooring@veriphor.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 20:14:32 +02:00
Bjørn Erik Pedersen 5a5f4a5495 all: Rewrite deprecated constructs in tests 2026-07-04 23:10:26 +02:00
Bjørn Erik Pedersen c6acc246ab Add markup.rst.syntaxHighlight option
Fixes #5349
2026-07-04 22:27:29 +02:00
Bjørn Erik Pedersen 29ed932513 tpl/resources: Deprecate resources.PostProcess in favour of templates.Defer
Fixes #15086
2026-07-04 21:28:31 +02:00
Bjørn Erik Pedersen 7b4ddd1863 contributing: Add a note about co-authoring attributions when borrowing test cases 2026-07-04 18:10:03 +02:00
bejaratommy 671897ae91 tpl/collections: Include key in IsSet unsupported-type warning
The warning logged when calling IsSet with an unsupported type did not
identify which key triggered it, making it hard to locate the offending
template. Include the key in the message.

Fixes #11794
2026-07-04 15:18:42 +02:00
dependabot[bot] a879ebfaaa build(deps): bump github.com/getkin/kin-openapi from 0.139.0 to 0.140.0
Bumps [github.com/getkin/kin-openapi](https://github.com/getkin/kin-openapi) from 0.139.0 to 0.140.0.
- [Release notes](https://github.com/getkin/kin-openapi/releases)
- [Commits](https://github.com/getkin/kin-openapi/compare/v0.139.0...v0.140.0)

---
updated-dependencies:
- dependency-name: github.com/getkin/kin-openapi
  dependency-version: 0.140.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-04 14:43:32 +02:00
sjh9714 499794d19e create: Keep new content placeholders buildable
Fixes #15078
2026-07-04 14:31:54 +02:00
hexbinoct feb3d494b9 hugolib: Use the output format's suffix for alias paths
Alias generation hardcoded "index.html" and only recognized a ".html"
suffix, so an alias with an explicit ".htm" extension (or any other
suffix configured for the html media type) was written to the wrong
path. For example "d.htm" produced the directory "d.htm/index.html"
instead of the file "d.htm".

Build the alias file name from the output format's BaseName and the
media type's first suffix, and detect an explicit file by matching the
alias extension against the configured suffixes. The same check now
drives the uglyURLs case in Aliases.

Fixes #15066
2026-07-04 14:31:34 +02:00
Bjørn Erik Pedersen 65c82178b7 hugio: Speedup hasBytesWriter
The old implementation copied the incoming bytes into a fixed-size buffer
one byte at a time, and for every byte ran bytes.Contains for every
pattern over the whole buffer. That's O(n·patterns) scans of the buffer,
which showed up badly on large output (a full rendered page).

Scan each not-yet-matched pattern once per Write with bytes.Contains over
the chunk itself, in place, rather than per byte. The only carried state
is a small boundary window (the last maxPatternLen-1 bytes) joined with
the head of the next chunk, so a pattern straddling a Write boundary is
still detected. The chunk is never copied, so the extra allocation is
bounded by the longest pattern and independent of the output size. Once
all patterns have matched we mark done and drop the buffer.

patternLen summed the pattern lengths (to size the old buffer); the
boundary window only needs the longest pattern, so it's renamed
maxPatternLen and returns the max.

```bash
                  │ benchcmp.bench  │       fix-hasbytewriter.bench       │
                  │     sec/op      │    sec/op     vs base               │
HasBytesWriter-10   2473.095µ ± ∞ ¹   6.114µ ± ∞ ¹  -99.75% (p=0.029 n=4)
¹ need >= 6 samples for confidence interval at level 0.95

                  │ benchcmp.bench │       fix-hasbytewriter.bench        │
                  │      B/op      │     B/op      vs base                │
HasBytesWriter-10      48.00 ± ∞ ¹   128.00 ± ∞ ¹  +166.67% (p=0.029 n=4)
¹ need >= 6 samples for confidence interval at level 0.95

                  │ benchcmp.bench │       fix-hasbytewriter.bench       │
                  │   allocs/op    │  allocs/op   vs base                │
```
2026-07-04 13:25:35 +02:00
dependabot[bot] 332d5ec823 build(deps): bump golang.org/x/mod from 0.36.0 to 0.37.0
Bumps [golang.org/x/mod](https://github.com/golang/mod) from 0.36.0 to 0.37.0.
- [Commits](https://github.com/golang/mod/compare/v0.36.0...v0.37.0)

---
updated-dependencies:
- dependency-name: golang.org/x/mod
  dependency-version: 0.37.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-04 12:54:41 +02:00
dependabot[bot] 212cc11ada build(deps): bump github.com/pelletier/go-toml/v2 from 2.3.1 to 2.4.2
Bumps [github.com/pelletier/go-toml/v2](https://github.com/pelletier/go-toml) from 2.3.1 to 2.4.2.
- [Release notes](https://github.com/pelletier/go-toml/releases)
- [Commits](https://github.com/pelletier/go-toml/compare/v2.3.1...v2.4.2)

---
updated-dependencies:
- dependency-name: github.com/pelletier/go-toml/v2
  dependency-version: 2.4.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-04 12:54:04 +02:00
Bjørn Erik Pedersen dfb35dcd7a tpl/crypto: Add crypto.Hash
Add a generic crypto.Hash template function returning the hex-encoded
checksum of a string using one of md5, sha1, sha256 (default), sha384 or
sha512. The supported algorithms match those used for the SRI hash in
.Data.Integrity on fingerprinted resources, so an SRI hash can be built
by composing with encoding.HexDecode and encoding.Base64Encode.

Fixes #15072

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-03 18:03:05 +02:00
Bjørn Erik Pedersen ef053faa6a Merge commit 'af91eb1997ace34ef5eed0be31646e8483b78096' 2026-07-03 10:43:53 +02:00
Bjørn Erik Pedersen af91eb1997 Squashed 'docs/' changes from e17426e2b6..c85af679bf
c85af679bf content: Miscellaneous edits
43149dae59 content: Cleanup trailing spaces
2b161d600c content: Improve hosting guides
edc02f6402 content: Improve description of scheduled Cloudflare builds
83dff65d50 content: Fix typos
a93f8b956b content: Fix formatting
3dde5702c7 content: Add instructions for scheduled Cloudflare builds
b1075d9c77 content: Change wrangler config format in Cloudflare hosting guide
565d3292c3 content: Add .mjs and .cjs variants to mounted config files
4fc418d223 content: Update version references
bf2efc9114 content: Update hosting guides
0d8ff2dfe1 Update HUGO_VERSION to 0.163.3

git-subtree-dir: docs
git-subtree-split: c85af679bfe21dd7c01924c47933444f002bdc6b
2026-07-03 10:43:53 +02:00
Bjørn Erik Pedersen a5ec542393 Add encoding.HexDecode/Encode
Fixes #15068
See #15060
2026-06-28 21:39:51 +02:00
Bjørn Erik Pedersen 884439b9a2 deps: Upgrade github.com/evanw/esbuild v0.28.0 => v0.28.1
Test / test (1.26.x, ubuntu-latest) (push) Has been cancelled
Test / test (1.26.x, windows-latest) (push) Has been cancelled
Closes #15033
2026-06-28 19:07:48 +02:00
Joe Mooring 128fb17c2b markup/pandoc: Add citation support
Closes #15062

Co-authored-by: Sebastian Höffner <info@sebastian-hoeffner.de>
2026-06-28 15:37:21 +02:00
Joe Mooring e46d37a984 tpl/tplimpl: Make template name lookup case-insensitive
Closes #15057

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-28 15:36:29 +02:00
Bjørn Erik Pedersen 790a8aa474 deps: Add Chroma dark/light mode support
Test / test (1.26.x, ubuntu-latest) (push) Has been cancelled
Test / test (1.26.x, windows-latest) (push) Has been cancelled
Closes #15017
2026-06-27 18:21:20 +02:00
Joe Mooring fe06735214 hugolib: Return error from .Render when template not found
Closes #15052
2026-06-25 12:09:52 +02:00
hugoreleaser d15baf53a9 releaser: Prepare repository for 0.164.0-DEV
[ci skip]
2026-06-18 16:39:26 +00:00
219 changed files with 5240 additions and 1324 deletions
+2 -2
View File
@@ -4,7 +4,7 @@ parameters:
defaults: &defaults
resource_class: large
docker:
- image: bepsays/ci-hugoreleaser:1.22600.20300
- image: bepsays/ci-hugoreleaser:1.22600.20500
environment: &buildenv
GOMODCACHE: /root/project/gomodcache
version: 2
@@ -58,7 +58,7 @@ jobs:
environment:
<<: [*buildenv]
docker:
- image: bepsays/ci-hugoreleaser-linux-arm64:1.22600.20300
- image: bepsays/ci-hugoreleaser-linux-arm64:1.22600.20500
steps:
- *restore-cache
- &attach-workspace
-13
View File
@@ -1,13 +0,0 @@
have_fun: false
memory_config:
disabled: false
code_review:
disable: false
comment_severity_threshold: HIGH
max_review_comments: -1
pull_request_opened:
help: true
summary: false
code_review: false
include_drafts: false
ignore_patterns: []
+2 -1
View File
@@ -51,6 +51,7 @@ jobs:
run: |
gem install asciidoctor -v "2.0.26"
gem install asciidoctor-diagram -v "3.1.0"
gem install asciidoctor-html5s -v "0.5.1"
- name: Install GoAT
run: go install github.com/blampe/goat/cmd/goat@177de93b192b8ffae608e5d9ec421cc99bf68402
- name: Install Python
@@ -63,7 +64,7 @@ jobs:
run: go install github.com/gohugoio/gotmplfmt@latest
- name: Install docutils
run: |
pip install docutils
pip install docutils Pygments
rst2html --version
- if: matrix.os == 'ubuntu-latest'
name: Install pandoc on Linux
+2 -1
View File
@@ -5,4 +5,5 @@ dist/
public/
.DS_Store
cache/filecache/_gen/
.claude/
.claude/
dump.txt
+1
View File
@@ -12,6 +12,7 @@
* In tests, use `qt` matchers (e.g. `b.Assert(err, qt.ErrorMatches, ...)`) instead of raw `if`/`t.Fatal` checks.
* In tests, always use the latest Hugo specification, e.g. for layouts, it's `layouts/page.html` and not `layouts/_default/single.html`, `layouts/list.html` and not `layouts/_default/list.html`
* Never name tests `TestIssue1234`; always give the test function a descriptive name, e.g. `TestDisablePathToLower`, and add any issue reference as a Go doc function comment, e.g. `// See issue 1234.`.
* If you borrow a test case (e.g. from the issue), that test's author must be added as co-author in the commit.
* If you're a security researcher, read @SECURITY.md carefully.
* Brevity is good. This applies to code, comments and commit messages. Don't write a novel.
* Use `./check.sh ./somepackage/...` when iterating.
+1
View File
@@ -72,6 +72,7 @@ To make the contribution process as seamless as possible, we ask for the followi
* When youre ready to create a pull request, be sure to:
* Sign the [CLA](https://cla-assistant.io/gohugoio/hugo).
* Have test cases for the new code. If you have questions about how to do this, please ask in your pull request.
* If you borrow a test case (e.g. from the issue), that test's author must be added as [co-author](https://docs.github.com/en/pull-requests/committing-changes-to-your-project/creating-and-editing-commits/creating-a-commit-with-multiple-authors) in the commit.
* Run `go fmt`.
* Add documentation if you are adding new features or changing functionality. The docs site lives in `/docs`.
* Squash your commits into a single commit. `git rebase -i`. Its okay to force update your pull request with `git push -f`.
+122 -65
View File
@@ -37,7 +37,6 @@ A fast and flexible static site generator built with love by [bep][], [spf13][],
[![GoDoc](https://godoc.org/github.com/gohugoio/hugo?status.svg)](https://godoc.org/github.com/gohugoio/hugo)
[![Tests on Linux, MacOS and Windows](https://github.com/gohugoio/hugo/workflows/Test/badge.svg)](https://github.com/gohugoio/hugo/actions?query=workflow%3ATest)
[![Go Report Card](https://goreportcard.com/badge/github.com/gohugoio/hugo)](https://goreportcard.com/report/github.com/gohugoio/hugo)
[Website][] | [Installation][] | [Documentation][] | [Support][] | [Contributing][] | <a rel="me" href="https://fosstodon.org/@gohugoio">Mastodon</a>
@@ -139,10 +138,6 @@ To build and install the extended/deploy edition, first install a C compiler suc
CGO_ENABLED=1 go install -tags extended,withdeploy github.com/gohugoio/hugo@latest
```
## Star History
[![Star History Chart](https://api.star-history.com/svg?repos=gohugoio/hugo&type=Timeline)](https://star-history.com/#gohugoio/hugo&Timeline)
## Documentation
Hugo's [documentation][] includes installation instructions, a quick start guide, conceptual explanations, reference information, and examples.
@@ -195,10 +190,48 @@ Hugo stands on the shoulders of great open source libraries. Run `hugo env --log
<summary>See current dependencies</summary>
```text
cel.dev/expr="v0.25.1"
cloud.google.com/go/auth/oauth2adapt="v0.2.8"
cloud.google.com/go/auth="v0.20.0"
cloud.google.com/go/compute/metadata="v0.9.0"
cloud.google.com/go/iam="v1.5.3"
cloud.google.com/go/monitoring="v1.24.3"
cloud.google.com/go/storage="v1.57.2"
cloud.google.com/go="v0.123.0"
github.com/Azure/azure-sdk-for-go/sdk/azcore="v1.20.0"
github.com/Azure/azure-sdk-for-go/sdk/azidentity="v1.13.1"
github.com/Azure/azure-sdk-for-go/sdk/internal="v1.11.2"
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob="v1.6.3"
github.com/Azure/go-autorest/autorest/to="v0.4.1"
github.com/AzureAD/microsoft-authentication-library-for-go="v1.6.0"
github.com/BurntSushi/locker="v0.0.0-20171006230638-a6e239ea1c69"
github.com/JohannesKaufmann/dom="v0.2.0"
github.com/JohannesKaufmann/html-to-markdown/v2="v2.5.0"
github.com/alecthomas/chroma/v2="v2.21.1"
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp="v1.31.0"
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric="v0.54.0"
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping="v0.54.0"
github.com/JohannesKaufmann/dom="v0.3.1"
github.com/JohannesKaufmann/html-to-markdown/v2="v2.5.2"
github.com/alecthomas/chroma/v2="v2.27.0"
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream="v1.7.8"
github.com/aws/aws-sdk-go-v2/config="v1.32.2"
github.com/aws/aws-sdk-go-v2/credentials="v1.19.2"
github.com/aws/aws-sdk-go-v2/feature/ec2/imds="v1.18.14"
github.com/aws/aws-sdk-go-v2/feature/s3/manager="v1.20.12"
github.com/aws/aws-sdk-go-v2/internal/configsources="v1.4.22"
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2="v2.7.22"
github.com/aws/aws-sdk-go-v2/internal/ini="v1.8.4"
github.com/aws/aws-sdk-go-v2/internal/v4a="v1.4.22"
github.com/aws/aws-sdk-go-v2/service/cloudfront="v1.61.1"
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding="v1.13.7"
github.com/aws/aws-sdk-go-v2/service/internal/checksum="v1.9.13"
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url="v1.13.21"
github.com/aws/aws-sdk-go-v2/service/internal/s3shared="v1.19.21"
github.com/aws/aws-sdk-go-v2/service/s3="v1.97.3"
github.com/aws/aws-sdk-go-v2/service/signin="v1.0.2"
github.com/aws/aws-sdk-go-v2/service/sso="v1.30.5"
github.com/aws/aws-sdk-go-v2/service/ssooidc="v1.35.10"
github.com/aws/aws-sdk-go-v2/service/sts="v1.41.2"
github.com/aws/aws-sdk-go-v2="v1.41.6"
github.com/aws/smithy-go="v1.25.0"
github.com/aymerick/douceur="v0.2.0"
github.com/bep/clocks="v0.5.0"
github.com/bep/debounce="v1.2.0"
@@ -206,105 +239,129 @@ github.com/bep/gitmap="v1.9.0"
github.com/bep/goat="v0.5.0"
github.com/bep/godartsass/v2="v2.5.0"
github.com/bep/golibsass="v1.2.0"
github.com/bep/goportabletext="v0.1.0"
github.com/bep/helpers="v0.6.0"
github.com/bep/imagemeta="v0.12.0"
github.com/bep/lazycache="v0.8.0"
github.com/bep/golocales="v0.2.0"
github.com/bep/goportabletext="v0.2.0"
github.com/bep/helpers="v0.12.0"
github.com/bep/imagemeta="v0.17.2"
github.com/bep/lazycache="v0.8.1"
github.com/bep/logg="v0.4.0"
github.com/bep/mclib="v1.20400.20402"
github.com/bep/overlayfs="v0.10.0"
github.com/bep/simplecobra="v0.6.1"
github.com/bep/textandbinarywriter="v0.0.0-20251212174530-cd9f0732f60f"
github.com/bep/tmc="v0.5.1"
github.com/bits-and-blooms/bitset="v1.24.4"
github.com/bep/mclib="v1.20401.20400"
github.com/bep/overlayfs="v0.11.0"
github.com/bep/simplecobra="v0.7.0"
github.com/bep/textandbinarywriter="v0.1.0"
github.com/bep/tmc="v0.6.0"
github.com/bits-and-blooms/bitset="v1.24.5"
github.com/cespare/xxhash/v2="v2.3.0"
github.com/clbanning/mxj/v2="v2.7.0"
github.com/clipperhouse/displaywidth="v0.6.0"
github.com/clipperhouse/stringish="v0.1.1"
github.com/clipperhouse/uax29/v2="v2.3.0"
github.com/clipperhouse/displaywidth="v0.10.0"
github.com/clipperhouse/uax29/v2="v2.6.0"
github.com/cncf/xds/go="v0.0.0-20251210132809-ee656c7534f5"
github.com/cpuguy83/go-md2man/v2="v2.0.6"
github.com/disintegration/gift="v1.2.1"
github.com/dlclark/regexp2="v1.11.5"
github.com/evanw/esbuild="v0.27.2"
github.com/dlclark/regexp2/v2="v2.2.1"
github.com/dustin/go-humanize="v1.0.1"
github.com/envoyproxy/go-control-plane/envoy="v1.36.0"
github.com/envoyproxy/protoc-gen-validate="v1.3.0"
github.com/evanw/esbuild="v0.28.1"
github.com/fatih/color="v1.18.0"
github.com/felixge/httpsnoop="v1.0.4"
github.com/frankban/quicktest="v1.14.6"
github.com/fsnotify/fsnotify="v1.9.0"
github.com/getkin/kin-openapi="v0.133.0"
github.com/go-openapi/jsonpointer="v0.21.0"
github.com/go-openapi/swag="v0.23.0"
github.com/getkin/kin-openapi="v0.140.0"
github.com/go-jose/go-jose/v4="v4.1.4"
github.com/go-logr/logr="v1.4.3"
github.com/go-logr/stdr="v1.2.2"
github.com/go-openapi/jsonpointer="v0.22.5"
github.com/go-openapi/swag/jsonname="v0.25.5"
github.com/gobuffalo/flect="v1.0.3"
github.com/gobwas/glob="v0.2.3"
github.com/goccy/go-yaml="v1.19.1"
github.com/goccy/go-yaml="v1.19.2"
github.com/gohugoio/gift="v0.2.0"
github.com/gohugoio/go-i18n/v2="v2.1.3-0.20251018145728-cfcc22d823c6"
github.com/gohugoio/go-radix="v1.2.0"
github.com/gohugoio/hashstructure="v0.6.0"
github.com/gohugoio/httpcache="v0.8.0"
github.com/gohugoio/hugo-goldmark-extensions/extras="v0.5.0"
github.com/gohugoio/hugo-goldmark-extensions/passthrough="v0.3.1"
github.com/gohugoio/locales="v0.14.0"
github.com/gohugoio/localescompressed="v1.0.1"
github.com/gohugoio/hugo-goldmark-extensions/extras="v0.7.0"
github.com/gohugoio/hugo-goldmark-extensions/passthrough="v0.5.0"
github.com/golang-jwt/jwt/v5="v5.3.0"
github.com/google/go-cmp="v0.7.0"
github.com/google/s2a-go="v0.1.9"
github.com/google/uuid="v1.6.0"
github.com/google/wire="v0.7.0"
github.com/googleapis/enterprise-certificate-proxy="v0.3.14"
github.com/googleapis/gax-go/v2="v2.21.0"
github.com/gorilla/css="v1.0.1"
github.com/gorilla/websocket="v1.5.3"
github.com/hairyhenderson/go-codeowners="v0.7.0"
github.com/hashicorp/golang-lru/v2="v2.0.7"
github.com/jdkato/prose="v1.2.1"
github.com/josharian/intern="v1.0.0"
github.com/kr/pretty="v0.3.1"
github.com/kr/text="v0.2.0"
github.com/kylelemons/godebug="v1.1.0"
github.com/kyokomi/emoji/v2="v2.2.13"
github.com/mailru/easyjson="v0.7.7"
github.com/makeworld-the-better-one/dither/v2="v2.4.0"
github.com/marekm4/color-extractor="v1.2.1"
github.com/mattn/go-colorable="v0.1.13"
github.com/mattn/go-isatty="v0.0.20"
github.com/mattn/go-colorable="v0.1.14"
github.com/mattn/go-isatty="v0.0.22"
github.com/mattn/go-runewidth="v0.0.19"
github.com/microcosm-cc/bluemonday="v1.0.27"
github.com/mitchellh/mapstructure="v1.5.1-0.20231216201459-8508981c8b6c"
github.com/mohae/deepcopy="v0.0.0-20170929034955-c48cc78d4826"
github.com/muesli/smartcrop="v0.3.0"
github.com/niklasfasching/go-org="v1.9.1"
github.com/oasdiff/yaml3="v0.0.0-20250309153720-d2182401db90"
github.com/oasdiff/yaml="v0.0.0-20250309154309-f31be36b4037"
github.com/oasdiff/yaml3="v0.0.13"
github.com/oasdiff/yaml="v0.1.0"
github.com/olekukonko/cat="v0.0.0-20250911104152-50322a0618f6"
github.com/olekukonko/errors="v1.1.0"
github.com/olekukonko/ll="v0.1.3"
github.com/olekukonko/tablewriter="v1.1.2"
github.com/olekukonko/errors="v1.2.0"
github.com/olekukonko/ll="v0.1.6"
github.com/olekukonko/tablewriter="v1.1.4"
github.com/pbnjay/memory="v0.0.0-20210728143218-7b4eea64cf58"
github.com/pelletier/go-toml/v2="v2.2.4"
github.com/perimeterx/marshmallow="v1.1.5"
github.com/pelletier/go-toml/v2="v2.4.3"
github.com/pkg/browser="v0.0.0-20240102092130-5ac0b6a4141c"
github.com/pkg/errors="v0.9.1"
github.com/rogpeppe/go-internal="v1.14.1"
github.com/rogpeppe/go-internal="v1.15.0"
github.com/russross/blackfriday/v2="v2.1.0"
github.com/sass/dart-sass/compiler="1.97.1"
github.com/sass/dart-sass/implementation="1.97.1"
github.com/sass/dart-sass/protocol="3.2.0"
github.com/santhosh-tekuri/jsonschema/v6="v6.0.2"
github.com/spf13/afero="v1.15.0"
github.com/spf13/cast="v1.10.0"
github.com/spf13/cobra="v1.10.2"
github.com/spf13/fsync="v0.10.1"
github.com/spf13/pflag="v1.0.9"
github.com/tdewolff/minify/v2="v2.24.8"
github.com/tdewolff/parse/v2="v2.8.5"
github.com/tetratelabs/wazero="v1.10.1"
github.com/spf13/pflag="v1.0.10"
github.com/spiffe/go-spiffe/v2="v2.6.0"
github.com/tdewolff/minify/v2="v2.24.13"
github.com/tdewolff/parse/v2="v2.8.12"
github.com/tetratelabs/wazero="v1.12.0"
github.com/webmproject/libwebp="v1.6.0"
github.com/woodsbury/decimal128="v1.3.0"
github.com/yuin/goldmark-emoji="v1.0.6"
github.com/yuin/goldmark="v1.7.13"
github.com/yuin/goldmark="v1.8.2"
go.opentelemetry.io/auto/sdk="v1.2.1"
go.opentelemetry.io/contrib/detectors/gcp="v1.39.0"
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc="v0.67.0"
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp="v0.67.0"
go.opentelemetry.io/otel/metric="v1.43.0"
go.opentelemetry.io/otel/sdk/metric="v1.43.0"
go.opentelemetry.io/otel/sdk="v1.43.0"
go.opentelemetry.io/otel/trace="v1.43.0"
go.opentelemetry.io/otel="v1.43.0"
go.uber.org/automaxprocs="v1.5.3"
go.yaml.in/yaml/v3="v3.0.4"
golang.org/x/crypto="v0.46.0"
golang.org/x/image="v0.34.0"
golang.org/x/mod="v0.31.0"
golang.org/x/net="v0.48.0"
golang.org/x/sync="v0.19.0"
golang.org/x/sys="v0.39.0"
golang.org/x/text="v0.32.0"
golang.org/x/tools="v0.40.0"
google.golang.org/protobuf="v1.36.10"
gopkg.in/yaml.v3="v3.0.1"
gocloud.dev="v0.45.0"
golang.org/x/crypto="v0.53.0"
golang.org/x/image="v0.43.0"
golang.org/x/mod="v0.37.0"
golang.org/x/net="v0.56.0"
golang.org/x/oauth2="v0.36.0"
golang.org/x/sync="v0.21.0"
golang.org/x/sys="v0.46.0"
golang.org/x/text="v0.38.0"
golang.org/x/time="v0.15.0"
golang.org/x/tools="v0.47.0"
golang.org/x/xerrors="v0.0.0-20240903120638-7835f813f4da"
google.golang.org/api="v0.276.0"
google.golang.org/genproto/googleapis/api="v0.0.0-20260319201613-d00831a3d3e7"
google.golang.org/genproto/googleapis/rpc="v0.0.0-20260401024825-9d38bb4040a9"
google.golang.org/genproto="v0.0.0-20260319201613-d00831a3d3e7"
google.golang.org/grpc="v1.80.0"
google.golang.org/protobuf="v1.36.11"
rsc.io/qr="v0.2.0"
software.sslmate.com/src/go-pkcs12="v0.2.0"
software.sslmate.com/src/go-pkcs12="v0.7.0"
```
</details>
+54 -13
View File
@@ -17,6 +17,7 @@ import (
"fmt"
"io"
"os"
"strings"
"github.com/gohugoio/hugo/common/herrors"
"github.com/gohugoio/hugo/hugofs"
@@ -59,6 +60,29 @@ func (c *Cache) Prune(force bool) (int, error) {
counter := 0
seen := c.entryLocker.seen
seenByLower := make(map[string]string, seen.Len())
for id := range seen.All() {
seenByLower[strings.ToLower(id)] = id
}
// Names on disk matching a used cache key except for the case, and the used keys
// actually walked. See the note about case-insensitive filesystems below.
var candidates map[string]string
visited := make(map[string]bool, seen.Len())
remove := func(name string) error {
err := c.Fs.Remove(name)
if err == nil {
counter++
return nil
}
if !herrors.IsNotExist(err) {
return err
}
return nil
}
err := afero.Walk(c.Fs, "", func(name string, info os.FileInfo, err error) error {
if info == nil {
return nil
@@ -93,27 +117,44 @@ func (c *Cache) Prune(force bool) (int, error) {
shouldRemove := force || c.isExpired(info.ModTime())
if !shouldRemove && c.entryLocker.seen.Len() > 0 {
// Remove it if it's not been touched/used in the last build.
shouldRemove = !c.entryLocker.seen.Has(name)
if seen.Has(name) {
visited[name] = true
} else if !shouldRemove && seen.Len() > 0 {
if id, found := seenByLower[strings.ToLower(name)]; found {
// On case-insensitive filesystems this is the same file as id; e.g. an
// entry created before Hugo started lowercasing the content paths in
// v0.123 (content/MyBundle => _gen/images/MyBundle). Decided once the
// walk is done: if id is walked too, they are distinct files and this
// one is stale. See issue 15101.
if candidates == nil {
candidates = make(map[string]string)
}
candidates[name] = id
} else {
// Remove it if it's not been touched/used in the last build.
shouldRemove = true
}
}
if shouldRemove {
err := c.Fs.Remove(name)
if err == nil {
counter++
}
if err != nil && !herrors.IsNotExist(err) {
return err
}
return remove(name)
}
return nil
})
if err != nil {
return counter, err
}
return counter, err
for name, id := range candidates {
if visited[id] {
if err := remove(name); err != nil {
return counter, err
}
}
}
return counter, nil
}
func (c *Cache) pruneRootDirs(force bool) (int, error) {
+61
View File
@@ -20,11 +20,72 @@ import (
"time"
"github.com/gohugoio/hugo/cache/filecache"
"github.com/gohugoio/hugo/htesting"
"github.com/spf13/afero"
qt "github.com/frankban/quicktest"
)
// A cache entry created before Hugo started lowercasing content paths in v0.123
// (e.g. _gen/images/MyBundle) is on a case-insensitive filesystem the same file as
// the lowercased cache key used today, and must not be pruned.
// See issue 15101.
func TestPruneCacheEntryWithOtherCase(t *testing.T) {
t.Parallel()
c := qt.New(t)
dir := t.TempDir()
if isCaseInsensitive, err := htesting.IsCaseInsensitiveFs(dir); err != nil {
t.Fatal(err)
} else if !isCaseInsensitive {
t.Skip("skip test on case-sensitive filesystem")
}
fs := afero.NewBasePathFs(afero.NewOsFs(), dir)
newCache := func() *filecache.Cache {
return filecache.NewCache(fs, filecache.FileCacheConfig{Dir: "cache", MaxAge: -1})
}
c.Assert(newCache().SetBytes("MyBundle/i1", []byte("abc")), qt.IsNil)
cache := newCache()
_, b, err := cache.GetOrCreateBytes("mybundle/i1", func() ([]byte, error) {
return []byte("def"), nil
})
c.Assert(err, qt.IsNil)
c.Assert(string(b), qt.Equals, "abc")
count, err := cache.Prune(false)
c.Assert(err, qt.IsNil)
c.Assert(count, qt.Equals, 0)
c.Assert(cache.GetString("MyBundle/i1"), qt.Equals, "abc")
}
// On a case-sensitive filesystem the entries above are distinct files,
// and the one not used in this build should be pruned.
func TestPruneCacheEntryWithOtherCaseCaseSensitiveFs(t *testing.T) {
t.Parallel()
c := qt.New(t)
fs := afero.NewMemMapFs()
cache := filecache.NewCache(fs, filecache.FileCacheConfig{Dir: "cache", MaxAge: -1})
c.Assert(cache.SetBytes("MyBundle/i1", []byte("abc")), qt.IsNil)
cache = filecache.NewCache(fs, filecache.FileCacheConfig{Dir: "cache", MaxAge: -1})
_, b, err := cache.GetOrCreateBytes("mybundle/i1", func() ([]byte, error) {
return []byte("def"), nil
})
c.Assert(err, qt.IsNil)
c.Assert(string(b), qt.Equals, "def")
count, err := cache.Prune(false)
c.Assert(err, qt.IsNil)
c.Assert(count, qt.Equals, 1)
c.Assert(cache.GetString("MyBundle/i1"), qt.Equals, "")
c.Assert(cache.GetString("mybundle/i1"), qt.Equals, "def")
}
func TestPrune(t *testing.T) {
t.Parallel()
+10 -3
View File
@@ -38,13 +38,20 @@ run_gofmt() {
# Run staticcheck
run_staticcheck() {
# Check if staticcheck is installed, install if not
if ! command -v staticcheck &> /dev/null; then
local staticcheck_bin
if command -v staticcheck &> /dev/null; then
staticcheck_bin=$(command -v staticcheck)
else
echo "==> Installing staticcheck..."
go install honnef.co/go/tools/cmd/staticcheck@latest
staticcheck_bin="$(go env GOBIN)"
if [ -z "$staticcheck_bin" ]; then
staticcheck_bin="$(go env GOPATH)/bin"
fi
staticcheck_bin="$staticcheck_bin/staticcheck"
fi
echo "==> Running staticcheck..."
staticcheck $PACKAGES
"$staticcheck_bin" $PACKAGES
echo " OK"
}
+28 -57
View File
@@ -21,12 +21,8 @@ import (
"os"
"path"
"path/filepath"
"slices"
"strings"
"github.com/alecthomas/chroma/v2"
"github.com/alecthomas/chroma/v2/formatters/html"
"github.com/alecthomas/chroma/v2/styles"
"github.com/bep/simplecobra"
"github.com/goccy/go-yaml"
"github.com/gohugoio/hugo/common/hugo"
@@ -34,6 +30,7 @@ import (
"github.com/gohugoio/hugo/helpers"
"github.com/gohugoio/hugo/hugofs"
"github.com/gohugoio/hugo/hugolib"
"github.com/gohugoio/hugo/markup/highlight"
"github.com/gohugoio/hugo/parser"
"github.com/spf13/cobra"
"github.com/spf13/cobra/doc"
@@ -47,6 +44,10 @@ func newGenCommand() *genCommand {
// Chroma flags.
style string
mode string
modeSelector bool
classDark string
classLight string
highlightStyle string
lineNumbersInlineStyle string
lineNumbersTableStyle string
@@ -63,44 +64,41 @@ func newGenCommand() *genCommand {
See https://gohugo.io/quick-reference/syntax-highlighting-styles/ for a preview of the available styles.`,
run: func(ctx context.Context, cd *simplecobra.Commandeer, r *rootCommand, args []string) error {
style = strings.ToLower(style)
if !slices.Contains(styles.Names(), style) {
return fmt.Errorf("invalid style: %s", style)
}
builder := styles.Get(style).Builder()
if highlightStyle != "" {
builder.Add(chroma.LineHighlight, highlightStyle)
}
if lineNumbersInlineStyle != "" {
builder.Add(chroma.LineNumbers, lineNumbersInlineStyle)
}
if lineNumbersTableStyle != "" {
builder.Add(chroma.LineNumbersTable, lineNumbersTableStyle)
}
style, err := builder.Build()
if err != nil {
return err
}
if omitEmpty {
// See https://github.com/alecthomas/chroma/commit/5b2a4c5a26c503c79bc86ba3c4ae5b330028bd3d
hugo.Deprecate("--omitEmpty", "Flag is no longer needed, empty classes are now always omitted.", "v0.149.0")
}
options := []html.Option{
html.WithCSSComments(!omitClassComments),
html.WithCustomCSS(chromaCSSOverrides(style)),
css, err := highlight.ChromaStylesCSS(highlight.ChromaStylesOptions{
Style: style,
Mode: mode,
ModeSelector: modeSelector,
ClassDark: classDark,
ClassLight: classLight,
HighlightStyle: highlightStyle,
LineNumbersInlineStyle: lineNumbersInlineStyle,
LineNumbersTableStyle: lineNumbersTableStyle,
OmitClassComments: omitClassComments,
})
if err != nil {
return err
}
formatter := html.New(options...)
w := os.Stdout
fmt.Fprintf(w, "/* Generated using: hugo %s */\n\n", strings.Join(os.Args[1:], " "))
formatter.WriteCSS(w, style)
fmt.Printf("/* Generated using: hugo %s */\n\n", strings.Join(os.Args[1:], " "))
fmt.Print(css)
return nil
},
withc: func(cmd *cobra.Command, r *rootCommand) {
cmd.ValidArgsFunction = cobra.NoFileCompletions
cmd.PersistentFlags().StringVar(&style, "style", "friendly", "highlighter style")
_ = cmd.RegisterFlagCompletionFunc("style", cobra.NoFileCompletions)
cmd.PersistentFlags().StringVar(&mode, "mode", "", `style mode ("light", "dark")`)
_ = cmd.RegisterFlagCompletionFunc("mode", cobra.FixedCompletions([]string{"light", "dark"}, cobra.ShellCompDirectiveNoFileComp))
cmd.PersistentFlags().BoolVar(&modeSelector, "modeSelector", false, `scope selectors under a top level mode class, e.g. ".dark .chroma"`)
_ = cmd.RegisterFlagCompletionFunc("modeSelector", cobra.NoFileCompletions)
cmd.PersistentFlags().StringVar(&classDark, "classDark", "dark", `class name used by --modeSelector for dark styles`)
_ = cmd.RegisterFlagCompletionFunc("classDark", cobra.NoFileCompletions)
cmd.PersistentFlags().StringVar(&classLight, "classLight", "light", `class name used by --modeSelector for light styles`)
_ = cmd.RegisterFlagCompletionFunc("classLight", cobra.NoFileCompletions)
cmd.PersistentFlags().StringVar(&highlightStyle, "highlightStyle", "", `foreground and background colors for highlighted lines, e.g. --highlightStyle "#fff000 bg:#000fff"`)
_ = cmd.RegisterFlagCompletionFunc("highlightStyle", cobra.NoFileCompletions)
cmd.PersistentFlags().StringVar(&lineNumbersInlineStyle, "lineNumbersInlineStyle", "", `foreground and background colors for inline line numbers, e.g. --lineNumbersInlineStyle "#fff000 bg:#000fff"`)
@@ -276,33 +274,6 @@ url: %s
}
}
func chromaCSSOverrides(style *chroma.Style) map[chroma.TokenType]string {
bg := style.Get(chroma.Background)
m := make(map[chroma.TokenType]string)
for tt := range chroma.StandardTypes {
if tt == chroma.Background || !style.Has(tt) || !chromaLeafToken(tt) {
continue
}
entry := style.Get(tt)
if !entry.Sub(bg).IsZero() || !entry.Colour.IsSet() {
continue
}
if css := html.StyleEntryToCSS(chroma.StyleEntry{Colour: entry.Colour}); css != "" {
m[tt] = css
}
}
return m
}
func chromaLeafToken(tt chroma.TokenType) bool {
for other := range chroma.StandardTypes {
if other != tt && (other.Category() == tt || other.SubCategory() == tt) {
return false
}
}
return true
}
type genCommand struct {
rootCmd *rootCommand
+1 -1
View File
@@ -1108,7 +1108,7 @@ func (s *staticSyncer) syncsStaticEvents(staticEvents []fsnotify.Event) error {
fromPath := ev.Name
relPath, found := sourceFs.MakePathRelative(fromPath, true)
relPath, found := sourceFs.MakePathRelative(fromPath, false)
if !found {
// Not member of this virtual host.
+41 -21
View File
@@ -18,6 +18,7 @@ import (
"crypto/md5"
"encoding/hex"
"io"
"reflect"
"strconv"
"sync"
@@ -105,6 +106,16 @@ func MD5FromStringHexEncoded(f string) string {
return hex.EncodeToString(h.Sum(nil))
}
// MD5FromReaderHexEncoded returns the MD5 hash of the given reader.
func MD5FromReaderHexEncoded(r io.Reader) string {
h := md5.New()
_, err := io.Copy(h, r)
if err != nil {
return ""
}
return hex.EncodeToString(h.Sum(nil))
}
// HashString returns a hash from the given elements.
// It will panic if the hash cannot be calculated.
// Note that this hash should be used primarily for identity, not for change detection as
@@ -124,11 +135,38 @@ func HashStringHex(vs ...any) string {
var hashOptsPool = sync.Pool{
New: func() any {
return &hashstructure.HashOptions{
Hasher: xxhash.New(),
Hasher: xxhash.New(),
UnwrapFunc: unwrapForHashing,
}
},
}
// hashstructure only sees exported struct fields, so rewrite known identity types before hashing,
// e.g. a Resource or Page nested in an options map hashes by its Key.
func unwrapForHashing(v reflect.Value) (reflect.Value, error) {
if v.Kind() != reflect.Struct {
return v, nil
}
var in any
if v.CanAddr() {
// The common case; pointer receiver methods on a struct
// reached through a pointer.
in = v.Addr().Interface()
} else {
in = v.Interface()
}
switch t := in.(type) {
case hashstructure.Hashable:
// Let hashstructure handle it.
return v, nil
case keyer:
return reflect.ValueOf(t.Key()), nil
case identity.IdentityProvider:
return reflect.ValueOf(t.GetIdentity()), nil
}
return v, nil
}
func getHashOpts() *hashstructure.HashOptions {
return hashOptsPool.Get().(*hashstructure.HashOptions)
}
@@ -145,15 +183,10 @@ func putHashOpts(opts *hashstructure.HashOptions) {
func HashUint64(vs ...any) uint64 {
var o any
if len(vs) == 1 {
o = toHashable(vs[0])
o = vs[0]
} else {
elements := make([]any, len(vs))
for i, e := range vs {
elements[i] = toHashable(e)
}
o = elements
o = vs
}
hash, err := Hash(o)
if err != nil {
panic(err)
@@ -176,19 +209,6 @@ type keyer interface {
Key() string
}
// For structs, hashstructure.Hash only works on the exported fields,
// so rewrite the input slice for known identity types.
func toHashable(v any) any {
switch t := v.(type) {
case keyer:
return t.Key()
case identity.IdentityProvider:
return t.GetIdentity()
default:
return v
}
}
type xxhashReadFrom struct {
buff []byte
*xxhash.Digest
+51 -28
View File
@@ -21,8 +21,9 @@ import (
type HasBytesWriter struct {
Patterns []*HasBytesPattern
i int
done bool
// The tail of the bytes written so far, retained so we can detect a
// pattern that straddles the boundary between two Write calls.
buff []byte
}
@@ -31,10 +32,13 @@ type HasBytesPattern struct {
Pattern []byte
}
func (h *HasBytesWriter) patternLen() int {
// maxPatternLen returns the length of the longest pattern.
func (h *HasBytesWriter) maxPatternLen() int {
l := 0
for _, p := range h.Patterns {
l += len(p.Pattern)
if len(p.Pattern) > l {
l = len(p.Pattern)
}
}
return l
}
@@ -44,36 +48,55 @@ func (h *HasBytesWriter) Write(p []byte) (n int, err error) {
return len(p), nil
}
if len(h.buff) == 0 {
h.buff = make([]byte, h.patternLen()*2)
keep := h.maxPatternLen() - 1
// Join the tail retained from previous Writes with the head of this chunk
// so a pattern straddling the boundary is still detected. Only the
// boundary window is copied; the chunk itself is scanned in place below.
var boundary []byte
if keep > 0 && len(h.buff) > 0 {
head := p
if len(head) > keep {
head = head[:keep]
}
boundary = make([]byte, 0, len(h.buff)+len(head))
boundary = append(boundary, h.buff...)
boundary = append(boundary, head...)
}
for i := range p {
h.buff[h.i] = p[i]
h.i++
if h.i == len(h.buff) {
// Shift left.
copy(h.buff, h.buff[len(h.buff)/2:])
h.i = len(h.buff) / 2
// Scan each not-yet-matched pattern once per Write instead of once per byte.
done := true
for _, pp := range h.Patterns {
if pp.Match {
continue
}
for _, pp := range h.Patterns {
if bytes.Contains(h.buff, pp.Pattern) {
pp.Match = true
done := true
for _, ppp := range h.Patterns {
if !ppp.Match {
done = false
break
}
}
if done {
h.done = true
}
return len(p), nil
}
if bytes.Contains(p, pp.Pattern) || bytes.Contains(boundary, pp.Pattern) {
pp.Match = true
continue
}
done = false
}
if done {
// All patterns found; no need to look at any more data.
h.done = true
h.buff = nil
return len(p), nil
}
// Retain the last keep bytes of (previous tail + this chunk) to detect a
// pattern straddling into the next Write.
switch {
case keep <= 0:
h.buff = h.buff[:0]
case len(p) >= keep:
h.buff = append(h.buff[:0], p[len(p)-keep:]...)
default:
// Chunk shorter than keep: slide the window over the retained tail.
if total := len(h.buff) + len(p); total > keep {
h.buff = h.buff[total-keep:]
}
h.buff = append(h.buff, p...)
}
return len(p), nil
+58
View File
@@ -65,3 +65,61 @@ func TestHasBytesWriter(t *testing.T) {
fmt.Fprintf(w, "__foo")
c.Assert(h.Patterns[0].Match, qt.Equals, true)
}
func TestHasBytesWriterMultiplePatterns(t *testing.T) {
c := qt.New(t)
neww := func() (*HasBytesWriter, io.Writer) {
var b bytes.Buffer
h := &HasBytesWriter{
Patterns: []*HasBytesPattern{
{Pattern: []byte("__hdeferred/")},
{Pattern: []byte("__h_pp_l1")},
},
}
return h, io.MultiWriter(&b, h)
}
// Neither pattern present.
h, w := neww()
fmt.Fprint(w, "the quick brown fox jumps over the lazy dog")
c.Assert(h.Patterns[0].Match, qt.Equals, false)
c.Assert(h.Patterns[1].Match, qt.Equals, false)
c.Assert(h.done, qt.Equals, false)
// Only the second pattern present; the writer must not report a match
// for the first, and must not prematurely mark itself done.
h, w = neww()
fmt.Fprint(w, "prefix __h_pp_l1 suffix")
c.Assert(h.Patterns[0].Match, qt.Equals, false)
c.Assert(h.Patterns[1].Match, qt.Equals, true)
c.Assert(h.done, qt.Equals, false)
// Both patterns present across multiple writes; done once all match.
h, w = neww()
fmt.Fprint(w, "aaa __hdef")
fmt.Fprint(w, "erred/xyz bbb __h_p")
fmt.Fprint(w, "p_l1 ccc")
c.Assert(h.Patterns[0].Match, qt.Equals, true)
c.Assert(h.Patterns[1].Match, qt.Equals, true)
c.Assert(h.done, qt.Equals, true)
}
func BenchmarkHasBytesWriter(b *testing.B) {
// A large chunk of output containing neither pattern is the common case
// (a normal rendered page): the writer must scan all of it.
content := []byte(strings.Repeat("<div class=\"nav\"><a href=\"/foo/bar\">baz</a></div>\n", 4000))
b.ResetTimer()
for range b.N {
h := &HasBytesWriter{
Patterns: []*HasBytesPattern{
{Pattern: []byte("__hdeferred/")},
{Pattern: []byte("__h_pp_l1")},
},
}
if _, err := h.Write(content); err != nil {
b.Fatal(err)
}
}
}
+7 -2
View File
@@ -33,6 +33,7 @@ import (
"github.com/gohugoio/hugo/common/loggers"
"github.com/gohugoio/hugo/common/version"
"github.com/gohugoio/hugo/hugofs/files"
"github.com/gohugoio/hugo/internal/warpc"
"github.com/spf13/afero"
@@ -211,7 +212,10 @@ func GetDependencyList() []string {
// GetDependencyListNonGo returns a list of non-Go dependencies.
func GetDependencyListNonGo() []string {
deps := []string{formatDep("github.com/webmproject/libwebp", "v1.6.0")} // via WASM. TODO(bep) get versions from the plugin setup.
var deps []string
for _, dep := range warpc.GetWASMDeps() {
deps = append(deps, formatDep(dep[0], dep[1]))
}
if IsExtended {
deps = append(
@@ -225,7 +229,8 @@ func GetDependencyListNonGo() []string {
if IsDartSassGeV2() {
dartSassPath = "github.com/sass/dart-sass"
}
deps = append(deps,
deps = append(
deps,
formatDep(dartSassPath+"/protocol", dartSass.ProtocolVersion),
formatDep(dartSassPath+"/compiler", dartSass.CompilerVersion),
formatDep(dartSassPath+"/implementation", dartSass.ImplementationVersion),
+2 -2
View File
@@ -35,8 +35,8 @@ func TestDeprecationLogLevelFromVersion(t *testing.T) {
c.Assert(deprecationLogLevelFromVersion(ver.String()), qt.Equals, logg.LevelError)
// Added just to find the threshold for where we can remove deprecated items.
// Subtract 5 from the minor version of the first ERRORed version => 0.136.0.
c.Assert(deprecationLogLevelFromVersion("0.141.0"), qt.Equals, logg.LevelError)
// Subtract 5 from the minor version of the first ERRORed version => 0.145.0.
c.Assert(deprecationLogLevelFromVersion("0.150.0"), qt.Equals, logg.LevelError)
}
func TestMarkupScope(t *testing.T) {
+2 -2
View File
@@ -19,7 +19,7 @@ import "github.com/gohugoio/hugo/common/version"
// This should be the only one.
var CurrentVersion = version.Version{
Major: 0,
Minor: 163,
PatchLevel: 3,
Minor: 165,
PatchLevel: 0,
Suffix: "",
}
-30
View File
@@ -458,36 +458,6 @@ func (c *Config) CompileConfig(logger loggers.Logger) error {
}
}
// Legacy privacy values.
if c.Privacy.Twitter.Disable {
hugo.DeprecateWithLogger("project config key privacy.twitter.disable", "Use privacy.x.disable instead.", "v0.141.0", logger.Logger())
c.Privacy.X.Disable = c.Privacy.Twitter.Disable
}
if c.Privacy.Twitter.EnableDNT {
hugo.DeprecateWithLogger("project config key privacy.twitter.enableDNT", "Use privacy.x.enableDNT instead.", "v0.141.0", logger.Logger())
c.Privacy.X.EnableDNT = c.Privacy.Twitter.EnableDNT
}
if c.Privacy.Twitter.Simple {
hugo.DeprecateWithLogger("project config key privacy.twitter.simple", "Use privacy.x.simple instead.", "v0.141.0", logger.Logger())
c.Privacy.X.Simple = c.Privacy.Twitter.Simple
}
// Legacy services values.
if c.Services.Twitter.DisableInlineCSS {
hugo.DeprecateWithLogger("project config key services.twitter.disableInlineCSS", "Use services.x.disableInlineCSS instead.", "v0.141.0", logger.Logger())
c.Services.X.DisableInlineCSS = c.Services.Twitter.DisableInlineCSS
}
// Legacy permalink tokens
for _, pc := range c.Permalinks {
if strings.Contains(pc.Pattern, ":filename") {
hugo.DeprecateWithLogger("the \":filename\" permalink token", "Use \":contentbasename\" instead.", "0.144.0", logger.Logger())
}
if strings.Contains(pc.Pattern, ":slugorfilename") {
hugo.DeprecateWithLogger("the \":slugorfilename\" permalink token", "Use \":slugorcontentbasename\" instead.", "0.144.0", logger.Logger())
}
}
// Legacy render hook values.
alternativeDetails := fmt.Sprintf(
"Set to %q if previous value was false, or set to %q if previous value was true.",
@@ -25,11 +25,13 @@ weight = 2
[[module.mounts]]
source = 'content/en'
target = 'content'
lang = 'en'
[module.mounts.sites.matrix]
languages = 'en'
[[module.mounts]]
source = 'content/sv'
target = 'content'
lang = 'sv'
[module.mounts.sites.matrix]
languages = 'sv'
-- content/en/p1.md --
---
title: "p1"
+8 -4
View File
@@ -19,19 +19,23 @@ defaultContentLanguage = 'en'
[[module.mounts]]
source = 'content/en'
target = 'content/en'
lang = 'en'
[module.mounts.sites.matrix]
languages = 'en'
[[module.mounts]]
source = 'content/nn'
target = 'content/nn'
lang = 'nn'
[module.mounts.sites.matrix]
languages = 'nn'
[[module.mounts]]
source = 'content/no'
target = 'content/no'
lang = 'no'
[module.mounts.sites.matrix]
languages = 'no'
[[module.mounts]]
source = 'content/sv'
target = 'content/sv'
lang = 'sv'
[module.mounts.sites.matrix]
languages = 'sv'
[[module.mounts]]
source = 'layouts'
target = 'layouts'
-14
View File
@@ -30,7 +30,6 @@ type Config struct {
Disqus Disqus
GoogleAnalytics GoogleAnalytics
Instagram Instagram
Twitter Twitter `json:"-"` // deprecated in favor of X in v0.141.0
Vimeo Vimeo
YouTube YouTube
X X
@@ -59,19 +58,6 @@ type Instagram struct {
Simple bool
}
// Twitter holds the privacy configuration settings related to the Twitter shortcode.
// Deprecated in favor of X in v0.141.0.
type Twitter struct {
Service `mapstructure:",squash"`
// When set to true, the Tweet and its embedded page on your site are not used
// for purposes that include personalized suggestions and personalized ads.
EnableDNT bool
// If simple mode is enabled, a static and no-JS version of the Tweet will be built.
Simple bool
}
// Vimeo holds the privacy configuration settings related to the Vimeo shortcode.
type Vimeo struct {
Service `mapstructure:",squash"`
+4 -5
View File
@@ -39,12 +39,11 @@ const securityConfigKey = "security"
var DefaultConfig = Config{
Exec: Exec{
Allow: MustNewWhitelist(
"^(dart-)?sass(-embedded)?$", // sass, dart-sass, dart-sass-embedded.
"^go$", // for Go Modules
"^git$", // For Git info
"^node$", // Used as the runtime for Node tools.
"^(dart-)?sass$", // sass, dart-sass
"^go$", // for Go Modules
"^git$", // For Git info
"^node$", // Used as the runtime for Node tools.
"^postcss$",
"^tailwindcss$",
),
// These have been tested to work with Hugo's external programs
// on Windows, Linux and MacOS.
+1 -1
View File
@@ -135,7 +135,7 @@ func TestToTOML(t *testing.T) {
got := DefaultConfig.ToTOML()
c.Assert(got, qt.Equals,
"[security]\n allowContent = ['! ^text/html$']\n enableInlineShortcodes = false\n\n [security.exec]\n allow = ['^(dart-)?sass(-embedded)?$', '^go$', '^git$', '^node$', '^postcss$', '^tailwindcss$']\n osEnv = ['(?i)^((HTTPS?|NO)_PROXY|PATH(EXT)?|APPDATA|TE?MP|TERM|GO\\w+|(XDG_CONFIG_)?HOME|USERPROFILE|SSH_AUTH_SOCK|DISPLAY|LANG|SYSTEMDRIVE|PROGRAMDATA)$']\n\n [security.funcs]\n getenv = ['^HUGO_', '^CI$']\n\n [security.http]\n methods = ['(?i)GET|POST']\n urls = ['(?i)^https?://[a-z0-9]', '! ^https?://\\d+\\.', '! (?i)localhost', '! (?i)^https?://[^/?#]*@']\n\n [security.node]\n [security.node.permissions]\n allowAddons = ['tailwindcss']\n allowChildProcess = ['tailwindcss']\n allowRead = ['.']\n allowWorker = ['tailwindcss']\n allowWrite = []\n disable = false",
"[security]\n allowContent = ['! ^text/html$']\n enableInlineShortcodes = false\n\n [security.exec]\n allow = ['^(dart-)?sass$', '^go$', '^git$', '^node$', '^postcss$']\n osEnv = ['(?i)^((HTTPS?|NO)_PROXY|PATH(EXT)?|APPDATA|TE?MP|TERM|GO\\w+|(XDG_CONFIG_)?HOME|USERPROFILE|SSH_AUTH_SOCK|DISPLAY|LANG|SYSTEMDRIVE|PROGRAMDATA)$']\n\n [security.funcs]\n getenv = ['^HUGO_', '^CI$']\n\n [security.http]\n methods = ['(?i)GET|POST']\n urls = ['(?i)^https?://[a-z0-9]', '! ^https?://\\d+\\.', '! (?i)localhost', '! (?i)^https?://[^/?#]*@']\n\n [security.node]\n [security.node.permissions]\n allowAddons = ['tailwindcss']\n allowChildProcess = ['tailwindcss']\n allowRead = ['.']\n allowWorker = ['tailwindcss']\n allowWrite = []\n disable = false",
)
}
-10
View File
@@ -31,7 +31,6 @@ type Config struct {
Disqus Disqus
GoogleAnalytics GoogleAnalytics
Instagram Instagram `json:"-"` // the embedded instagram shortcode no longer uses this
Twitter Twitter `json:"-"` // deprecated in favor of X in v0.141.0
X X
RSS RSS
}
@@ -61,15 +60,6 @@ type Instagram struct {
AccessToken string // this is no longer used by the embedded instagram shortcode
}
// Twitter holds the functional configuration settings related to the Twitter shortcodes.
// Deprecated in favor of X in v0.141.0.
type Twitter struct {
// The Simple variant of Twitter is decorated with a basic set of inline styles.
// This means that if you want to provide your own CSS, you want
// to disable the inline CSS provided by Hugo.
DisableInlineCSS bool
}
// X holds the functional configuration settings related to the X shortcodes.
type X struct {
// The Simple variant of X is decorated with a basic set of inline styles.
+37 -6
View File
@@ -74,7 +74,6 @@ func TestNewContentFromFile(t *testing.T) {
c := qt.New(t)
for i, cas := range cases {
c.Run(cas.name, func(c *qt.C) {
c.Parallel()
@@ -109,7 +108,6 @@ func TestNewContentFromFile(t *testing.T) {
}
}
})
}
}
@@ -159,6 +157,37 @@ site RegularPages: {{ len site.RegularPages }}
cContains(c, readFileFromFs(t, fs.Source, filepath.Join("content", "mypage.md")), `draft: true`)
}
// See issue 15078.
func TestNewContentWithBuildCascade(t *testing.T) {
t.Parallel()
mm := afero.NewMemMapFs()
c := qt.New(t)
c.Assert(initFs(mm), qt.IsNil)
c.Assert(mm.MkdirAll(filepath.Join("content", "posts", "drafts"), 0o755), qt.IsNil)
c.Assert(afero.WriteFile(mm, filepath.Join("content", "posts", "drafts", "_index.md"), []byte(`---
title: Drafts
build:
render: never
cascade:
draft: true
build:
render: link
draft: true
---
`), 0o755), qt.IsNil)
cfg, fs := newTestCfg(c, mm)
conf := testconfig.GetTestConfigs(fs.Source, cfg)
h, err := hugolib.NewHugoSites(deps.DepsCfg{Configs: conf, Fs: fs})
c.Assert(err, qt.IsNil)
const target = "posts/drafts/trip-to-puebla/index.md"
c.Assert(create.NewContent(h, "", target, false), qt.IsNil)
c.Assert(readFileFromFs(c, fs.Source, filepath.Join("content", target)), qt.Contains, `title: "Trip to Puebla"`)
}
func initFs(fs afero.Fs) error {
perm := os.FileMode(0o755)
var err error
@@ -308,10 +337,10 @@ theme = "mytheme"
[languages]
[languages.en]
weight = 1
languageName = "English"
label = "English"
[languages.nn]
weight = 2
languageName = "Nynorsk"
label = "Nynorsk"
[module]
[[module.mounts]]
@@ -320,11 +349,13 @@ languageName = "Nynorsk"
[[module.mounts]]
source = 'content'
target = 'content'
lang = 'en'
[module.mounts.sites.matrix]
languages = 'en'
[[module.mounts]]
source = 'content_nn'
target = 'content'
lang = 'nn'
[module.mounts.sites.matrix]
languages = 'nn'
`
if mm == nil {
mm = afero.NewMemMapFs()
+1 -1
View File
@@ -1,7 +1,7 @@
---
title: {{ replace .File.ContentBaseName "-" " " }}
params:
reference:
reference:
---
<!--
@@ -8,7 +8,7 @@ _comment: Do not remove front matter.
```go-html-template
{{ $js := resources.Get "js/main.js" | js.Build (dict "params" (dict "api" "https://example.org/api")) }}
```
And then in your JS file:
```js
@@ -34,7 +34,7 @@ Time zone offsets|`"Z0700" "Z07:00" "Z07" "Z070000" "Z07:00:00"`
{{ $t = time.AsTime $t }}
{{ $t = $t.Format "Jan 02, 2006 3:04 PM Z07:00" }}
{{ $t }} → Jan 27, 2023 11:44 PM -08:00
{{ $t }} → Jan 27, 2023 11:44 PM -08:00
```
Strings such as `PST` and `CET` are not time zones. They are time zone _abbreviations_.
+1 -1
View File
@@ -8,7 +8,7 @@ weight: 40
## Apache License
_Version 2.0, January 2004_
_Version 2.0, January 2004_
_<http://www.apache.org/licenses/>_
### Terms and Conditions for use, reproduction, and distribution
+1 -1
View File
@@ -1,6 +1,6 @@
---
title: Security model
linkTitle: Security
linkTitle: Security
description: A summary of Hugo's security model.
categories: []
keywords: []
@@ -112,7 +112,7 @@ The most common front matter fields are `date`, `draft`, `title`, and `weight`,
: (`map`) A map to define [sites matrix](g) and [sites complements](g) for the page.
<!-- markdownlint-disable MD049 -->
{{< code-toggle file=content/_index.md fm=true >}}
title = 'Home'
[sites.matrix]
+1 -1
View File
@@ -18,5 +18,5 @@ Try to use the same language (e.g., tagline) everywhere:
- Home: https://gohugo.io/
- Docs: https://gohugo.io/documentation/
- Project repo: https://github.com/gohugoio/hugo?tab=readme-ov-file#readme
- Docs repo: https://github.com/gohugoio/hugoDocs?tab=readme-ov-file#readme
- Docs repo: https://github.com/gohugoio/hugoDocs?tab=readme-ov-file#readme
-->
@@ -7,7 +7,7 @@ params:
functions_and_methods:
aliases: [append]
returnType: '[]any'
signatures:
signatures:
- collections.Append ELEMENT [ELEMENT...] SLICE
- collections.Append SLICE1 SLICE2
aliases: [/functions/append]
+1 -1
View File
@@ -47,7 +47,7 @@ The example above generates the _same_ random numbers each time it is called. To
When `N` is greater than `HIGH`, this function returns the full, sorted range [0, `HIGH`) of size `HIGH`:
```go-html-template
{{ collections.D 6 42 7 }} → [0 1 2 3 4 5 6]
{{ collections.D 6 42 7 }} → [0 1 2 3 4 5 6]
```
A common use case is the selection of random pages from a page collection. For example, to render a list of 5 random pages using the [day of the year][] as the seed value:
@@ -12,7 +12,7 @@ aliases: [/functions/shuffle]
---
```go-html-template
{{ collections.Shuffle (slice "a" "b" "c") }} → [b a c]
{{ collections.Shuffle (slice "a" "b" "c") }} → [b a c]
```
The result will vary from one build to the next.
@@ -8,7 +8,7 @@ params:
aliases: [union]
returnType: '[]any'
signatures: [collections.Union SLICE1 SLICE2]
aliases: [/functions/union]
aliases: [/functions/union]
---
@@ -1,5 +1,5 @@
---
title: collections.Where
title: collections.Where
description: Returns a slice by filtering the given slice based on a key, operator, and value.
categories: []
keywords: []
@@ -320,7 +320,7 @@ This template:
Is rendered to:
```html
<ul>
<ul>
<li><a href="/posts/post-2/">Post 2</a></li>
</ul>
```
+36
View File
@@ -0,0 +1,36 @@
---
title: crypto.Hash
description: Hashes the given input with the given algorithm and returns its checksum encoded to a hexadecimal string.
categories: []
keywords: []
params:
functions_and_methods:
aliases: []
returnType: string
signatures: ['crypto.Hash [ALGORITHM] INPUT']
---
The `ALGORITHM` is one of `md5`, `sha1`, `sha256` (the default), `sha384`, or `sha512`:
```go-html-template
{{ crypto.Hash "sha256" "Hello world" }} → 64ec88ca00b268e5ba1a35678a1b5316d212f4f366b2477232534a8aeca37f3c
{{ "Hello world" | crypto.Hash "sha512" }} → b7f783baed8297f0db917462184ff4f08e69c2d5e5f79a942600f9725f58ce1f29c18139bf80b06c0fff2bdd34738452ecf40c488c22a7e3d80cdf6f9c1c0d47
```
If you omit the algorithm, it defaults to `sha256`:
```go-html-template
{{ "Hello world" | crypto.Hash }} → 64ec88ca00b268e5ba1a35678a1b5316d212f4f366b2477232534a8aeca37f3c
```
The supported algorithms match those used for the [Subresource Integrity] hash in [`.Data.Integrity`] on a fingerprinted resource. Combine `crypto.Hash` with [`encoding.HexDecode`] and [`encoding.Base64Encode`] to construct an SRI hash from a string:
```go-html-template
{{ $algo := "sha256" }}
{{ $integrity := printf "%s-%s" $algo ("Hello world" | crypto.Hash $algo | encoding.HexDecode | encoding.Base64Encode) }}
```
[Subresource Integrity]: https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity
[`.Data.Integrity`]: /methods/resource/data/
[`encoding.HexDecode`]: /functions/encoding/hexdecode/
[`encoding.Base64Encode`]: /functions/encoding/base64encode/
+5 -5
View File
@@ -175,12 +175,12 @@ The `css.Build` function accepts an options map to fine-tune bundling, minificat
`vars`
: {{< new-in 0.160.0 />}}
: (`map`) A map of key-value pairs used to generate CSS variables. The `css.Build` function injects these variables into the stylesheet when it encounters the `hugo:vars` internal identifier within an `@import` statement.
```go-html-template
{{ $vars := dict
"font-family" "\"Times New Roman\", Times, serif"
"font-size" "24px"
"primary-color" "blue"
"font-size" "24px"
"primary-color" "blue"
}}
{{ $opts := dict "vars" $vars }}
{{ $r := resources.Get "css/main.css" | css.Build $opts }}
@@ -226,9 +226,9 @@ The `css.Build` function accepts an options map to fine-tune bundling, minificat
"font-family" "\"Times New Roman\", Times, serif"
"font-size" "24px"
"primary-color" "blue"
"mobile" (dict
"mobile" (dict
"font-size" "12px"
"primary-color" "red"
"primary-color" "red"
)
}}
{{ $opts := dict "vars" $vars }}
+7 -7
View File
@@ -33,7 +33,7 @@ The `css.Sass` function accepts an options map.
```go-html-template
{{ $opts := dict
"transpiler" "dartsass"
"enableSourceMap" true
"enableSourceMap" true
}}
{{ $r := resources.Get "sass/main.scss" | css.Sass $opts }}
```
@@ -66,7 +66,7 @@ The `css.Sass` function accepts an options map.
```go-html-template
{{ $opts := dict
"transpiler" "dartsass"
"precision" 10
"precision" 10
}}
{{ $r := resources.Get "sass/main.scss" | css.Sass $opts }}
```
@@ -131,10 +131,10 @@ The `css.Sass` function accepts an options map.
```go-html-template
{{ $vars := dict
"font-family" "\"Times New Roman\", Times, serif"
"font-size" "24px"
"font-size" "24px"
"primary-color" "blue"
}}
{{ $opts := dict
{{ $opts := dict
"transpiler" "dartsass"
"vars" $vars
}}
@@ -172,12 +172,12 @@ The `css.Sass` function accepts an options map.
"font-family" "\"Times New Roman\", Times, serif"
"font-size" "24px"
"primary-color" "blue"
"mobile" (dict
"mobile" (dict
"font-size" "12px"
"primary-color" "red"
)
}}
{{ $opts := dict
{{ $opts := dict
"transpiler" "dartsass"
"vars" $vars
}}
@@ -235,7 +235,7 @@ The `css.Sass` function accepts an options map.
{{< /code-toggle >}}
```go-html-template
{{ $opts := dict
{{ $opts := dict
"transpiler" "dartsass"
"vars" site.Params.theme.style }}
{{ $r := resources.Get "sass/main.scss" | css.Sass $opts }}
+1 -1
View File
@@ -7,7 +7,7 @@ params:
functions_and_methods:
aliases: []
returnType: debug.Timer
signatures: [debug.Timer NAME]
signatures: [debug.Timer NAME]
---
Use the `debug.Timer` function to determine execution time for a block of code, useful for finding performance bottlenecks in templates.
@@ -0,0 +1,15 @@
---
title: encoding.HexDecode
description: Returns the hexadecimal decoding of the given content.
categories: []
keywords: []
params:
functions_and_methods:
aliases: []
returnType: string
signatures: [encoding.HexDecode INPUT]
---
```go-html-template
{{ "48656c6c6f20776f726c64" | encoding.HexDecode }} → Hello world
```
@@ -0,0 +1,15 @@
---
title: encoding.HexEncode
description: Returns the hexadecimal encoding of the given content.
categories: []
keywords: []
params:
functions_and_methods:
aliases: []
returnType: string
signatures: [encoding.HexEncode INPUT]
---
```go-html-template
{{ "Hello world" | encoding.HexEncode }} → 48656c6c6f20776f726c64
```
+1 -1
View File
@@ -1,6 +1,6 @@
---
title: Fmt functions
linkTitle: fmt
linkTitle: fmt
description: Use these functions to print strings within a template or to print messages to the terminal.
categories: []
keywords: []
+1 -1
View File
@@ -6,7 +6,7 @@ keywords: []
params:
functions_and_methods:
aliases: []
returnType:
returnType:
signatures: [page]
aliases: [/functions/page]
---
+1 -1
View File
@@ -6,7 +6,7 @@ keywords: []
params:
functions_and_methods:
aliases: []
returnType:
returnType:
signatures: [site]
aliases: [/functions/site]
---
@@ -37,7 +37,7 @@ Use with the [`range`][] statement:
```go-html-template
{{ $var := slice 1 2 3 }}
{{ range $var }}
{{ . }} → 1 2 3
{{ . }} → 1 2 3
{{ else }}
{{ print "var is falsy" }}
{{ end }}
+1 -1
View File
@@ -33,7 +33,7 @@ Use with the [`range`][] statement:
```go-html-template
{{ $var := slice 1 2 3 }}
{{ range $var }}
{{ . }} → 1 2 3
{{ . }} → 1 2 3
{{ end }}
```
@@ -6,7 +6,7 @@ keywords: []
params:
functions_and_methods:
aliases: []
returnType:
returnType:
signatures: [range COLLECTION]
aliases: [/functions/range]
---
@@ -47,7 +47,7 @@ With this contrived example:
```go-html-template
{{ $s := slice "foo" "bar" "baz" }}
{{ range $s }}
{{ .Title }}
{{ .Title }}
{{ end }}
```
@@ -67,7 +67,7 @@ This template will render the page title three times:
```go-html-template
{{ $s := slice "foo" "bar" "baz" }}
{{ range $s }}
{{ $.Title }}
{{ $.Title }}
{{ end }}
```
@@ -6,7 +6,7 @@ keywords: []
params:
functions_and_methods:
aliases: []
returnType:
returnType:
signatures: ['template NAME [CONTEXT]']
---
+1 -1
View File
@@ -11,5 +11,5 @@ params:
---
```go-html-template
{{ hugo.Generator }} → <meta name="generator" content="Hugo 0.163.2">
{{ hugo.Generator }} → <meta name="generator" content="Hugo 0.163.3">
```
@@ -5,7 +5,7 @@ categories: []
keywords: []
params:
functions_and_methods:
aliases: []
aliases: []
returnType: bool
signatures: [hugo.IsMultilingual]
---
+1 -1
View File
@@ -11,5 +11,5 @@ params:
---
```go-html-template
{{ hugo.Version }} → 0.163.2
{{ hugo.Version }} → 0.163.3
```
+3 -3
View File
@@ -56,8 +56,8 @@ Specify `level`, `scale`, and `targetDir` as needed to achieve the desired resul
```go-html-template
{{ $text := "https://gohugo.io" }}
{{ $opts := dict
"level" "high"
{{ $opts := dict
"level" "high"
"scale" 3
"targetDir" "images/qr"
}}
@@ -94,7 +94,7 @@ Then hide the QR code with CSS unless printing the page:
/* Show QR code when printing */
@media print {
.qr-code {
display: block;
display: block;
}
}
```
@@ -45,9 +45,9 @@ The "footer" partial renders the site footer. In this contrived example, the foo
You can pass anything in context: a page, a page collection, a scalar value, a slice, or a map. In this example we pass the current page and three scalar values:
```go-html-template
{{ $ctx := dict
{{ $ctx := dict
"page" .
"name" "John Doe"
"name" "John Doe"
"major" "Finance"
"gpa" 4.0
}}
@@ -19,7 +19,7 @@ Let's say you need to publish a file named "site.json" in the root of your `publ
```json
{
"build_date": "2026-04-04T10:46:21-07:00",
"hugo_version": "0.163.2",
"hugo_version": "0.163.3",
"last_modified": "2026-04-04T10:46:26-07:00"
}
```
@@ -84,7 +84,7 @@ To post data:
{{ $url := "https://example.org/api" }}
{{ $opts := dict
"method" "post"
"body" `{"complete": true}`
"body" `{"complete": true}`
"headers" (dict "Content-Type" "application/json")
}}
{{ $resource := resources.GetRemote $url $opts }}
@@ -94,7 +94,7 @@ To override the default cache key:
```go-html-template
{{ $url := "https://example.org/images/a.jpg" }}
{{ $opts := dict
{{ $opts := dict
"key" (print $url (now.Format "2006-01-02"))
}}
{{ $resource := resources.GetRemote $url $opts }}
@@ -109,9 +109,9 @@ Default is `production` for `hugo build` and `development` for `hugo server`.
`HUGO_FILE_X`
: Hugo automatically mounts the following files from your project's root directory under `assets/_jsconfig`:
- `babel.config.js`
- `postcss.config.js`
- `tailwind.config.js`
- `babel.config.js`, `babel.config.mjs`, `babel.config.cjs`
- `postcss.config.js`, `postcss.config.mjs`, `postcss.config.cjs`
- `tailwind.config.js`, `tailwind.config.mjs`, `tailwind.config.cjs`
For each file, Hugo creates a corresponding environment variable named `HUGO_FILE_:filename:`, where `:filename:` is the uppercase version of the filename with periods replaced by underscores. This allows you to access these files within your JavaScript, for example:
@@ -1,5 +1,5 @@
---
title: transform.Emojify
title: transform.Emojify
description: Runs a string through the Emoji emoticons processor.
categories: []
keywords: []
@@ -6,7 +6,7 @@ keywords: [highlight]
params:
functions_and_methods:
aliases: []
returnType: highlight.HighlightResult
returnType: highlight.HighlightResult
signatures: ['transform.HighlightCodeBlock CONTEXT [OPTIONS]']
---
@@ -119,7 +119,7 @@ Step 2
{{- end }}
{{- end -}}
```
Step 3
: In your base template, conditionally include the KaTeX CSS within the head element.
+1 -1
View File
@@ -1,5 +1,5 @@
---
title: urls.AbsURL
title: urls.AbsURL
description: Returns an absolute URL.
categories: []
keywords: []
+1 -1
View File
@@ -1,5 +1,5 @@
---
title: urls.PathEscape
title: urls.PathEscape
description: Returns the given string, applying percent-encoding to special characters and reserved delimiters so it can be safely used as a segment within a URL path.
categories: []
keywords: []
@@ -1,5 +1,5 @@
---
title: urls.PathUnescape
title: urls.PathUnescape
description: Returns the given string, replacing all percent-encoded sequences with the corresponding unescaped characters.
categories: []
keywords: []
@@ -58,7 +58,7 @@ my-project/
├── archetypes/
│ └── default.md
├── assets/
├── config/
├── config/
│ └── _default/
│ └── hugo.toml
├── content/
@@ -115,7 +115,7 @@ Hugo creates a [unified file system](g), allowing you to mount two or more direc
```tree
home/
└── user/
├── my-project/
├── my-project/
│ ├── content/
│ │ ├── books/
│ │ │ ├── _index.md
@@ -125,7 +125,7 @@ home/
│ ├── themes/
│ │ └── my-theme/
│ └── hugo.toml
└── shared-content/
└── shared-content/
└── films/
├── _index.md
├── film-1.md
+1 -1
View File
@@ -82,7 +82,7 @@ hugo server
The [`hugo server`][] command builds your site and serves your pages using a minimal HTTP server. When you run `hugo server` it will display the URL of your local site:
```text
Web Server is available at http://localhost:1313/
Web Server is available at http://localhost:1313/
```
While the server is running, it watches your project directory for changes to assets, configuration, content, data, layouts, translations, and static files. When it detects a change, the server rebuilds your site and refreshes your browser using [LiveReload][].
@@ -8,11 +8,11 @@ aliases: [/hosting-and-deployment/deployment-with-rclone/]
## Assumptions
- A web host running a web server. This could be a shared hosting environment or a VPS.
- Access to your web host with any of the [protocols supported by rclone][], such as SFTP.
- A web host running a web server. This could be a shared hosting environment or a VPS
- Access to your web host with any of the [protocols supported by rclone][], such as SFTP
- A functional static website built with Hugo
- Deploying from an [Rclone][] compatible operating system
- You have [installed Rclone][].
- You have [installed Rclone][]
**NB**: You can remove `--interactive` in the commands below once you are comfortable with rclone, if you wish. Also, `--gc` and `--minify` are optional in the commands below.
@@ -8,7 +8,7 @@ aliases: [/hosting-and-deployment/deployment-with-rsync/]
## Assumptions
- A web host running a web server. This could be a shared hosting environment or a VPS.
- A web host running a web server. This could be a shared hosting environment or a VPS
- Access to your web host with SSH
- A functional static website built with Hugo
@@ -87,7 +87,7 @@ USER=my-user
HOST=my-server.com
DIR=my/directory/to/topologix.fr/ # the directory where your website files should go
hugo build && rsync -avz --delete public/ ${USER}@${HOST}:~/${DIR} # this will delete everything on the server that's not in the local public directory
hugo build && rsync -avz --delete public/ ${USER}@${HOST}:~/${DIR} # this will delete everything on the server that's not in the local public directory
exit 0
```

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Before

Width:  |  Height:  |  Size: 80 KiB

After

Width:  |  Height:  |  Size: 80 KiB

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 60 KiB

@@ -1,12 +1,12 @@
---
title: Host on AWS Amplify
description: Host your site on AWS Amplify.
description: Host your project on AWS Amplify.
categories: []
keywords: []
aliases: [/hosting-and-deployment/hosting-on-aws-amplify/]
---
Use these instructions to enable continuous deployment from a GitHub repository. The same general steps apply if you are using GitLab for version control.
Use these instructions to enable continuous deployment from a GitHub repository. The same general steps apply for other Git providers such as GitLab or Bitbucket.
{{% include "/_common/gitignore-public.md" %}}
@@ -14,89 +14,114 @@ Use these instructions to enable continuous deployment from a GitHub repository.
Please complete the following tasks before continuing:
1. [Create](https://aws.amazon.com/resources/create-account/) an AWS account
1. [Log in](https://console.aws.amazon.com/) to your AWS account
1. [Create](https://github.com/signup) a GitHub account
1. [Log in](https://github.com/login) to your GitHub account
1. [Create](https://github.com/new) a GitHub repository for your project
1. [Create](https://git-scm.com/docs/git-init) a local Git repository for your project with a [remote][] reference to your GitHub repository
1. Create a Hugo project within your local Git repository and test it with the `hugo server` command
1. Commit the changes to your local Git repository and push to your GitHub repository
1. [Create](https://aws.amazon.com/resources/create-account/) an AWS account.
1. [Log in](https://console.aws.amazon.com/) to your AWS account.
1. [Create](https://github.com/signup) a GitHub account.
1. [Log in](https://github.com/login) to your GitHub account.
1. [Create](https://github.com/new) a GitHub repository for your project.
1. [Create](https://git-scm.com/docs/git-init) a local Git repository for your project with a [remote][] reference to your GitHub repository.
1. Create a Hugo project within your local Git repository and test it with the `hugo server` command.
1. Commit the changes to your local Git repository and push to your GitHub repository.
## Procedure
This procedure will enable continuous deployment from a GitHub repository. The procedure is essentially the same if you are using GitLab or Bitbucket.
Step 1
: Create a file named `amplify.yml` in the root of your project.
```sh
touch amplify.yml
```
Step 2
: Copy and paste the YAML below into the file you created. Change the application versions and time zone as needed.
: Create an `amplify.yml` file in the root of your project, adjusting the tool versions and time zone as needed.
```yaml {file="amplify.yml" copy=true}
version: 1
env:
variables:
# Application versions
# Define tool versions
DART_SASS_VERSION: 1.101.0
GO_VERSION: 1.26.4
HUGO_VERSION: 0.163.2
# Time zone
HUGO_VERSION: 0.163.3
NODE_VERSION: 24.16.0
# Set the build time zone
TZ: Europe/Oslo
# Cache
HUGO_CACHEDIR: ${PWD}/.hugo
NPM_CONFIG_CACHE: ${PWD}/.npm
# Set the build cache directory
HUGO_CACHEDIR: ${PWD}/.cache/hugo
frontend:
phases:
preBuild:
commands:
# Create directory for user-specific executable files
- echo "Creating directory for user-specific executable files..."
# Create a temporary directory for downloads
- build_temp_dir=$(mktemp -d)
# Create a local tools directory
- mkdir -p "${HOME}/.local"
# Install Dart Sass
- echo "Installing Dart Sass ${DART_SASS_VERSION}..."
- curl -sLJO "https://github.com/sass/dart-sass/releases/download/${DART_SASS_VERSION}/dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz"
- tar -C "${HOME}/.local" -xf "dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz"
- rm "dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz"
- export PATH="${HOME}/.local/dart-sass:${PATH}"
- |
echo "Installing Dart Sass ${DART_SASS_VERSION}..."
curl -sfL --output-dir "${build_temp_dir}" -O "https://github.com/sass/dart-sass/releases/download/${DART_SASS_VERSION}/dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz"
tar -C "${HOME}/.local" -xf "${build_temp_dir}/dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz"
export PATH="${HOME}/.local/dart-sass:${PATH}"
# Install Go
- echo "Installing Go ${GO_VERSION}..."
- curl -sLJO "https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz"
- tar -C "${HOME}/.local" -xf "go${GO_VERSION}.linux-amd64.tar.gz"
- rm "go${GO_VERSION}.linux-amd64.tar.gz"
- export PATH="${HOME}/.local/go/bin:${PATH}"
- |
if [[ -f "go.mod" ]]; then
echo "Installing Go ${GO_VERSION}..."
curl -sfL --output-dir "${build_temp_dir}" -O "https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz"
tar -C "${HOME}/.local" -xf "${build_temp_dir}/go${GO_VERSION}.linux-amd64.tar.gz"
export PATH="${HOME}/.local/go/bin:${PATH}"
fi
# Install Hugo
- echo "Installing Hugo ${HUGO_VERSION}..."
- curl -sLJO "https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.tar.gz"
- mkdir "${HOME}/.local/hugo"
- tar -C "${HOME}/.local/hugo" -xf "hugo_extended_${HUGO_VERSION}_linux-amd64.tar.gz"
- rm "hugo_extended_${HUGO_VERSION}_linux-amd64.tar.gz"
- export PATH="${HOME}/.local/hugo:${PATH}"
- |
echo "Installing Hugo ${HUGO_VERSION}..."
curl -sfL --output-dir "${build_temp_dir}" -O "https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_${HUGO_VERSION}_linux-amd64.tar.gz"
mkdir -p "${HOME}/.local/hugo"
tar -C "${HOME}/.local/hugo" -xf "${build_temp_dir}/hugo_${HUGO_VERSION}_linux-amd64.tar.gz"
export PATH="${HOME}/.local/hugo:${PATH}"
# Verify installations
- echo "Verifying installations..."
- "echo Dart Sass: $(sass --version)"
- "echo Go: $(go version)"
- "echo Hugo: $(hugo version)"
- "echo Node.js: $(node --version)"
# Install Node.js
- |
if [[ -f "package-lock.json" ]]; then
echo "Installing Node.js ${NODE_VERSION}..."
curl -sfL --output-dir "${build_temp_dir}" -O "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.gz"
tar -C "${HOME}/.local" -xf "${build_temp_dir}/node-v${NODE_VERSION}-linux-x64.tar.gz"
export PATH="${HOME}/.local/node-v${NODE_VERSION}-linux-x64/bin:${PATH}"
fi
# Install Node.js dependencies
- echo "Installing Node.js dependencies..."
- "[[ -f package-lock.json || -f npm-shrinkwrap.json ]] && npm ci --prefer-offline || true"
# Log tool versions
- |
echo "Logging tool versions..."
command -v sass &> /dev/null && echo "Dart Sass: $(sass --version)" || echo "Dart Sass: not installed"
command -v go &> /dev/null && echo "Go: $(go version)" || echo "Go: not installed"
command -v hugo &> /dev/null && echo "Hugo: $(hugo version)" || echo "Hugo: not installed"
command -v node &> /dev/null && echo "Node.js: $(node --version)" || echo "Node.js: not installed"
# Configure Git
- echo "Configuring Git..."
- git config --global core.quotepath false
- |
echo "Configuring Git..."
git config --global core.quotepath false
# Fetch full Git history
- |
if [[ $(git rev-parse --is-shallow-repository) == true ]]; then
echo "Fetching full Git history..."
git fetch --unshallow
fi
# Initialize Git submodules
- |
if [[ -f .gitmodules ]]; then
echo "Initializing Git submodules..."
git submodule update --init --recursive
fi
# Install Node.js dependencies
- |
if [[ -f package-lock.json ]]; then
echo "Installing Node.js dependencies..."
npm ci
fi
build:
commands:
- echo "Building site..."
- echo "Building the project..."
- hugo build --gc --minify
artifacts:
baseDirectory: public
@@ -104,10 +129,19 @@ Step 2
- '**/*'
cache:
paths:
- ${HUGO_CACHEDIR}/**/*
- ${NPM_CONFIG_CACHE}/**/*
- .cache/hugo/**/*
```
Step 2
: In your project configuration, change the location of the image cache to the [`cacheDir`][] as shown below:
{{< code-toggle file=hugo copy=true >}}
[caches.images]
dir = ':cacheDir/images'
{{< /code-toggle >}}
See [configure file caches][] for more information.
Step 3
: Commit and push the change to your GitHub repository.
@@ -123,27 +157,27 @@ Step 4
Step 5
: Choose a source code provider, then press the **Next** button.
![screen capture](amplify-step-05.png)
![screen capture](amplify-01.png)
Step 6
: Authorize AWS Amplify to access your GitHub account.
![screen capture](amplify-step-06.png)
![screen capture](amplify-02.png)
Step 7
: Select your personal account or relevant organization.
![screen capture](amplify-step-07.png)
![screen capture](amplify-03.png)
Step 8
: Authorize access to one or more repositories.
![screen capture](amplify-step-08.png)
![screen capture](amplify-04.png)
Step 9
: Select a repository and branch, then press the **Next** button.
![screen capture](amplify-step-09.png)
![screen capture](amplify-05.png)
Step 10
: On the "App settings" page, scroll to the bottom then press the **Next** button. Amplify reads the `amplify.yml` file you created in Steps 1-3 instead of using the values on this page.
@@ -154,7 +188,9 @@ Step 11
Step 12
: When your site has finished deploying, press the **Visit deployed URL** button to view your published site.
![screen capture](amplify-step-11.png)
![screen capture](amplify-06.png)
[Amplify Console]: https://console.aws.amazon.com/amplify/apps
[`cacheDir`]: /configuration/all/#cachedir
[configure file caches]: /configuration/caches/
[remote]: https://git-scm.com/docs/git-remote
@@ -1,6 +1,6 @@
---
title: Host on Azure Static Web Apps
description: Host your site on Azure Static Web Apps.
description: Host your project on Azure Static Web Apps.
categories: []
keywords: []
aliases: [/hosting-and-deployment/hosting-on-azure-static-web-apps/]
@@ -1,11 +1,11 @@
---
title: Host on Cloudflare
description: Host your site on Cloudflare.
description: Host your project on Cloudflare.
categories: []
keywords: []
---
Use these instructions to enable continuous deployment from a GitHub repository. The same general steps apply if you are using GitLab for version control.
Use these instructions to enable continuous deployment from a GitHub repository. The same general steps apply for other Git providers such as GitLab or Bitbucket.
{{% include "/_common/gitignore-public.md" %}}
@@ -25,39 +25,53 @@ Please complete the following tasks before continuing:
## Procedure
Step 1
: Create a `wrangler.toml` file in the root of your project.
: Create a `wrangler.jsonc` file in the root of your project.
```toml {file="wrangler.toml" copy=true}
name = 'hosting-cloudflare-worker'
compatibility_date = '2025-07-31'
[build]
command = 'chmod a+x build.sh && ./build.sh'
[assets]
directory = './public'
not_found_handling = '404-page'
```jsonc {file="wrangler.jsonc" copy=true}
{
// Set this to the name of your project.
"name": "test",
// Set this to today's date in YYYY-MM-DD format.
"compatibility_date": "2026-06-19",
"build": {
"command": "chmod a+x build.sh && ./build.sh"
},
"assets": {
"directory": "./public",
"not_found_handling": "404-page"
}
}
```
Step 2
: Create a `build.sh` file in the root of your project.
: Create a `build.sh` file in the root of your project, adjusting the tool versions and time zone as needed.
```sh {file="build.sh" copy=true}
#!/usr/bin/env bash
#------------------------------------------------------------------------------
# @file
# Builds a Hugo site hosted on a Cloudflare Worker.
# Builds a Hugo project hosted on a Cloudflare Worker.
#------------------------------------------------------------------------------
# Exit on error, undefined variables, or pipe failures
set -euo pipefail
build_temp_dir=""
# Define tool versions
DART_SASS_VERSION=1.101.0
GO_VERSION=1.26.4
HUGO_VERSION=0.163.3
NODE_VERSION=24.16.0
# Set the build time zone
TZ=Europe/Oslo
# Set the build cache directory
HUGO_CACHEDIR="${PWD}/.cache/hugo"
# Perform cleanup
cleanup() {
if [[ -n "${build_temp_dir}" && -d "${build_temp_dir}" ]]; then
if [[ -n "${build_temp_dir:-}" && -d "${build_temp_dir}" ]]; then
rm -rf "${build_temp_dir}"
fi
}
@@ -66,75 +80,78 @@ Step 2
trap cleanup EXIT SIGINT SIGTERM
main() {
# Define tool versions
DART_SASS_VERSION=1.101.0
GO_VERSION=1.26.4
HUGO_VERSION=0.163.2
NODE_VERSION=24.16.0
# Export the build time zone
export TZ
# Set the build timezone
export TZ=Europe/Oslo
# Export the build cache directory
export HUGO_CACHEDIR
# Set the build cache directory
export HUGO_CACHEDIR="${PWD}/.cache/hugo_cache"
# Create and move into a temporary directory for downloads
# Create a temporary directory for downloads
build_temp_dir=$(mktemp -d)
pushd "${build_temp_dir}" > /dev/null
# Create the local tools directory
# Create a local tools directory
mkdir -p "${HOME}/.local"
# Install Dart Sass
echo "Installing Dart Sass ${DART_SASS_VERSION}..."
curl -sLO "https://github.com/sass/dart-sass/releases/download/${DART_SASS_VERSION}/dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz"
tar -C "${HOME}/.local" -xf "dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz"
curl -sfL --output-dir "${build_temp_dir}" -O "https://github.com/sass/dart-sass/releases/download/${DART_SASS_VERSION}/dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz"
tar -C "${HOME}/.local" -xf "${build_temp_dir}/dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz"
export PATH="${HOME}/.local/dart-sass:${PATH}"
# Install Go
echo "Installing Go ${GO_VERSION}..."
curl -sLO "https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz"
tar -C "${HOME}/.local" -xf "go${GO_VERSION}.linux-amd64.tar.gz"
export PATH="${HOME}/.local/go/bin:${PATH}"
if [[ -f "go.mod" ]]; then
echo "Installing Go ${GO_VERSION}..."
curl -sfL --output-dir "${build_temp_dir}" -O "https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz"
tar -C "${HOME}/.local" -xf "${build_temp_dir}/go${GO_VERSION}.linux-amd64.tar.gz"
export PATH="${HOME}/.local/go/bin:${PATH}"
fi
# Install Hugo
echo "Installing Hugo ${HUGO_VERSION}..."
curl -sLO "https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_${HUGO_VERSION}_linux-amd64.tar.gz"
curl -sfL --output-dir "${build_temp_dir}" -O "https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_${HUGO_VERSION}_linux-amd64.tar.gz"
mkdir -p "${HOME}/.local/hugo"
tar -C "${HOME}/.local/hugo" -xf "hugo_${HUGO_VERSION}_linux-amd64.tar.gz"
tar -C "${HOME}/.local/hugo" -xf "${build_temp_dir}/hugo_${HUGO_VERSION}_linux-amd64.tar.gz"
export PATH="${HOME}/.local/hugo:${PATH}"
# Install Node.js
echo "Installing Node.js ${NODE_VERSION}..."
curl -sLO "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.xz"
tar -C "${HOME}/.local" -xf "node-v${NODE_VERSION}-linux-x64.tar.xz"
export PATH="${HOME}/.local/node-v${NODE_VERSION}-linux-x64/bin:${PATH}"
if [[ -f "package-lock.json" ]]; then
echo "Installing Node.js ${NODE_VERSION}..."
curl -sfL --output-dir "${build_temp_dir}" -O "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.gz"
tar -C "${HOME}/.local" -xf "${build_temp_dir}/node-v${NODE_VERSION}-linux-x64.tar.gz"
export PATH="${HOME}/.local/node-v${NODE_VERSION}-linux-x64/bin:${PATH}"
fi
# Return to the project root
popd > /dev/null
# Verify installations
echo "Verifying installations..."
echo Dart Sass: "$(sass --version)"
echo Go: "$(go version)"
echo Hugo: "$(hugo version)"
echo Node.js: "$(node --version)"
# Log tool versions
echo "Logging tool versions..."
command -v sass &> /dev/null && echo "Dart Sass: $(sass --version)" || echo "Dart Sass: not installed"
command -v go &> /dev/null && echo "Go: $(go version)" || echo "Go: not installed"
command -v hugo &> /dev/null && echo "Hugo: $(hugo version)" || echo "Hugo: not installed"
command -v node &> /dev/null && echo "Node.js: $(node --version)" || echo "Node.js: not installed"
# Configure Git
echo "Configuring Git..."
git config --global core.quotepath false
if [ "$(git rev-parse --is-shallow-repository)" = "true" ]; then
# Fetch full Git history
if [[ $(git rev-parse --is-shallow-repository) == true ]]; then
echo "Fetching full Git history..."
git fetch --unshallow
fi
# Initialize Git submodules
if [[ -f .gitmodules ]]; then
echo "Initializing Git submodules..."
git submodule update --init --recursive
fi
# Install Node.js dependencies
if [ -f package-lock.json ]; then
if [[ -f package-lock.json ]]; then
echo "Installing Node.js dependencies..."
npm ci
fi
# Build the site
echo "Building the site..."
# Build the project
echo "Building the project..."
hugo build --gc --minify
}
@@ -142,39 +159,49 @@ Step 2
```
Step 3
: Commit the changes to your local Git repository and push to your GitHub repository.
: In your project configuration, change the location of the image cache to the [`cacheDir`][] as shown below:
{{< code-toggle file=hugo copy=true >}}
[caches.images]
dir = ':cacheDir/images'
{{< /code-toggle >}}
See [configure file caches][] for more information.
Step 4
: Commit the changes to your local Git repository and push to your GitHub repository.
Step 5
: In the upper right corner of the Cloudflare [dashboard][], press the **Add** button and select "Workers" from the drop down menu.
![screen capture](cloudflare-01.png)
Step 5
Step 6
: Verify your account if prompted.
![screen capture](cloudflare-02.png)
Step 6
Step 7
: On the "Create a Worker" page, under the "Ship something new" heading, press the **Connect GitHub** button.
![screen capture](cloudflare-03.png)
Step 7
Step 8
: Select the GitHub account where you want to install the Cloudflare Workers and Pages application.
![screen capture](cloudflare-04.png)
Step 8
Step 9
: Authorize the Cloudflare Workers and Pages application to access all repositories or only select repositories, then press the **Install & Authorize** button.
![screen capture](cloudflare-05.png)
Step 9
Step 10
: On the "Create a Worker" page, under the "Select a repository" heading, select the repository to deploy, then press the **Next** button.
![screen capture](cloudflare-06.png)
Step 10
Step 11
: On the "Create a Worker" page, under the "Set up your application" heading, perform the following steps:
1. Provide a **Project name**.
@@ -184,7 +211,7 @@ Step 10
1. In the **Variable value** field, enter `true`.
1. Press the **Deploy** button.
Step 11
Step 12
: Wait for the site to build and deploy, then press the **Visit** button in the upper left corner of your screen.
![screen capture](cloudflare-07.png)
@@ -193,13 +220,58 @@ In the future, whenever you push a change from your local Git repository, Cloudf
## Build cache
The build script shown in [Step 2](#step-2) sets Hugo's [cache directory][] to the path required by Cloudflare's build cache, which is disabled by default. To enable the Cloudflare build cache:
The build script shown in [Step 2](#step-2) sets Hugo's [`cacheDir`][] to the path required by Cloudflare's build cache, which is disabled by default. To enable the Cloudflare build cache, you must complete two steps.
First, your project must have both a `package.json` and `package-lock.json` file in the project root. If you have only a package.json file, run `npm install` to create the corresponding `package-lock.json` file. If your project does not require any Node.js packages, create both files by running `npm init -y && npm install`.
Second, you must enable the build cache in your project dashboard.
1. Navigate to Workers & Pages Overview on the [dashboard][].
1. Find your Workers project.
1. Go to **Settings** > **Build** > **Build cache**.
1. Go to **Settings**&nbsp;>&nbsp;**Build**&nbsp;>&nbsp;**Build cache**.
1. Press the **Enable** button.
[cache directory]: /configuration/all/#cache-directory
## Scheduled builds
If your site uses [`resources.GetRemote`][] to fetch external data at build time, that data is embedded in the static HTML when the site is built. Without a scheduled build, the data only refreshes when someone commits code to the repository. To keep content current, you can trigger a rebuild on a schedule by creating a Cloudflare deploy hook and calling it from a GitHub Actions workflow.
Step 1
: In the Cloudflare [dashboard][], go to **Workers & Pages**. Select your project, then navigate to **Settings**&nbsp;>&nbsp;**Builds**&nbsp;>&nbsp;**Deploy Hooks**. Press **Create deploy hook**, provide a name (e.g., `github-cron`), and copy the generated URL.
Step 2
: In your GitHub repository, go to **Settings**&nbsp;>&nbsp;**Secrets and variables**&nbsp;>&nbsp;**Actions**. Press **New repository secret**, name it `CLOUDFLARE_DEPLOY_HOOK`, paste the deploy hook URL as the value, and save.
Step 3
: Create a GitHub Actions workflow file in your repository.
```yaml {file=".github/workflows/scheduled-cloudflare-deploy.yaml" copy=true}
name: github-cron
on:
schedule:
- cron: "42 7 * * *"
timezone: Etc/UTC
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Trigger Cloudflare deploy hook
run: curl -X POST "${{ secrets.CLOUDFLARE_DEPLOY_HOOK }}"
```
Adjust the [`cron`][] expression to set your desired build schedule. In the example above, the job is scheduled to run every day at 7:42 AM UTC.
Step 4
: Commit the changes to your local Git repository and push to your GitHub repository.
> [!NOTE]
> The schedule event can be delayed during periods of high loads of GitHub Actions workflow runs. High load times include the start of every hour. If the load is sufficiently high enough, some queued jobs may be dropped. To decrease the chance of delay, schedule your workflow to run at a different time of the hour, or use a dedicated third-party scheduling service such as [Google Cloud Scheduler][] or [cron-job.org][].
[`cacheDir`]: /configuration/all/#cachedir
[`cron`]: https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows#schedule
[`resources.GetRemote`]: /functions/resources/getremote/
[configure file caches]: /configuration/caches/
[cron-job.org]: https://cron-job.org/en/
[dashboard]: https://dash.cloudflare.com/
[remote]: https://git-scm.com/docs/git-remote
[Google Cloud Scheduler]: https://docs.cloud.google.com/scheduler/docs/overview
@@ -1,6 +1,6 @@
---
title: Host on Firebase
description: Host your site on Firebase.
description: Host your project on Firebase.
categories: []
keywords: []
aliases: [/hosting-and-deployment/hosting-on-firebase/]
@@ -1,12 +1,12 @@
---
title: Host on GitHub Pages
description: Host your site on GitHub Pages.
description: Host your project on GitHub Pages.
categories: []
keywords: []
aliases: [/hosting-and-deployment/hosting-on-github/]
---
Use these instructions to enable continuous deployment from a GitHub repository using GitHub Actions.
Use these instructions to enable continuous deployment from a GitHub repository to GitHub Pages.
{{% include "/_common/gitignore-public.md" %}}
@@ -21,12 +21,12 @@ There are three types of GitHub Pages sites: project, user, and organization. Pr
Please complete the following tasks before continuing:
1. [Create](https://github.com/signup) a GitHub account
1. [Log in][] to your GitHub account
1. [Create](https://github.com/new) a GitHub repository for your project
1. [Create](https://git-scm.com/docs/git-init) a local Git repository for your project with a [remote][] reference to your GitHub repository
1. Create a Hugo project within your local Git repository and test it with the `hugo server` command
1. Commit the changes to your local Git repository and push to your GitHub repository
1. [Create](https://github.com/signup) a GitHub account.
1. [Log in][] to your GitHub account.
1. [Create](https://github.com/new) a GitHub repository for your project.
1. [Create](https://git-scm.com/docs/git-init) a local Git repository for your project with a [remote][] reference to your GitHub repository.
1. Create a Hugo project within your local Git repository and test it with the `hugo server` command.
1. Commit the changes to your local Git repository and push to your GitHub repository.
## Procedure
@@ -40,25 +40,7 @@ Step 1
![screen capture](gh-pages-02.png)
Step 2
: In your project configuration, change the location of the image cache to the [`cacheDir`][] as shown below:
{{< code-toggle file=hugo copy=true >}}
[caches.images]
dir = ':cacheDir/images'
{{< /code-toggle >}}
See [configure file caches][] for more information.
Step 3
: Create a file named `hugo.yaml` in a directory named `.github/workflows`.
```sh
mkdir -p .github/workflows
touch .github/workflows/hugo.yaml
```
Step 4
: Copy and paste the YAML below into the file you created.
: Create a `hugo.yaml` file in the `.github/workflows` directory, adjusting the tool versions and time zone as needed.
```yaml {file=".github/workflows/hugo.yaml" copy=true}
name: Build and deploy
@@ -81,10 +63,13 @@ Step 4
build:
runs-on: ubuntu-latest
env:
# Define tool versions
DART_SASS_VERSION: 1.101.0
GO_VERSION: 1.26.4
HUGO_VERSION: 0.163.2
HUGO_VERSION: 0.163.3
NODE_VERSION: 24.16.0
# Set the build time zone
TZ: Europe/Oslo
steps:
- name: Checkout
@@ -92,97 +77,140 @@ Step 4
with:
submodules: recursive
fetch-depth: 0
- name: Setup Go
- name: Setup Pages
id: pages
uses: actions/configure-pages@v6
- name: Create a local tools directory
run: |
mkdir -p "${HOME}/.local"
- name: Install Go
if: hashFiles('go.mod') != ''
uses: actions/setup-go@v6
with:
go-version: ${{ env.GO_VERSION }}
cache: false
- name: Setup Node.js
- name: Install Node.js
if: hashFiles('package-lock.json') != ''
uses: actions/setup-node@v6
with:
node-version: ${{ env.NODE_VERSION }}
- name: Setup Pages
id: pages
uses: actions/configure-pages@v6
- name: Create directory for user-specific executable files
run: |
mkdir -p "${HOME}/.local"
- name: Install Dart Sass
run: |
curl -sLJO "https://github.com/sass/dart-sass/releases/download/${DART_SASS_VERSION}/dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz"
tar -C "${HOME}/.local" -xf "dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz"
rm "dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz"
echo "Installing Dart Sass ${DART_SASS_VERSION}..."
curl -sfL --output-dir "${{ runner.temp }}" -O "https://github.com/sass/dart-sass/releases/download/${DART_SASS_VERSION}/dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz"
tar -C "${HOME}/.local" -xf "${{ runner.temp }}/dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz"
echo "${HOME}/.local/dart-sass" >> "${GITHUB_PATH}"
- name: Install Hugo
run: |
curl -sLJO "https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.tar.gz"
echo "Installing Hugo ${HUGO_VERSION}..."
curl -sfL --output-dir "${{ runner.temp }}" -O "https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.tar.gz"
mkdir "${HOME}/.local/hugo"
tar -C "${HOME}/.local/hugo" -xf "hugo_extended_${HUGO_VERSION}_linux-amd64.tar.gz"
rm "hugo_extended_${HUGO_VERSION}_linux-amd64.tar.gz"
tar -C "${HOME}/.local/hugo" -xf "${{ runner.temp }}/hugo_extended_${HUGO_VERSION}_linux-amd64.tar.gz"
echo "${HOME}/.local/hugo" >> "${GITHUB_PATH}"
- name: Verify installations
- name: Log tool versions
run: |
echo "Dart Sass: $(sass --version)"
echo "Go: $(go version)"
echo "Hugo: $(hugo version)"
echo "Node.js: $(node --version)"
- name: Install Node.js dependencies
run: |
[[ -f package-lock.json || -f npm-shrinkwrap.json ]] && npm ci || true
echo "Logging tool versions..."
command -v sass &> /dev/null && echo "Dart Sass: $(sass --version)" || echo "Dart Sass: not installed"
command -v go &> /dev/null && echo "Go: $(go version)" || echo "Go: not installed"
command -v hugo &> /dev/null && echo "Hugo: $(hugo version)" || echo "Hugo: not installed"
command -v node &> /dev/null && echo "Node.js: $(node --version)" || echo "Node.js: not installed"
- name: Configure Git
run: |
echo "Configuring Git..."
git config --global core.quotepath false
- name: Fetch full Git history
run: |
if [[ $(git rev-parse --is-shallow-repository) == true ]]; then
echo "Fetching full Git history..."
git fetch --unshallow
fi
- name: Initialize Git submodules
run: |
if [[ -f .gitmodules ]]; then
echo "Initializing Git submodules..."
git submodule update --init --recursive
fi
- name: Install Node.js dependencies
run: |
if [[ -f package-lock.json ]]; then
echo "Installing Node.js dependencies..."
npm ci
fi
- name: Cache restore
id: cache-restore
uses: actions/cache/restore@v5
with:
path: ${{ runner.temp }}/hugo_cache
key: hugo-${{ github.run_id }}
restore-keys:
hugo-
- name: Build the site
restore-keys: hugo-
- name: Build
run: |
echo "Building the project..."
hugo build \
--gc \
--minify \
--baseURL "${{ steps.pages.outputs.base_url }}/" \
--cacheDir "${{ runner.temp }}/hugo_cache"
- name: Cache save
id: cache-save
uses: actions/cache/save@v5
with:
path: ${{ runner.temp }}/hugo_cache
key: ${{ steps.cache-restore.outputs.cache-primary-key }}
- name: Upload artifact
uses: actions/upload-pages-artifact@v5
with:
include-hidden-files: false
path: ./public
deploy:
runs-on: ubuntu-latest
needs: build
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v5
```
Step 5
Step 3
: In your project configuration, change the location of the image cache to the [`cacheDir`][] as shown below:
{{< code-toggle file=hugo copy=true >}}
[caches.images]
dir = ':cacheDir/images'
{{< /code-toggle >}}
See [configure file caches][] for more information.
Step 4
: Commit the changes to your local Git repository and push to your GitHub repository.
Step 6
Step 5
: From GitHub's main menu, choose **Actions**. You will see something like this:
![screen capture](gh-pages-03.png)
Step 7
Step 6
: When GitHub has finished building and deploying your site, the color of the status indicator will change to green.
![screen capture](gh-pages-04.png)
Step 8
Step 7
: Click on the commit message as shown above. Under the deploy step, you will see a link to your live site.
![screen capture](gh-pages-05.png)
@@ -1,12 +1,12 @@
---
title: Host on GitLab Pages
description: Host your site on GitLab Pages.
description: Host your project on GitLab Pages.
categories: []
keywords: []
aliases: [/hosting-and-deployment/hosting-on-gitlab/]
---
Use these instructions to enable continuous deployment from a GitLab repository.
Use these instructions to enable continuous deployment from a GitLab repository to GitLab Pages.
{{% include "/_common/gitignore-public.md" %}}
@@ -14,12 +14,12 @@ Use these instructions to enable continuous deployment from a GitLab repository.
Please complete the following tasks before continuing:
1. [Create](https://gitlab.com/users/sign_up) a GitLab account
1. [Log in](https://gitlab.com/users/sign_in) to your GitLab account
1. [Create](https://gitlab.com/projects/new) a GitLab repository for your project
1. [Create](https://git-scm.com/docs/git-init) a local Git repository for your project with a [remote][] reference to your GitLab repository
1. Create a Hugo project within your local Git repository and test it with the `hugo server` command
1. Commit the changes to your local Git repository and push to your GitLab repository
1. [Create](https://gitlab.com/users/sign_up) a GitLab account.
1. [Log in](https://gitlab.com/users/sign_in) to your GitLab account.
1. [Create](https://gitlab.com/projects/new) a GitLab repository for your project.
1. [Create](https://git-scm.com/docs/git-init) a local Git repository for your project with a [remote][] reference to your GitLab repository.
1. Create a Hugo project within your local Git repository and test it with the `hugo server` command.
1. Commit the changes to your local Git repository and push to your GitLab repository.
## BaseURL
@@ -28,86 +28,38 @@ The [`baseURL`][] in your project configuration must reflect the full URL of you
## Procedure
Step 1
: Create a `.gitlab-ci.yml` file in the root of your project.
: Create a `.gitlab-ci.yml` file in the root of your project, adjusting the tool versions and time zone as needed.
```yaml {file=".gitlab-ci.yml" copy=true}
variables:
# Application versions
# Define tool versions
DART_SASS_VERSION: 1.101.0
HUGO_VERSION: 0.163.2
GO_VERSION: 1.26.4
HUGO_VERSION: 0.163.3
NODE_VERSION: 24.16.0
# Git
# Set the build timezone
TZ: Europe/Oslo
# Set the build cache directory
HUGO_CACHEDIR: ${CI_PROJECT_DIR}/.cache/hugo
# Set the repository clone and fetch strategy
GIT_DEPTH: 0
GIT_STRATEGY: clone
GIT_SUBMODULE_STRATEGY: recursive
# Time zone
TZ: Europe/Oslo
cache:
key: ${CI_COMMIT_REF_SLUG}
fallback_keys:
- ${CI_DEFAULT_BRANCH}
paths:
- .cache/hugo
image:
name: golang:1.26.4-bookworm
name: buildpack-deps:bookworm
pages:
stage: deploy
script:
- |
# Create directory for user-specific executable files
echo "Creating directory for user-specific executable files..."
mkdir -p "${HOME}/.local"
# Install utilities
echo "Installing utilities..."
apt-get update
apt-get install -y brotli xz-utils zstd
# Install Dart Sass
echo "Installing Dart Sass ${DART_SASS_VERSION}..."
curl -sLJO "https://github.com/sass/dart-sass/releases/download/${DART_SASS_VERSION}/dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz"
tar -C "${HOME}/.local" -xf "dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz"
rm "dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz"
export PATH="${HOME}/.local/dart-sass:${PATH}"
# Install Hugo
echo "Installing Hugo ${HUGO_VERSION}..."
curl -sLJO "https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_${HUGO_VERSION}_linux-amd64.tar.gz"
mkdir -p "${HOME}/.local/hugo"
tar -C "${HOME}/.local/hugo" -xf "hugo_${HUGO_VERSION}_linux-amd64.tar.gz"
rm "hugo_${HUGO_VERSION}_linux-amd64.tar.gz"
export PATH="${HOME}/.local/hugo:${PATH}"
# Install Node.js
echo "Installing Node.js ${NODE_VERSION}..."
curl -sLJO "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.xz"
tar -C "${HOME}/.local" -xf "node-v${NODE_VERSION}-linux-x64.tar.xz"
rm "node-v${NODE_VERSION}-linux-x64.tar.xz"
export PATH="${HOME}/.local/node-v${NODE_VERSION}-linux-x64/bin:${PATH}"
# Verify installations
echo "Verifying installations..."
echo "Dart Sass: $(sass --version)"
echo "Go: $(go version)"
echo "Hugo: $(hugo version)"
echo "Node.js: $(node --version)"
echo "brotli: $(brotli --version)"
echo "xz: $(xz --version)"
echo "zstd: $(zstd --version)"
# Install Node.js dependencies
echo "Installing Node.js dependencies..."
[[ -f package-lock.json || -f npm-shrinkwrap.json ]] && npm ci --prefer-offline || true
# Configure Git
echo "Configuring Git..."
git config --global core.quotepath false
# Build site
echo "Building site..."
hugo --gc --minify --baseURL "${CI_PAGES_URL}"
# Compress published files
echo "Compressing published files..."
find public/ -type f -regextype posix-extended -regex '.+\.(css|html|js|json|mjs|svg|txt|xml)$' -print0 > files.txt
time xargs --null --max-procs=0 --max-args=1 brotli --quality=10 --force --keep < files.txt
time xargs --null --max-procs=0 --max-args=1 gzip -9 --force --keep < files.txt
- chmod a+x build.sh && ./build.sh
artifacts:
paths:
- public
@@ -116,20 +68,135 @@ Step 1
```
Step 2
: Commit the changes to your local Git repository and push to your GitLab repository.
: Create a `build.sh` file in the root of your project.
```sh {file="build.sh" copy=true}
#!/usr/bin/env bash
#------------------------------------------------------------------------------
# @file
# Builds a Hugo project hosted on GitLab Pages.
#------------------------------------------------------------------------------
# Exit on error, undefined variables, or pipe failures
set -euo pipefail
# Perform cleanup
cleanup() {
if [[ -n "${build_temp_dir:-}" && -d "${build_temp_dir}" ]]; then
rm -rf "${build_temp_dir}"
fi
}
# Register the cleanup trap
trap cleanup EXIT SIGINT SIGTERM
main() {
# Create a temporary directory for downloads
build_temp_dir=$(mktemp -d)
# Create a local tools directory
mkdir -p "${HOME}/.local"
# Install utilities
echo "Installing utilities..."
apt-get update > /dev/null
apt-get install -y brotli > /dev/null
# Install Dart Sass
echo "Installing Dart Sass ${DART_SASS_VERSION}..."
curl -sfLO --output-dir "${build_temp_dir}" "https://github.com/sass/dart-sass/releases/download/${DART_SASS_VERSION}/dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz"
tar -C "${HOME}/.local" -xf "${build_temp_dir}/dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz"
export PATH="${HOME}/.local/dart-sass:${PATH}"
# Install Go
if [[ -f "${CI_PROJECT_DIR}/go.mod" ]]; then
echo "Installing Go ${GO_VERSION}..."
curl -sfLO --output-dir "${build_temp_dir}" "https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz"
tar -C "${HOME}/.local" -xf "${build_temp_dir}/go${GO_VERSION}.linux-amd64.tar.gz"
export PATH="${HOME}/.local/go/bin:${PATH}"
fi
# Install Hugo
echo "Installing Hugo ${HUGO_VERSION}..."
curl -sfLO --output-dir "${build_temp_dir}" "https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_${HUGO_VERSION}_linux-amd64.tar.gz"
mkdir -p "${HOME}/.local/hugo"
tar -C "${HOME}/.local/hugo" -xf "${build_temp_dir}/hugo_${HUGO_VERSION}_linux-amd64.tar.gz"
export PATH="${HOME}/.local/hugo:${PATH}"
# Install Node.js
if [[ -f "${CI_PROJECT_DIR}/package-lock.json" ]]; then
echo "Installing Node.js ${NODE_VERSION}..."
curl -sfLO --output-dir "${build_temp_dir}" "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.gz"
tar -C "${HOME}/.local" -xf "${build_temp_dir}/node-v${NODE_VERSION}-linux-x64.tar.gz"
export PATH="${HOME}/.local/node-v${NODE_VERSION}-linux-x64/bin:${PATH}"
fi
# Log tool versions
echo "Logging tool versions..."
command -v sass &> /dev/null && echo "Dart Sass: $(sass --version)" || echo "Dart Sass: not installed"
command -v go &> /dev/null && echo "Go: $(go version)" || echo "Go: not installed"
command -v hugo &> /dev/null && echo "Hugo: $(hugo version)" || echo "Hugo: not installed"
command -v node &> /dev/null && echo "Node.js: $(node --version)" || echo "Node.js: not installed"
# Configure Git
echo "Configuring Git..."
git config --global core.quotepath false
# Fetch full Git history
if [[ $(git rev-parse --is-shallow-repository) == true ]]; then
echo "Fetching full Git history..."
git fetch --unshallow
fi
# Initialize Git submodules
if [[ -f .gitmodules ]]; then
echo "Initializing Git submodules..."
git submodule update --init --recursive
fi
# Install Node.js dependencies
if [[ -f package-lock.json ]]; then
echo "Installing Node.js dependencies..."
npm ci
fi
# Build the project
echo "Building the project..."
hugo build --gc --minify
# Compress published files
echo "Compressing published files..."
find public/ -type f -regextype posix-extended -regex '.+\.(cjs|css|html|js|json|mjs|svg|txt|xml)$' -print0 > "${build_temp_dir}/files.txt"
xargs --null --max-procs=0 --max-args=1 brotli --quality=10 --force --keep < "${build_temp_dir}/files.txt"
xargs --null --max-procs=0 --max-args=1 gzip -9 --force --keep < "${build_temp_dir}/files.txt"
}
main "$@"
```
Step 3
: From your GitLab repository, navigate to **Build**&nbsp;>&nbsp;**Pipelines** to follow the CI pipeline building your page.
: In your project configuration, change the location of the image cache to the [`cacheDir`][] as shown below:
{{< code-toggle file=hugo copy=true >}}
[caches.images]
dir = ':cacheDir/images'
{{< /code-toggle >}}
See [configure file caches][] for more information.
Step 4
: Commit the changes to your local Git repository and push to your GitLab repository.
Step 5
: From your GitLab repository, navigate to **Build**&nbsp;>&nbsp;**Pipelines** to follow the CI pipeline building your page.
Step 6
: When the pipeline has passed, your new website is available at `https://<YourUsername>.gitlab.io/<your-hugo-site>/`.
In the future, whenever you push a change from your local Git repository, GitLab Pages will rebuild and deploy your site.
## Other resources
- [GitLab Pages documentation][]
[GitLab Pages documentation]: https://docs.gitlab.com/user/project/pages/
[`baseURL`]: /configuration/all/#baseurl
[`cacheDir`]: /configuration/all/#cachedir
[configure file caches]: /configuration/caches/
[remote]: https://git-scm.com/docs/git-remote
@@ -1,12 +1,12 @@
---
title: Host on Netlify
description: Host your site on Netlify.
description: Host your project on Netlify.
categories: []
keywords: []
aliases: [/hosting-and-deployment/hosting-on-netlify/]
---
Use these instructions to enable continuous deployment from a GitHub repository. The same general steps apply if you are using Azure DevOps, Bitbucket, or GitLab for version control.
Use these instructions to enable continuous deployment from a GitHub repository. The same general steps apply for other Git providers such as GitLab or Bitbucket.
{{% include "/_common/gitignore-public.md" %}}
@@ -14,27 +14,24 @@ Use these instructions to enable continuous deployment from a GitHub repository.
Please complete the following tasks before continuing:
1. [Create](https://app.netlify.com/signup) a Netlify account
1. [Log in](https://app.netlify.com/login) to your Netlify account
1. [Create](https://github.com/signup) a GitHub account
1. [Log in](https://github.com/login) to your GitHub account
1. [Create](https://github.com/new) a GitHub repository for your project
1. [Create](https://git-scm.com/docs/git-init) a local Git repository for your project with a [remote][] reference to your GitHub repository
1. Create a Hugo project within your local Git repository and test it with the `hugo server` command
1. Commit the changes to your local Git repository and push to your GitHub repository
1. [Create](https://app.netlify.com/signup) a Netlify account.
1. [Log in](https://app.netlify.com/login) to your Netlify account.
1. [Create](https://github.com/signup) a GitHub account.
1. [Log in](https://github.com/login) to your GitHub account.
1. [Create](https://github.com/new) a GitHub repository for your project.
1. [Create](https://git-scm.com/docs/git-init) a local Git repository for your project with a [remote][] reference to your GitHub repository.
1. Create a Hugo project within your local Git repository and test it with the `hugo server` command.
1. Commit the changes to your local Git repository and push to your GitHub repository.
## Procedure
<!-- Using "text" as the code block language because "toml" looks terrible. -->
Step 1
: Create a `netlify.toml` file in the root of your project.
: Create a `netlify.toml` file in the root of your project, adjusting the tool versions and time zone as needed.
```toml {file="netlify.toml" copy=true}
[build.environment]
DART_SASS_VERSION = "1.101.0"
GO_VERSION = "1.26.4"
HUGO_VERSION = "0.163.2"
HUGO_VERSION = "0.163.3"
NODE_VERSION = "24.16.0"
TZ = "Europe/Oslo"
@@ -46,20 +43,20 @@ Step 1
"""
```
If your site requires Dart Sass to transpile Sass to CSS, set the `DART_SASS_VERSION` and include the Dart Sass installation in the build step.
If your project requires Dart Sass to transpile Sass to CSS, set the `DART_SASS_VERSION` and include the Dart Sass installation in the build step.
```toml {file="netlify.toml" copy=true}
[build.environment]
DART_SASS_VERSION = "1.101.0"
GO_VERSION = "1.26.4"
HUGO_VERSION = "0.163.2"
HUGO_VERSION = "0.163.3"
NODE_VERSION = "24.16.0"
TZ = "Europe/Oslo"
[build]
publish = "public"
command = """\
curl -sLJO "https://github.com/sass/dart-sass/releases/download/${DART_SASS_VERSION}/dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz" && \
curl -sfLO "https://github.com/sass/dart-sass/releases/download/${DART_SASS_VERSION}/dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz" && \
tar -C "${HOME}/.local" -xf "dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz" && \
rm "dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz" && \
export PATH="${HOME}/.local/dart-sass:${PATH}" && \
@@ -69,57 +66,69 @@ Step 1
```
Step 2
: Commit the changes to your local Git repository and push to your GitHub repository.
: In your project configuration, change the location of the image cache to the [`cacheDir`][] as shown below:
{{< code-toggle file=hugo copy=true >}}
[caches.images]
dir = ':cacheDir/images'
{{< /code-toggle >}}
See [configure file caches][] for more information.
Step 3
: Commit the changes to your local Git repository and push to your GitHub repository.
Step 4
: In the upper right corner of the Netlify dashboard, press the **Add new project** button and select “Import an existing project".
![screen capture](netlify-01.png)
Step 4
Step 5
: Connect to GitHub.
![screen capture](netlify-02.png)
Step 5
Step 6
: Press the "Authorize Netlify" button to allow the Netlify application to access your GitHub account.
![screen capture](netlify-03.png)
Step 6
Step 7
: Press the **Configure Netlify on GitHub** button.
![screen capture](netlify-04.png)
Step 7
Step 8
: Select the GitHub account where you want to install the Netlify application.
![screen capture](netlify-05.png)
Step 8
Step 9
: Authorize the Netlify application to access all repositories or only select repositories, then press the Install button.
![screen capture](netlify-06.png)
Your browser will be redirected to the Netlify dashboard.
Step 9
Step 10
: Click on the name of the repository you wish to import.
![screen capture](netlify-07.png)
Step 10
Step 11
: On the "Review configuration" page, enter a project name, leave the settings at their default values, then press the **Deploy** button.
![screen capture](netlify-08.png)
![screen capture](netlify-09.png)
Step 11
Step 12
: When the deployment completes, click on the link to your published site.
![screen capture](netlify-10.png)
In the future, whenever you push a change from your local Git repository, Netlify will rebuild and deploy your site.
[`cacheDir`]: /configuration/all/#cachedir
[configure file caches]: /configuration/caches/
[remote]: https://git-scm.com/docs/git-remote
@@ -1,12 +1,12 @@
---
title: Host on Render
description: Host your site on Render.
description: Host your project on Render.
categories: []
keywords: []
aliases: [/hosting-and-deployment/hosting-on-render/]
---
Use these instructions to enable continuous deployment from a GitHub repository. The same general steps apply if you are using Bitbucket or GitLab for version control.
Use these instructions to enable continuous deployment from a GitHub repository. The same general steps apply for other Git providers such as GitLab or Bitbucket.
{{% include "/_common/gitignore-public.md" %}}
@@ -14,19 +14,19 @@ Use these instructions to enable continuous deployment from a GitHub repository.
Please complete the following tasks before continuing:
1. [Create](https://dashboard.render.com/register) a Render account
1. [Log in](https://dashboard.render.com/login) to your Render account
1. [Create](https://github.com/signup) a GitHub account
1. [Log in](https://github.com/login) to your GitHub account
1. [Create](https://github.com/new) a GitHub repository for your project
1. [Create](https://git-scm.com/docs/git-init) a local Git repository for your project with a [remote][] reference to your GitHub repository
1. Create a Hugo project within your local Git repository and test it with the `hugo server` command
1. Commit the changes to your local Git repository and push to your GitHub repository
1. [Create](https://dashboard.render.com/register) a Render account.
1. [Log in](https://dashboard.render.com/login) to your Render account.
1. [Create](https://github.com/signup) a GitHub account.
1. [Log in](https://github.com/login) to your GitHub account.
1. [Create](https://github.com/new) a GitHub repository for your project.
1. [Create](https://git-scm.com/docs/git-init) a local Git repository for your project with a [remote][] reference to your GitHub repository.
1. Create a Hugo project within your local Git repository and test it with the `hugo server` command.
1. Commit the changes to your local Git repository and push to your GitHub repository.
## Procedure
Step 1
: Create a [Render Blueprint][] in the root of your project.
: Create a `render.yaml` file in the root of your project, adjusting the tool versions and time zone as needed.
```yaml {file="render.yaml" copy=true}
services:
@@ -42,7 +42,7 @@ Step 1
- key: GO_VERSION
value: 1.26.4
- key: HUGO_VERSION
value: 0.163.2
value: 0.163.3
- key: NODE_VERSION
value: 24.16.0
- key: TZ
@@ -57,15 +57,16 @@ Step 2
#------------------------------------------------------------------------------
# @file
# Builds a Hugo site hosted on a Render.
# Builds a Hugo project hosted on Render.
#
# Render automatically installs Node.js dependencies.
# Render automatically installs Node.js and any Node.js dependencies.
#------------------------------------------------------------------------------
# Exit on error, undefined variables, or pipe failures
set -euo pipefail
build_temp_dir=""
# Set the build cache directory
HUGO_CACHEDIR="${PWD}/.cache/hugo"
# Perform cleanup
cleanup() {
@@ -78,112 +79,133 @@ Step 2
trap cleanup EXIT SIGINT SIGTERM
main() {
# Create and move into a temporary directory for downloads
build_temp_dir=$(mktemp -d)
pushd "${build_temp_dir}" > /dev/null
# Export the build cache directory
export HUGO_CACHEDIR
# Create the local tools directory
# Create a temporary directory for downloads
build_temp_dir=$(mktemp -d)
# Create a local tools directory
mkdir -p "${HOME}/.local"
# Install Dart Sass
echo "Installing Dart Sass ${DART_SASS_VERSION}..."
curl -sLJO "https://github.com/sass/dart-sass/releases/download/${DART_SASS_VERSION}/dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz"
tar -C "${HOME}/.local" -xf "dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz"
curl -sfL --output-dir "${build_temp_dir}" -O "https://github.com/sass/dart-sass/releases/download/${DART_SASS_VERSION}/dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz"
tar -C "${HOME}/.local" -xf "${build_temp_dir}/dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz"
export PATH="${HOME}/.local/dart-sass:${PATH}"
# Install Go
echo "Installing Go ${GO_VERSION}..."
curl -sLJO "https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz"
tar -C "${HOME}/.local" -xf "go${GO_VERSION}.linux-amd64.tar.gz"
export PATH="${HOME}/.local/go/bin:${PATH}"
if [[ -f "go.mod" ]]; then
echo "Installing Go ${GO_VERSION}..."
curl -sfL --output-dir "${build_temp_dir}" -O "https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz"
tar -C "${HOME}/.local" -xf "${build_temp_dir}/go${GO_VERSION}.linux-amd64.tar.gz"
export PATH="${HOME}/.local/go/bin:${PATH}"
fi
# Install Hugo
echo "Installing Hugo ${HUGO_VERSION}..."
curl -sLJO "https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_${HUGO_VERSION}_linux-amd64.tar.gz"
curl -sfL --output-dir "${build_temp_dir}" -O "https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_${HUGO_VERSION}_linux-amd64.tar.gz"
mkdir -p "${HOME}/.local/hugo"
tar -C "${HOME}/.local/hugo" -xf "hugo_${HUGO_VERSION}_linux-amd64.tar.gz"
tar -C "${HOME}/.local/hugo" -xf "${build_temp_dir}/hugo_${HUGO_VERSION}_linux-amd64.tar.gz"
export PATH="${HOME}/.local/hugo:${PATH}"
# Return to the project root
popd > /dev/null
# Verify installations
echo "Verifying installations..."
echo Dart Sass: "$(sass --version)"
echo Go: "$(go version)"
echo Hugo: "$(hugo version)"
echo Node.js: "$(node --version)"
# Log tool versions
echo "Logging tool versions..."
command -v sass &> /dev/null && echo "Dart Sass: $(sass --version)" || echo "Dart Sass: not installed"
command -v go &> /dev/null && echo "Go: $(go version)" || echo "Go: not installed"
command -v hugo &> /dev/null && echo "Hugo: $(hugo version)" || echo "Hugo: not installed"
command -v node &> /dev/null && echo "Node.js: $(node --version)" || echo "Node.js: not installed"
# Configure Git
echo "Configuring Git..."
git config --global core.quotepath false
if [ "$(git rev-parse --is-shallow-repository)" = "true" ]; then
# Fetch full Git history
if [[ $(git rev-parse --is-shallow-repository) == true ]]; then
echo "Fetching full Git history..."
git fetch --unshallow
fi
# Build the site
echo "Building the site..."
hugo build --gc --minify --baseURL "${RENDER_EXTERNAL_URL}"
# Initialize Git submodules
if [[ -f .gitmodules ]]; then
echo "Initializing Git submodules..."
git submodule update --init --recursive
fi
# Build the project
echo "Building the project..."
hugo build --gc --minify
}
main "$@"
```
Step 3
: Commit the changes to your local Git repository and push to your GitHub repository.
: In your project configuration, change the location of the image cache to the [`cacheDir`][] as shown below:
{{< code-toggle file=hugo copy=true >}}
[caches.images]
dir = ':cacheDir/images'
{{< /code-toggle >}}
See [configure file caches][] for more information.
Step 4
: Commit the changes to your local Git repository and push to your GitHub repository.
Step 5
: On the Render [dashboard][], press the **Add new** button and select "Blueprint" from the drop-down menu.
![screen capture](render-01.png)
Step 5
Step 6
: Press the **GitHub** button to connect to your GitHub account.
![screen capture](render-02.png)
Step 6
Step 7
: Press the **Authorize Render** button to allow the Render application to access your GitHub account.
![screen capture](render-03.png)
Step 7
Step 8
: Select the GitHub account where you want to install the Render application.
![screen capture](render-04.png)
Step 8
Step 9
: Authorize the Render application to access all repositories or only select repositories, then press the **Install** button.
![screen capture](render-05.png)
![screen capture](render-05.png)
Step 9
: On the "Create a new Blueprint Instance in My Workspacee" page, press the **Connect** button to the right of the name of your GitHub repository.
Step 10
: On the "Create a new Blueprint Instance in My Workspace" page, press the **Connect** button to the right of the name of your GitHub repository.
![screen capture](render-06.png)
Step 10
Step 11
: Enter a unique name for your Blueprint, then press the **Deploy Blueprint** button at the bottom of the page.
![screen capture](render-07.png)
Step 11
Step 12
: Wait for the site to build and deploy, then click on the "Resources" link on the left side of the page.
![screen capture](render-08.png)
Step 12
Step 13
: Click on the link to the static site resource.
![screen capture](render-09.png)
Step 13
Step 14
: Click on the link to your published site.
![screen capture](render-10.png)
In the future, whenever you push a change from your local Git repository, Render will rebuild and deploy your site.
[Render Blueprint]: https://render.com/docs/blueprint-spec
[`cacheDir`]: /configuration/all/#cachedir
[configure file caches]: /configuration/caches/
[dashboard]: https://dashboard.render.com/
[remote]: https://git-scm.com/docs/git-remote
@@ -1,6 +1,6 @@
---
title: Host on SourceHut Pages
description: Host your site on SourceHut Pages.
description: Host your project on SourceHut Pages.
categories: []
keywords: []
aliases: [/hosting-and-deployment/hosting-on-sourcehut/]
@@ -1,11 +1,11 @@
---
title: Host on Vercel
description: Host your site on Vercel.
description: Host your project on Vercel.
categories: []
keywords: []
---
Use these instructions to enable continuous deployment from a GitHub repository. The same general steps apply if you are using Bitbucket or GitLab for version control.
Use these instructions to enable continuous deployment from a GitHub repository. The same general steps apply for other Git providers such as GitLab or Bitbucket.
{{% include "/_common/gitignore-public.md" %}}
@@ -13,14 +13,14 @@ Use these instructions to enable continuous deployment from a GitHub repository.
Please complete the following tasks before continuing:
1. [Create](https://vercel.com/signup) a Vercel account
1. [Log in](https://vercel.com/login) to your Vercel account
1. [Create](https://github.com/signup) a GitHub account
1. [Log in](https://github.com/login) to your GitHub account
1. [Create](https://github.com/new) a GitHub repository for your project
1. [Create](https://git-scm.com/docs/git-init) a local Git repository for your project with a [remote][] reference to your GitHub repository
1. Create a Hugo project within your local Git repository and test it with the `hugo server` command
1. Commit the changes to your local Git repository and push to your GitHub repository
1. [Create](https://vercel.com/signup) a Vercel account.
1. [Log in](https://vercel.com/login) to your Vercel account.
1. [Create](https://github.com/signup) a GitHub account.
1. [Log in](https://github.com/login) to your GitHub account.
1. [Create](https://github.com/new) a GitHub repository for your project.
1. [Create](https://git-scm.com/docs/git-init) a local Git repository for your project with a [remote][] reference to your GitHub repository.
1. Create a Hugo project within your local Git repository and test it with the `hugo server` command.
1. Commit the changes to your local Git repository and push to your GitHub repository.
## Procedure
@@ -30,28 +30,37 @@ Step 1
```json {file="vercel.json" copy=true}
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"installCommand": "",
"buildCommand": "chmod a+x build.sh && ./build.sh",
"outputDirectory": "public"
}
```
Step 2
: Create a `build.sh` file in the root of your project.
: Create a `build.sh` file in the root of your project, adjusting the tool versions and time zone as needed.
```sh {file="build.sh" copy=true}
#!/usr/bin/env bash
#------------------------------------------------------------------------------
# @file
# Builds a Hugo site hosted on Vercel.
#
# The Vercel build image automatically installs Node.js dependencies.
# Builds a Hugo project hosted on Vercel.
#------------------------------------------------------------------------------
# Exit on error, undefined variables, or pipe failures
set -euo pipefail
build_temp_dir=""
# Define tool versions
DART_SASS_VERSION=1.101.0
GO_VERSION=1.26.4
HUGO_VERSION=0.163.3
NODE_VERSION=24.16.0
# Set the build time zone
TZ=Europe/Oslo
# Set the build cache directory
HUGO_CACHEDIR="${PWD}/.vercel/cache/hugo"
# Perform cleanup
cleanup() {
@@ -64,127 +73,151 @@ Step 2
trap cleanup EXIT SIGINT SIGTERM
main() {
# Define tool versions
DART_SASS_VERSION=1.101.0
GO_VERSION=1.26.4
HUGO_VERSION=0.163.2
NODE_VERSION=24.16.0
# Export the build time zone
export TZ
# Set the build timezone
export TZ=Europe/Oslo
# Export the build cache directory
export HUGO_CACHEDIR
# Create and move into a temporary directory for downloads
# Create a temporary directory for downloads
build_temp_dir=$(mktemp -d)
pushd "${build_temp_dir}" > /dev/null
# Create the local tools directory
# Create a local tools directory
mkdir -p "${HOME}/.local"
# Install Dart Sass
echo "Installing Dart Sass ${DART_SASS_VERSION}..."
curl -sLJO "https://github.com/sass/dart-sass/releases/download/${DART_SASS_VERSION}/dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz"
tar -C "${HOME}/.local" -xf "dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz"
curl -sfL --output-dir "${build_temp_dir}" -O "https://github.com/sass/dart-sass/releases/download/${DART_SASS_VERSION}/dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz"
tar -C "${HOME}/.local" -xf "${build_temp_dir}/dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz"
export PATH="${HOME}/.local/dart-sass:${PATH}"
# Install Go
echo "Installing Go ${GO_VERSION}..."
curl -sLJO "https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz"
tar -C "${HOME}/.local" -xf "go${GO_VERSION}.linux-amd64.tar.gz"
export PATH="${HOME}/.local/go/bin:${PATH}"
if [[ -f "go.mod" ]]; then
echo "Installing Go ${GO_VERSION}..."
curl -sfL --output-dir "${build_temp_dir}" -O "https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz"
tar -C "${HOME}/.local" -xf "${build_temp_dir}/go${GO_VERSION}.linux-amd64.tar.gz"
export PATH="${HOME}/.local/go/bin:${PATH}"
fi
# Install Hugo
echo "Installing Hugo ${HUGO_VERSION}..."
curl -sLJO "https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_${HUGO_VERSION}_linux-amd64.tar.gz"
curl -sfL --output-dir "${build_temp_dir}" -O "https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_${HUGO_VERSION}_linux-amd64.tar.gz"
mkdir -p "${HOME}/.local/hugo"
tar -C "${HOME}/.local/hugo" -xf "hugo_${HUGO_VERSION}_linux-amd64.tar.gz"
tar -C "${HOME}/.local/hugo" -xf "${build_temp_dir}/hugo_${HUGO_VERSION}_linux-amd64.tar.gz"
export PATH="${HOME}/.local/hugo:${PATH}"
# Install Node.js
echo "Installing Node.js ${NODE_VERSION}..."
curl -sLJO "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.xz"
tar -C "${HOME}/.local" -xf "node-v${NODE_VERSION}-linux-x64.tar.xz"
export PATH="${HOME}/.local/node-v${NODE_VERSION}-linux-x64/bin:${PATH}"
if [[ -f "package-lock.json" ]]; then
echo "Installing Node.js ${NODE_VERSION}..."
curl -sfL --output-dir "${build_temp_dir}" -O "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.gz"
tar -C "${HOME}/.local" -xf "${build_temp_dir}/node-v${NODE_VERSION}-linux-x64.tar.gz"
export PATH="${HOME}/.local/node-v${NODE_VERSION}-linux-x64/bin:${PATH}"
fi
# Return to the project root
popd > /dev/null
# Verify installations
echo "Verifying installations..."
echo Dart Sass: "$(sass --version)"
echo Go: "$(go version)"
echo Hugo: "$(hugo version)"
echo Node.js: "$(node --version)"
# Log tool versions
echo "Logging tool versions..."
command -v sass &> /dev/null && echo "Dart Sass: $(sass --version)" || echo "Dart Sass: not installed"
command -v go &> /dev/null && echo "Go: $(go version)" || echo "Go: not installed"
command -v hugo &> /dev/null && echo "Hugo: $(hugo version)" || echo "Hugo: not installed"
command -v node &> /dev/null && echo "Node.js: $(node --version)" || echo "Node.js: not installed"
# Configure Git
echo "Configuring Git..."
git config --global core.quotepath false
if [ "$(git rev-parse --is-shallow-repository)" = "true" ]; then
# Fetch full Git history
if [[ $(git rev-parse --is-shallow-repository) == true ]]; then
echo "Fetching full Git history..."
git fetch --unshallow
fi
# Build the site
echo "Building the site..."
hugo build --gc --minify --baseURL "https://${VERCEL_PROJECT_PRODUCTION_URL}"
# Initialize Git submodules
if [[ -f .gitmodules ]]; then
echo "Initializing Git submodules..."
git submodule update --init --recursive
fi
# Install Node.js dependencies
if [[ -f package-lock.json ]]; then
echo "Installing Node.js dependencies..."
npm ci
fi
# Build the project
echo "Building the project..."
hugo build --gc --minify
}
main "$@"
```
Step 3
: Commit the changes to your local Git repository and push to your GitHub repository.
: In your project configuration, change the location of the image cache to the [`cacheDir`][] as shown below:
{{< code-toggle file=hugo copy=true >}}
[caches.images]
dir = ':cacheDir/images'
{{< /code-toggle >}}
See [configure file caches][] for more information.
Step 4
: Commit the changes to your local Git repository and push to your GitHub repository.
Step 5
: In the upper right corner of the Vercel dashboard, press the **Add New** button and select "Project" from the drop down menu.
![screen capture](vercel-01.png)
Step 5
Step 6
: Press the "Continue with GitHub" button.
![screen capture](vercel-02.png)
Step 6
Step 7
: Press the **Authorize Vercel** button to allow the Vercel application to access your GitHub account.
![screen capture](vercel-03.png)
Step 7
Step 8
: Press the **Install** button to install the Vercel application.
![screen capture](vercel-04.png)
Step 8
Step 9
: Select the GitHub account where you want to install the Vercel application.
![screen capture](vercel-05.png)
Step 9
Step 10
: Authorize the Vercel application to access all repositories or only select repositories, then press the **Install** button.
![screen capture](vercel-06.png)
Your browser will be redirected to the Cloudflare dashboard.
Step 10
Step 11
: Press the **Import** button to the right of the name of your GitHub repository.
![screen capture](vercel-07.png)
Step 11
Step 12
: On the "New Project" page, leave the settings at their default values and press the **Deploy** button.
![screen capture](vercel-08.png)
Step 12
Step 13
: When the deployment completes, press the **Continue to Dashboard" button at the bottom of the page.
![screen capture](vercel-09.png)
Step 13
Step 14
: On the "Production Deployment" page, click on the link to your published site.
![screen capture](vercel-10.png)
In the future, whenever you push a change from your local Git repository, Vercel will rebuild and deploy your site.
[`cacheDir`]: /configuration/all/#cachedir
[configure file caches]: /configuration/caches/
[remote]: https://git-scm.com/docs/git-remote
@@ -13,7 +13,7 @@ Modules that need Node packages (e.g. for Tailwind CSS) can declare those depend
Each module declares its Node dependencies in a `package.json` file in its root directory, using the standard `dependencies` and `devDependencies` fields.
<!-- TODO
In the admonition below, remove the reference to v0.159.0 somewhere
In the admonition below, remove the reference to v0.159.0 somewhere
after v0.174.0, 15 minor releases after the improvement.
-->
@@ -37,7 +37,7 @@ project/
```
<!-- TODO
In the admonition below, remove the reference to v0.159.0 somewhere
In the admonition below, remove the reference to v0.159.0 somewhere
after v0.174.0, 15 minor releases after the improvement.
-->
@@ -24,7 +24,7 @@ content/
│ │ ├── auction-1.md
│ │ └── auction-2.md <-- current section: 2023-11
│ ├── 2023-12/
│ │ ├── _index.md
│ │ ├── _index.md
│ │ ├── auction-3.md
│ │ └── auction-4.md
│ ├── _index.md <-- current section: auctions
@@ -35,7 +35,7 @@ content/
│ ├── book-1.md
│ └── book-2.md <-- current section: books
├── films/
│ ├── _index.md <-- current section: films
│ ├── _index.md <-- current section: films
│ ├── film-1.md
│ └── film-2.md <-- current section: films
└── _index.md <-- current section: home
+1 -1
View File
@@ -58,7 +58,7 @@ Use these methods on the `Data` object within a _taxonomy_ template.
: (`page.Taxonomy`) Returns the `Taxonomy` object, consisting of a map of terms and the [weighted pages](g) associated with each term.
```go-html-template
{{ $taxonomyObject := .Data.Terms }}
{{ $taxonomyObject := .Data.Terms }}
```
> [!NOTE]
+1 -1
View File
@@ -24,7 +24,7 @@ content/
│ │ ├── auction-1.md
│ │ └── auction-2.md <-- first section: auctions
│ ├── 2023-12/
│ │ ├── _index.md
│ │ ├── _index.md
│ │ ├── auction-3.md
│ │ └── auction-4.md
│ ├── _index.md <-- first section: auctions
+2 -2
View File
@@ -132,7 +132,7 @@ Use these methods on the `GitInfo` object.
```go-html-template
{{ with .GitInfo }}
{{ range .Ancestors | first 5 }}
{{ range .Ancestors | first 5 }}
{{ .CommitDate.Format "2006-01-02" }}: {{ .Subject }}
{{ end }}
{{ end }}
@@ -142,7 +142,7 @@ Use these methods on the `GitInfo` object.
```go-html-template
{{ with .GitInfo }}
{{ range .Ancestors.Reverse | first 5 }}
{{ range .Ancestors.Reverse | first 5 }}
{{ .CommitDate.Format "2006-01-02" }}: {{ .Subject }}
{{ end }}
{{ end }}
+1 -1
View File
@@ -21,7 +21,7 @@ content/
│ ├── book-2.md <-- kind = page IsBranch = false
│ └── _index.md <-- kind = section IsBranch = true
├── tags
│ ├── fiction
│ ├── fiction
│ │ └── _index.md <-- kind = term IsBranch = true
│ └── _index.md <-- kind = taxonomy IsBranch = true
└── _index.md <-- kind = home IsBranch = true
+2 -2
View File
@@ -24,7 +24,7 @@ content/
│ │ ├── auction-1.md
│ │ └── auction-2.md <-- parent: 2023-11
│ ├── 2023-12/
│ │ ├── _index.md
│ │ ├── _index.md
│ │ ├── auction-3.md
│ │ └── auction-4.md
│ ├── _index.md <-- parent: home
@@ -35,7 +35,7 @@ content/
│ ├── book-1.md
│ └── book-2.md <-- parent: books
├── films/
│ ├── _index.md <-- parent: home
│ ├── _index.md <-- parent: home
│ ├── film-1.md
│ └── film-2.md <-- parent: films
└── _index.md <-- parent: nil
+2 -2
View File
@@ -98,7 +98,7 @@ A file tree:
content/
└── s1/
├── p1/
│ └── index.md
│ └── index.md
└── p2.md
```
@@ -108,7 +108,7 @@ The same content represented as a logical tree:
content/
└── s1/
├── p1
└── p2
└── p2
```
A key difference between these trees is the relative path from p1 to p2:
+1 -1
View File
@@ -25,7 +25,7 @@ content/
│ └── book-2.md
├── films/
│ ├── _index.md
│ ├── film-1.md
│ ├── film-1.md
│ └── film-2.md
└── _index.md
```
+1 -1
View File
@@ -84,7 +84,7 @@ Consider this content structure:
```tree
content/
├── headless/
├── headless/
│ ├── a.jpg
│ ├── b.jpg
│ ├── c.jpg
+1 -1
View File
@@ -32,7 +32,7 @@ baseURL = 'https://example.org/docs/'
Template:
```go-html-template
{{ .Site.Home.Permalink }} → https://example.org/docs/
{{ .Site.Home.Permalink }} → https://example.org/docs/
{{ .Site.Home.RelPermalink }} → /docs/
```
+1 -1
View File
@@ -92,7 +92,7 @@ Some of the methods above are commonly used in a base template as attributes for
```go-html-template
<html
lang="{{ .Site.Language.Locale }}"
lang="{{ .Site.Language.Locale }}"
dir="{{ or .Site.Language.Direction `ltr` }}"
>
```
@@ -1,6 +1,5 @@
---
title: regular expression
reference:
---
A _regular expression_, also known as a _regex_, is a sequence of characters that defines a search pattern. Use the [RE2 syntax][] when defining regular expressions in your templates or in your project configuration.
+2 -2
View File
@@ -28,8 +28,8 @@ Hugo renders this HTML:
```html
<figure class="ma0 w-75">
<a href="https://www.nps.gov/zion/index.htm">
<img
src="/images/examples/zion-national-park.jpg"
<img
src="/images/examples/zion-national-park.jpg"
alt="A photograph of Zion National Park"
>
</a>
+5 -5
View File
@@ -113,9 +113,9 @@ In the example above:
Hugo renders the above to:
```html {trim=false}
<h2>my page title</h2>
```
### Whitespace
@@ -194,7 +194,7 @@ You can split a template action over two or more lines. For example, these are e
```go-html-template
{{ $v := or $arg1 $arg2 }}
{{ $v := or
{{ $v := or
$arg1
$arg2
}}
@@ -225,8 +225,8 @@ Other than using the `nil` keyword in comparisons, you may not use it as an argu
These, on the other hand, are invalid:
```go-html-template
{{ $a := nil }}
{{ add 3 nil }}
{{ $a := nil }}
{{ add 3 nil }}
{{ nil | print}}
```

Some files were not shown because too many files have changed in this diff Show More