mirror of
https://github.com/gohugoio/hugo.git
synced 2026-08-30 02:02:38 +00:00
Compare commits
61 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 75f383065f | |||
| 2db43f841c | |||
| 46ce1f191b | |||
| aae02ca612 | |||
| 83cec785cf | |||
| 4e52be8b90 | |||
| 7888ac585c | |||
| eb1dbe0709 | |||
| 77824d704c | |||
| ec0caaec7c | |||
| 845b8885de | |||
| 43385d6aeb | |||
| a9b0b95ef4 | |||
| e229f4b387 | |||
| 020253904f | |||
| 4a5e94087b | |||
| 48a7aee961 | |||
| 6c583e3227 | |||
| 5d64b492f4 | |||
| b3f32949cb | |||
| 55ecd3a90e | |||
| 3f35721fb2 | |||
| 5c80cb0d20 | |||
| a5e5be234c | |||
| 565c30eac9 | |||
| 48dd6a918a | |||
| 744b8566ec | |||
| 7de5317aef | |||
| 4cbd4ef991 | |||
| a32c889a7b | |||
| 852d868549 | |||
| 1e34e5b26d | |||
| 641d2616c7 | |||
| a834bb9f7e | |||
| 4f130f6e4f | |||
| 9dfa112617 | |||
| ec1933f79d | |||
| 75ad9cdaab | |||
| e293e7ca6d | |||
| 157d86414d | |||
| 6be253000f | |||
| 947e4e66b5 | |||
| 989b299b55 | |||
| 5f897868c0 | |||
| b47376586a | |||
| e477373487 | |||
| 5ab38de363 | |||
| 7b69218489 | |||
| 34373407b7 | |||
| 3afe91d4b1 | |||
| 54398f8d57 | |||
| b8c15f245b | |||
| d0dc518844 | |||
| b529859008 | |||
| 487bb96474 | |||
| 2f6864387c | |||
| c1dc35dd71 | |||
| fc3d1cbadb | |||
| 7e130e34f2 | |||
| 88b7868fbd | |||
| dea158c885 |
@@ -4,7 +4,7 @@ parameters:
|
||||
defaults: &defaults
|
||||
resource_class: large
|
||||
docker:
|
||||
- image: bepsays/ci-hugoreleaser:1.22300.20200
|
||||
- image: bepsays/ci-hugoreleaser:1.22301.20401
|
||||
environment: &buildenv
|
||||
GOMODCACHE: /root/project/gomodcache
|
||||
version: 2
|
||||
@@ -58,7 +58,7 @@ jobs:
|
||||
environment:
|
||||
<<: [*buildenv]
|
||||
docker:
|
||||
- image: bepsays/ci-hugoreleaser-linux-arm64:1.22300.20200
|
||||
- image: bepsays/ci-hugoreleaser-linux-arm64:1.22301.20401
|
||||
steps:
|
||||
- *restore-cache
|
||||
- &attach-workspace
|
||||
|
||||
@@ -66,8 +66,6 @@ See the [features] section of the documentation for a comprehensive summary of H
|
||||
<p float="left">
|
||||
<a href="https://www.linode.com/?utm_campaign=hugosponsor&utm_medium=banner&utm_source=hugogithub" target="_blank"><img src="https://raw.githubusercontent.com/gohugoio/gohugoioTheme/master/assets/images/sponsors/linode-logo_standard_light_medium.png" width="200" alt="Linode"></a>
|
||||
|
||||
<a href="https://route4me.com/" target="_blank"><img src="https://raw.githubusercontent.com/gohugoio/gohugoioTheme/master/assets/images/sponsors/Route4MeLogoBlueOnWhite.svg" width="200" alt="Route Planning & Route Optimization Software"></a>
|
||||
|
||||
<a href="https://www.jetbrains.com/go/?utm_source=OSS&utm_medium=referral&utm_campaign=hugo" target="_blank"><img src="https://raw.githubusercontent.com/gohugoio/gohugoioTheme/master/assets/images/sponsors/goland.svg" width="200" alt="The complete IDE crafted for professional Go developers."></a>
|
||||
</p>
|
||||
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# allow user to override go executable by running as GOEXE=xxx make ...
|
||||
GOEXE="${GOEXE-go}"
|
||||
|
||||
# Convenience script to
|
||||
# - For a given branch
|
||||
# - Run benchmark tests for a given package
|
||||
# - Do the same for master
|
||||
# - then compare the two runs with benchcmp
|
||||
|
||||
benchFilter=".*"
|
||||
|
||||
if (( $# < 2 ));
|
||||
then
|
||||
echo "USAGE: ./bench.sh <git-branch> <package-to-bench> (and <benchmark filter> (regexp, optional))"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
|
||||
if [ $# -eq 3 ]; then
|
||||
benchFilter=$3
|
||||
fi
|
||||
|
||||
|
||||
BRANCH=$1
|
||||
PACKAGE=$2
|
||||
|
||||
git checkout $BRANCH
|
||||
"${GOEXE}" test -test.run=NONE -bench="$benchFilter" -test.benchmem=true ./$PACKAGE > /tmp/bench-$PACKAGE-$BRANCH.txt
|
||||
|
||||
git checkout master
|
||||
"${GOEXE}" test -test.run=NONE -bench="$benchFilter" -test.benchmem=true ./$PACKAGE > /tmp/bench-$PACKAGE-master.txt
|
||||
|
||||
|
||||
benchcmp /tmp/bench-$PACKAGE-master.txt /tmp/bench-$PACKAGE-$BRANCH.txt
|
||||
@@ -1,12 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# allow user to override go executable by running as GOEXE=xxx make ...
|
||||
GOEXE="${GOEXE-go}"
|
||||
|
||||
# Send in a regexp matching the benchmarks you want to run, i.e. './benchSite.sh "YAML"'.
|
||||
# Note the quotes, which will be needed for more complex expressions.
|
||||
# The above will run all variations, but only for front matter YAML.
|
||||
|
||||
echo "Running with BenchmarkSiteBuilding/${1}"
|
||||
|
||||
"${GOEXE}" test -run="NONE" -bench="BenchmarkSiteBuilding/${1}" -test.benchmem=true ./hugolib -memprofile mem.prof -count 3 -cpuprofile cpu.prof
|
||||
@@ -1 +0,0 @@
|
||||
gobench -package=./hugolib -bench="BenchmarkSiteNew/Deep_content_tree"
|
||||
@@ -1 +0,0 @@
|
||||
docker run --rm --mount type=bind,source="$(pwd)",target=/hugo -w /hugo -i -t bepsays/ci-goreleaser:1.11-2 /bin/bash
|
||||
+12
-9
@@ -103,7 +103,8 @@ type configKey struct {
|
||||
type rootCommand struct {
|
||||
Printf func(format string, v ...interface{})
|
||||
Println func(a ...interface{})
|
||||
Out io.Writer
|
||||
StdOut io.Writer
|
||||
StdErr io.Writer
|
||||
|
||||
logger loggers.Logger
|
||||
|
||||
@@ -356,7 +357,7 @@ func (r *rootCommand) getOrCreateHugo(cfg config.Provider, ignoreModuleDoesNotEx
|
||||
}
|
||||
|
||||
func (r *rootCommand) newDepsConfig(conf *commonConfig) deps.DepsCfg {
|
||||
return deps.DepsCfg{Configs: conf.configs, Fs: conf.fs, LogOut: r.logger.Out(), LogLevel: r.logger.Level(), ChangesFromBuild: r.changesFromBuild}
|
||||
return deps.DepsCfg{Configs: conf.configs, Fs: conf.fs, StdOut: r.logger.StdOut(), StdErr: r.logger.StdErr(), LogLevel: r.logger.Level(), ChangesFromBuild: r.changesFromBuild}
|
||||
}
|
||||
|
||||
func (r *rootCommand) Name() string {
|
||||
@@ -421,21 +422,23 @@ func (r *rootCommand) Run(ctx context.Context, cd *simplecobra.Commandeer, args
|
||||
}
|
||||
|
||||
func (r *rootCommand) PreRun(cd, runner *simplecobra.Commandeer) error {
|
||||
r.Out = os.Stdout
|
||||
r.StdOut = os.Stdout
|
||||
r.StdErr = os.Stderr
|
||||
if r.quiet {
|
||||
r.Out = io.Discard
|
||||
r.StdOut = io.Discard
|
||||
r.StdErr = io.Discard
|
||||
}
|
||||
// Used by mkcert (server).
|
||||
log.SetOutput(r.Out)
|
||||
log.SetOutput(r.StdOut)
|
||||
|
||||
r.Printf = func(format string, v ...interface{}) {
|
||||
if !r.quiet {
|
||||
fmt.Fprintf(r.Out, format, v...)
|
||||
fmt.Fprintf(r.StdOut, format, v...)
|
||||
}
|
||||
}
|
||||
r.Println = func(a ...interface{}) {
|
||||
if !r.quiet {
|
||||
fmt.Fprintln(r.Out, a...)
|
||||
fmt.Fprintln(r.StdOut, a...)
|
||||
}
|
||||
}
|
||||
_, running := runner.Command.(*serverCommand)
|
||||
@@ -485,8 +488,8 @@ func (r *rootCommand) createLogger(running bool) (loggers.Logger, error) {
|
||||
optsLogger := loggers.Options{
|
||||
DistinctLevel: logg.LevelWarn,
|
||||
Level: level,
|
||||
Stdout: r.Out,
|
||||
Stderr: r.Out,
|
||||
StdOut: r.StdOut,
|
||||
StdErr: r.StdErr,
|
||||
StoreErrors: running,
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -75,7 +75,9 @@ See https://xyproto.github.io/splash/docs/all.html for a preview of the availabl
|
||||
return err
|
||||
}
|
||||
formatter := html.New(html.WithAllClasses(true))
|
||||
formatter.WriteCSS(os.Stdout, style)
|
||||
w := os.Stdout
|
||||
fmt.Fprintf(w, "/* Generated using: hugo %s */\n\n", strings.Join(os.Args[1:], " "))
|
||||
formatter.WriteCSS(w, style)
|
||||
return nil
|
||||
},
|
||||
withc: func(cmd *cobra.Command, r *rootCommand) {
|
||||
|
||||
@@ -920,7 +920,11 @@ func (c *hugoBuilder) handleEvents(watcher *watcher.Batcher,
|
||||
|
||||
changed := c.changeDetector.changed()
|
||||
if c.changeDetector != nil {
|
||||
lrl.Logf("build changed %d files", len(changed))
|
||||
if len(changed) >= 10 {
|
||||
lrl.Logf("build changed %d files", len(changed))
|
||||
} else {
|
||||
lrl.Logf("build changed %d files: %q", len(changed), changed)
|
||||
}
|
||||
if len(changed) == 0 {
|
||||
// Nothing has changed.
|
||||
return
|
||||
@@ -966,7 +970,7 @@ func (c *hugoBuilder) handleEvents(watcher *watcher.Batcher,
|
||||
pathToRefresh := h.PathSpec.RelURL(paths.ToSlashTrimLeading(otherChanges[0]), false)
|
||||
lrl.Logf("refreshing %q", pathToRefresh)
|
||||
livereload.RefreshPath(pathToRefresh)
|
||||
} else if len(cssChanges) == 0 {
|
||||
} else if len(cssChanges) == 0 || len(otherChanges) > 1 {
|
||||
lrl.Logf("force refresh")
|
||||
livereload.ForceRefresh()
|
||||
}
|
||||
|
||||
+1
-1
@@ -57,7 +57,7 @@ func newListCommand() *listCommand {
|
||||
return err
|
||||
}
|
||||
|
||||
writer := csv.NewWriter(r.Out)
|
||||
writer := csv.NewWriter(r.StdOut)
|
||||
defer writer.Flush()
|
||||
|
||||
writer.Write([]string{
|
||||
|
||||
+4
-2
@@ -32,6 +32,7 @@ import (
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -210,16 +211,17 @@ func (f *fileChangeDetector) changed() []string {
|
||||
}
|
||||
}
|
||||
|
||||
return f.filterIrrelevant(c)
|
||||
return f.filterIrrelevantAndSort(c)
|
||||
}
|
||||
|
||||
func (f *fileChangeDetector) filterIrrelevant(in []string) []string {
|
||||
func (f *fileChangeDetector) filterIrrelevantAndSort(in []string) []string {
|
||||
var filtered []string
|
||||
for _, v := range in {
|
||||
if !f.irrelevantRe.MatchString(v) {
|
||||
filtered = append(filtered, v)
|
||||
}
|
||||
}
|
||||
sort.Strings(filtered)
|
||||
return filtered
|
||||
}
|
||||
|
||||
|
||||
@@ -133,6 +133,21 @@ func IsNotExist(err error) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsExist returns true if the error is a file exists error.
|
||||
// Unlike os.IsExist, this also considers wrapped errors.
|
||||
func IsExist(err error) bool {
|
||||
if os.IsExist(err) {
|
||||
return true
|
||||
}
|
||||
|
||||
// os.IsExist does not consider wrapped errors.
|
||||
if os.IsExist(errors.Unwrap(err)) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
var nilPointerErrRe = regexp.MustCompile(`at <(.*)>: error calling (.*?): runtime error: invalid memory address or nil pointer dereference`)
|
||||
|
||||
const deferredPrefix = "__hdeferred/"
|
||||
|
||||
@@ -384,7 +384,7 @@ func extractPosition(e error) (pos text.Position) {
|
||||
case godartsass.SassError:
|
||||
span := v.Span
|
||||
start := span.Start
|
||||
filename, _ := paths.UrlToFilename(span.Url)
|
||||
filename, _ := paths.UrlStringToFilename(span.Url)
|
||||
pos.Filename = filename
|
||||
pos.Offset = start.Offset
|
||||
pos.ColumnNumber = start.Column
|
||||
|
||||
@@ -223,6 +223,27 @@ func AsTime(v reflect.Value, loc *time.Location) (time.Time, bool) {
|
||||
return time.Time{}, false
|
||||
}
|
||||
|
||||
// ToSliceAny converts the given value to a slice of any if possible.
|
||||
func ToSliceAny(v any) ([]any, bool) {
|
||||
if v == nil {
|
||||
return nil, false
|
||||
}
|
||||
switch vv := v.(type) {
|
||||
case []any:
|
||||
return vv, true
|
||||
default:
|
||||
vvv := reflect.ValueOf(v)
|
||||
if vvv.Kind() == reflect.Slice {
|
||||
out := make([]any, vvv.Len())
|
||||
for i := 0; i < vvv.Len(); i++ {
|
||||
out[i] = vvv.Index(i).Interface()
|
||||
}
|
||||
return out, true
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func CallMethodByName(cxt context.Context, name string, v reflect.Value) []reflect.Value {
|
||||
fn := v.MethodByName(name)
|
||||
var args []reflect.Value
|
||||
|
||||
@@ -50,6 +50,19 @@ func TestIsContextType(t *testing.T) {
|
||||
c.Assert(IsContextType(reflect.TypeOf(valueCtx)), qt.IsTrue)
|
||||
}
|
||||
|
||||
func TestToSliceAny(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
|
||||
checkOK := func(in any, expected []any) {
|
||||
out, ok := ToSliceAny(in)
|
||||
c.Assert(ok, qt.Equals, true)
|
||||
c.Assert(out, qt.DeepEquals, expected)
|
||||
}
|
||||
|
||||
checkOK([]any{1, 2, 3}, []any{1, 2, 3})
|
||||
checkOK([]int{1, 2, 3}, []any{1, 2, 3})
|
||||
}
|
||||
|
||||
func BenchmarkIsContextType(b *testing.B) {
|
||||
type k string
|
||||
b.Run("value", func(b *testing.B) {
|
||||
|
||||
+1
-1
@@ -426,7 +426,7 @@ func DeprecateLevel(item, alternative, version string, level logg.Level) {
|
||||
loggers.Log().Logger().WithLevel(level).WithField(loggers.FieldNameCmd, "deprecated").Logf(msg)
|
||||
}
|
||||
|
||||
// We ususally do about one minor version a month.
|
||||
// We usually do about one minor version a month.
|
||||
// We want people to run at least the current and previous version without any warnings.
|
||||
// We want people who don't update Hugo that often to see the warnings and errors before we remove the feature.
|
||||
func deprecationLogLevelFromVersion(ver string) logg.Level {
|
||||
|
||||
@@ -17,7 +17,7 @@ package hugo
|
||||
// This should be the only one.
|
||||
var CurrentVersion = Version{
|
||||
Major: 0,
|
||||
Minor: 140,
|
||||
Minor: 141,
|
||||
PatchLevel: 0,
|
||||
Suffix: "-DEV",
|
||||
}
|
||||
|
||||
@@ -40,8 +40,8 @@ func newNoAnsiEscapeHandler(outWriter, errWriter io.Writer, noLevelPrefix bool,
|
||||
|
||||
type noAnsiEscapeHandler struct {
|
||||
mu sync.Mutex
|
||||
outWriter io.Writer // Defaults to os.Stdout.
|
||||
errWriter io.Writer // Defaults to os.Stderr.
|
||||
outWriter io.Writer
|
||||
errWriter io.Writer
|
||||
predicate func(*logg.Entry) bool
|
||||
noLevelPrefix bool
|
||||
}
|
||||
|
||||
+25
-21
@@ -38,8 +38,8 @@ var (
|
||||
// Options defines options for the logger.
|
||||
type Options struct {
|
||||
Level logg.Level
|
||||
Stdout io.Writer
|
||||
Stderr io.Writer
|
||||
StdOut io.Writer
|
||||
StdErr io.Writer
|
||||
DistinctLevel logg.Level
|
||||
StoreErrors bool
|
||||
HandlerPost func(e *logg.Entry) error
|
||||
@@ -48,21 +48,22 @@ type Options struct {
|
||||
|
||||
// New creates a new logger with the given options.
|
||||
func New(opts Options) Logger {
|
||||
if opts.Stdout == nil {
|
||||
opts.Stdout = os.Stdout
|
||||
if opts.StdOut == nil {
|
||||
opts.StdOut = os.Stdout
|
||||
}
|
||||
if opts.Stderr == nil {
|
||||
opts.Stderr = os.Stdout
|
||||
if opts.StdErr == nil {
|
||||
opts.StdErr = os.Stderr
|
||||
}
|
||||
|
||||
if opts.Level == 0 {
|
||||
opts.Level = logg.LevelWarn
|
||||
}
|
||||
|
||||
var logHandler logg.Handler
|
||||
if terminal.PrintANSIColors(os.Stdout) {
|
||||
logHandler = newDefaultHandler(opts.Stdout, opts.Stderr)
|
||||
if terminal.PrintANSIColors(os.Stderr) {
|
||||
logHandler = newDefaultHandler(opts.StdErr, opts.StdErr)
|
||||
} else {
|
||||
logHandler = newNoAnsiEscapeHandler(opts.Stdout, opts.Stderr, false, nil)
|
||||
logHandler = newNoAnsiEscapeHandler(opts.StdErr, opts.StdErr, false, nil)
|
||||
}
|
||||
|
||||
errorsw := &strings.Builder{}
|
||||
@@ -137,7 +138,8 @@ func New(opts Options) Logger {
|
||||
logCounters: logCounters,
|
||||
errors: errorsw,
|
||||
reset: reset,
|
||||
out: opts.Stdout,
|
||||
stdOut: opts.StdOut,
|
||||
stdErr: opts.StdErr,
|
||||
level: opts.Level,
|
||||
logger: logger,
|
||||
tracel: l.WithLevel(logg.LevelTrace),
|
||||
@@ -153,8 +155,6 @@ func NewDefault() Logger {
|
||||
opts := Options{
|
||||
DistinctLevel: logg.LevelWarn,
|
||||
Level: logg.LevelWarn,
|
||||
Stdout: os.Stdout,
|
||||
Stderr: os.Stdout,
|
||||
}
|
||||
return New(opts)
|
||||
}
|
||||
@@ -163,8 +163,6 @@ func NewTrace() Logger {
|
||||
opts := Options{
|
||||
DistinctLevel: logg.LevelWarn,
|
||||
Level: logg.LevelTrace,
|
||||
Stdout: os.Stdout,
|
||||
Stderr: os.Stdout,
|
||||
}
|
||||
return New(opts)
|
||||
}
|
||||
@@ -189,7 +187,8 @@ type Logger interface {
|
||||
Level() logg.Level
|
||||
LoggCount(logg.Level) int
|
||||
Logger() logg.Logger
|
||||
Out() io.Writer
|
||||
StdOut() io.Writer
|
||||
StdErr() io.Writer
|
||||
Printf(format string, v ...any)
|
||||
Println(v ...any)
|
||||
PrintTimerIfDelayed(start time.Time, name string)
|
||||
@@ -207,7 +206,8 @@ type logAdapter struct {
|
||||
logCounters *logLevelCounter
|
||||
errors *strings.Builder
|
||||
reset func()
|
||||
out io.Writer
|
||||
stdOut io.Writer
|
||||
stdErr io.Writer
|
||||
level logg.Level
|
||||
logger logg.Logger
|
||||
tracel logg.LevelLogger
|
||||
@@ -259,8 +259,12 @@ func (l *logAdapter) Logger() logg.Logger {
|
||||
return l.logger
|
||||
}
|
||||
|
||||
func (l *logAdapter) Out() io.Writer {
|
||||
return l.out
|
||||
func (l *logAdapter) StdOut() io.Writer {
|
||||
return l.stdOut
|
||||
}
|
||||
|
||||
func (l *logAdapter) StdErr() io.Writer {
|
||||
return l.stdErr
|
||||
}
|
||||
|
||||
// PrintTimerIfDelayed prints a time statement to the FEEDBACK logger
|
||||
@@ -271,7 +275,7 @@ func (l *logAdapter) PrintTimerIfDelayed(start time.Time, name string) {
|
||||
if milli < 500 {
|
||||
return
|
||||
}
|
||||
l.Printf("%s in %v ms", name, milli)
|
||||
fmt.Fprintf(l.stdErr, "%s in %v ms", name, milli)
|
||||
}
|
||||
|
||||
func (l *logAdapter) Printf(format string, v ...any) {
|
||||
@@ -279,11 +283,11 @@ func (l *logAdapter) Printf(format string, v ...any) {
|
||||
if !strings.HasSuffix(format, "\n") {
|
||||
format += "\n"
|
||||
}
|
||||
fmt.Fprintf(l.out, format, v...)
|
||||
fmt.Fprintf(l.stdOut, format, v...)
|
||||
}
|
||||
|
||||
func (l *logAdapter) Println(v ...any) {
|
||||
fmt.Fprintln(l.out, v...)
|
||||
fmt.Fprintln(l.stdOut, v...)
|
||||
}
|
||||
|
||||
func (l *logAdapter) Reset() {
|
||||
|
||||
@@ -31,8 +31,8 @@ func TestLogDistinct(t *testing.T) {
|
||||
opts := loggers.Options{
|
||||
DistinctLevel: logg.LevelWarn,
|
||||
StoreErrors: true,
|
||||
Stdout: io.Discard,
|
||||
Stderr: io.Discard,
|
||||
StdOut: io.Discard,
|
||||
StdErr: io.Discard,
|
||||
}
|
||||
|
||||
l := loggers.New(opts)
|
||||
@@ -54,8 +54,8 @@ func TestHookLast(t *testing.T) {
|
||||
HandlerPost: func(e *logg.Entry) error {
|
||||
panic(e.Message)
|
||||
},
|
||||
Stdout: io.Discard,
|
||||
Stderr: io.Discard,
|
||||
StdOut: io.Discard,
|
||||
StdErr: io.Discard,
|
||||
}
|
||||
|
||||
l := loggers.New(opts)
|
||||
@@ -70,8 +70,8 @@ func TestOptionStoreErrors(t *testing.T) {
|
||||
|
||||
opts := loggers.Options{
|
||||
StoreErrors: true,
|
||||
Stderr: &sb,
|
||||
Stdout: &sb,
|
||||
StdErr: &sb,
|
||||
StdOut: &sb,
|
||||
}
|
||||
|
||||
l := loggers.New(opts)
|
||||
@@ -131,8 +131,8 @@ func TestReset(t *testing.T) {
|
||||
opts := loggers.Options{
|
||||
StoreErrors: true,
|
||||
DistinctLevel: logg.LevelWarn,
|
||||
Stdout: io.Discard,
|
||||
Stderr: io.Discard,
|
||||
StdOut: io.Discard,
|
||||
StdErr: io.Discard,
|
||||
}
|
||||
|
||||
l := loggers.New(opts)
|
||||
|
||||
@@ -113,11 +113,14 @@ func (c *Cache[K, T]) set(key K, value T) {
|
||||
}
|
||||
|
||||
// ForEeach calls the given function for each key/value pair in the cache.
|
||||
func (c *Cache[K, T]) ForEeach(f func(K, T)) {
|
||||
// If the function returns false, the iteration stops.
|
||||
func (c *Cache[K, T]) ForEeach(f func(K, T) bool) {
|
||||
c.RLock()
|
||||
defer c.RUnlock()
|
||||
for k, v := range c.m {
|
||||
f(k, v)
|
||||
if !f(k, v) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -185,7 +185,7 @@ func TestScratchSetInMap(t *testing.T) {
|
||||
scratch.SetInMap("key", "zyx", "Zyx")
|
||||
scratch.SetInMap("key", "abc", "Abc (updated)")
|
||||
scratch.SetInMap("key", "def", "Def")
|
||||
c.Assert(scratch.GetSortedMapValues("key"), qt.DeepEquals, []any{0: "Abc (updated)", 1: "Def", 2: "Lux", 3: "Zyx"})
|
||||
c.Assert(scratch.GetSortedMapValues("key"), qt.DeepEquals, any([]any{"Abc (updated)", "Def", "Lux", "Zyx"}))
|
||||
}
|
||||
|
||||
func TestScratchDeleteInMap(t *testing.T) {
|
||||
@@ -199,7 +199,7 @@ func TestScratchDeleteInMap(t *testing.T) {
|
||||
scratch.DeleteInMap("key", "abc")
|
||||
scratch.SetInMap("key", "def", "Def")
|
||||
scratch.DeleteInMap("key", "lmn") // Do nothing
|
||||
c.Assert(scratch.GetSortedMapValues("key"), qt.DeepEquals, []any{0: "Def", 1: "Lux", 2: "Zyx"})
|
||||
c.Assert(scratch.GetSortedMapValues("key"), qt.DeepEquals, any([]any{"Def", "Lux", "Zyx"}))
|
||||
}
|
||||
|
||||
func TestScratchGetSortedMapValues(t *testing.T) {
|
||||
|
||||
+104
-26
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021 The Hugo Authors. All rights reserved.
|
||||
// Copyright 2024 The Hugo Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"net/url"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -159,31 +160,6 @@ func Uglify(in string) string {
|
||||
return path.Clean(in)
|
||||
}
|
||||
|
||||
// UrlToFilename converts the URL s to a filename.
|
||||
// If ParseRequestURI fails, the input is just converted to OS specific slashes and returned.
|
||||
func UrlToFilename(s string) (string, bool) {
|
||||
u, err := url.ParseRequestURI(s)
|
||||
if err != nil {
|
||||
return filepath.FromSlash(s), false
|
||||
}
|
||||
|
||||
p := u.Path
|
||||
|
||||
if p == "" {
|
||||
p, _ = url.QueryUnescape(u.Opaque)
|
||||
return filepath.FromSlash(p), true
|
||||
}
|
||||
|
||||
p = filepath.FromSlash(p)
|
||||
|
||||
if u.Host != "" {
|
||||
// C:\data\file.txt
|
||||
p = strings.ToUpper(u.Host) + ":" + p
|
||||
}
|
||||
|
||||
return p, true
|
||||
}
|
||||
|
||||
// URLEscape escapes unicode letters.
|
||||
func URLEscape(uri string) string {
|
||||
// escape unicode letters
|
||||
@@ -193,3 +169,105 @@ func URLEscape(uri string) string {
|
||||
}
|
||||
return u.String()
|
||||
}
|
||||
|
||||
// TrimExt trims the extension from a path..
|
||||
func TrimExt(in string) string {
|
||||
return strings.TrimSuffix(in, path.Ext(in))
|
||||
}
|
||||
|
||||
// From https://github.com/golang/go/blob/e0c76d95abfc1621259864adb3d101cf6f1f90fc/src/cmd/go/internal/web/url.go#L45
|
||||
func UrlFromFilename(filename string) (*url.URL, error) {
|
||||
if !filepath.IsAbs(filename) {
|
||||
return nil, fmt.Errorf("filepath must be absolute")
|
||||
}
|
||||
|
||||
// If filename has a Windows volume name, convert the volume to a host and prefix
|
||||
// per https://blogs.msdn.microsoft.com/ie/2006/12/06/file-uris-in-windows/.
|
||||
if vol := filepath.VolumeName(filename); vol != "" {
|
||||
if strings.HasPrefix(vol, `\\`) {
|
||||
filename = filepath.ToSlash(filename[2:])
|
||||
i := strings.IndexByte(filename, '/')
|
||||
|
||||
if i < 0 {
|
||||
// A degenerate case.
|
||||
// \\host.example.com (without a share name)
|
||||
// becomes
|
||||
// file://host.example.com/
|
||||
return &url.URL{
|
||||
Scheme: "file",
|
||||
Host: filename,
|
||||
Path: "/",
|
||||
}, nil
|
||||
}
|
||||
|
||||
// \\host.example.com\Share\path\to\file
|
||||
// becomes
|
||||
// file://host.example.com/Share/path/to/file
|
||||
return &url.URL{
|
||||
Scheme: "file",
|
||||
Host: filename[:i],
|
||||
Path: filepath.ToSlash(filename[i:]),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// C:\path\to\file
|
||||
// becomes
|
||||
// file:///C:/path/to/file
|
||||
return &url.URL{
|
||||
Scheme: "file",
|
||||
Path: "/" + filepath.ToSlash(filename),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// /path/to/file
|
||||
// becomes
|
||||
// file:///path/to/file
|
||||
return &url.URL{
|
||||
Scheme: "file",
|
||||
Path: filepath.ToSlash(filename),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UrlToFilename converts the URL s to a filename.
|
||||
// If ParseRequestURI fails, the input is just converted to OS specific slashes and returned.
|
||||
func UrlStringToFilename(s string) (string, bool) {
|
||||
u, err := url.ParseRequestURI(s)
|
||||
if err != nil {
|
||||
return filepath.FromSlash(s), false
|
||||
}
|
||||
|
||||
p := u.Path
|
||||
|
||||
if p == "" {
|
||||
p, _ = url.QueryUnescape(u.Opaque)
|
||||
return filepath.FromSlash(p), false
|
||||
}
|
||||
|
||||
if runtime.GOOS != "windows" {
|
||||
return p, true
|
||||
}
|
||||
|
||||
if len(p) == 0 || p[0] != '/' {
|
||||
return filepath.FromSlash(p), false
|
||||
}
|
||||
|
||||
p = filepath.FromSlash(p)
|
||||
|
||||
if len(u.Host) == 1 {
|
||||
// file://c/Users/...
|
||||
return strings.ToUpper(u.Host) + ":" + p, true
|
||||
}
|
||||
|
||||
if u.Host != "" && u.Host != "localhost" {
|
||||
if filepath.VolumeName(u.Host) != "" {
|
||||
return "", false
|
||||
}
|
||||
return `\\` + u.Host + p, true
|
||||
}
|
||||
|
||||
if vol := filepath.VolumeName(p[1:]); vol == "" || strings.HasPrefix(vol, `\\`) {
|
||||
return "", false
|
||||
}
|
||||
|
||||
return p[1:], true
|
||||
}
|
||||
|
||||
@@ -19,6 +19,13 @@ type Closer interface {
|
||||
Close() error
|
||||
}
|
||||
|
||||
// CloserFunc is a convenience type to create a Closer from a function.
|
||||
type CloserFunc func() error
|
||||
|
||||
func (f CloserFunc) Close() error {
|
||||
return f()
|
||||
}
|
||||
|
||||
type CloseAdder interface {
|
||||
Add(Closer)
|
||||
}
|
||||
|
||||
@@ -65,6 +65,9 @@ func (q *EvictingStringQueue) Len() int {
|
||||
|
||||
// Contains returns whether the queue contains v.
|
||||
func (q *EvictingStringQueue) Contains(v string) bool {
|
||||
if q == nil {
|
||||
return false
|
||||
}
|
||||
q.mu.Lock()
|
||||
defer q.mu.Unlock()
|
||||
return q.set[v]
|
||||
|
||||
@@ -505,6 +505,9 @@ type RootConfig struct {
|
||||
// Set this to true to put all languages below their language ID.
|
||||
DefaultContentLanguageInSubdir bool
|
||||
|
||||
// Disable generation of redirect to the default language when DefaultContentLanguageInSubdir is enabled.
|
||||
DisableDefaultLanguageRedirect bool
|
||||
|
||||
// Disable creation of alias redirect pages.
|
||||
DisableAliases bool
|
||||
|
||||
@@ -731,7 +734,7 @@ func (c *Configs) Validate(logger loggers.Logger) error {
|
||||
|
||||
// transientErr returns the last transient error found during config compilation.
|
||||
func (c *Configs) transientErr() error {
|
||||
for _, l := range c.LanguageConfigSlice {
|
||||
for _, l := range c.LanguageConfigMap {
|
||||
if l.C.transientErr != nil {
|
||||
return l.C.transientErr
|
||||
}
|
||||
@@ -748,7 +751,6 @@ func (c *Configs) Init() error {
|
||||
var languages langs.Languages
|
||||
defaultContentLanguage := c.Base.DefaultContentLanguage
|
||||
for k, v := range c.LanguageConfigMap {
|
||||
c.LanguageConfigSlice = append(c.LanguageConfigSlice, v)
|
||||
languageConf := v.Languages[k]
|
||||
language, err := langs.NewLanguage(k, defaultContentLanguage, v.TimeZone, languageConf)
|
||||
if err != nil {
|
||||
|
||||
@@ -175,3 +175,43 @@ func TestMapUglyURLs(t *testing.T) {
|
||||
b.Assert(c.C.IsUglyURLSection("posts"), qt.IsTrue)
|
||||
b.Assert(c.C.IsUglyURLSection("blog"), qt.IsFalse)
|
||||
}
|
||||
|
||||
// Issue 13199
|
||||
func TestInvalidOutputFormat(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
files := `
|
||||
-- hugo.toml --
|
||||
disableKinds = ['page','rss','section','sitemap','taxonomy','term']
|
||||
[outputs]
|
||||
home = ['html','foo']
|
||||
-- layouts/index.html --
|
||||
x
|
||||
`
|
||||
|
||||
b, err := hugolib.TestE(t, files)
|
||||
b.Assert(err, qt.IsNotNil)
|
||||
b.Assert(err.Error(), qt.Contains, `failed to create config: unknown output format "foo" for kind "home"`)
|
||||
}
|
||||
|
||||
// Issue 13201
|
||||
func TestLanguageConfigSlice(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
files := `
|
||||
-- hugo.toml --
|
||||
disableKinds = ['page','rss','section','sitemap','taxonomy','term']
|
||||
[languages.en]
|
||||
title = 'TITLE_EN'
|
||||
weight = 2
|
||||
[languages.de]
|
||||
title = 'TITLE_DE'
|
||||
weight = 1
|
||||
[languages.fr]
|
||||
title = 'TITLE_FR'
|
||||
weight = 3
|
||||
`
|
||||
|
||||
b := hugolib.Test(t, files)
|
||||
b.Assert(b.H.Configs.LanguageConfigSlice[0].Title, qt.Equals, `TITLE_DE`)
|
||||
}
|
||||
|
||||
@@ -137,11 +137,11 @@ func (c ConfigLanguage) Watching() bool {
|
||||
return c.m.Base.Internal.Watch
|
||||
}
|
||||
|
||||
func (c ConfigLanguage) NewIdentityManager(name string) identity.Manager {
|
||||
func (c ConfigLanguage) NewIdentityManager(name string, opts ...identity.ManagerOption) identity.Manager {
|
||||
if !c.Watching() {
|
||||
return identity.NopManager
|
||||
}
|
||||
return identity.NewManager(name)
|
||||
return identity.NewManager(name, opts...)
|
||||
}
|
||||
|
||||
func (c ConfigLanguage) ContentTypes() config.ContentTypesProvider {
|
||||
|
||||
@@ -58,7 +58,7 @@ type AllProvider interface {
|
||||
BuildDrafts() bool
|
||||
Running() bool
|
||||
Watching() bool
|
||||
NewIdentityManager(name string) identity.Manager
|
||||
NewIdentityManager(name string, opts ...identity.ManagerOption) identity.Manager
|
||||
FastRenderMode() bool
|
||||
PrintUnusedTemplates() bool
|
||||
EnableMissingTranslationPlaceholders() bool
|
||||
|
||||
Vendored
+54
-12
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
@@ -23,6 +24,7 @@ import (
|
||||
"github.com/gohugoio/hugo/helpers"
|
||||
"github.com/gohugoio/hugo/hugofs"
|
||||
"github.com/gohugoio/hugo/identity"
|
||||
"github.com/gohugoio/hugo/internal/js"
|
||||
"github.com/gohugoio/hugo/internal/warpc"
|
||||
"github.com/gohugoio/hugo/media"
|
||||
"github.com/gohugoio/hugo/resources/page"
|
||||
@@ -47,6 +49,9 @@ type Deps struct {
|
||||
// The templates to use. This will usually implement the full tpl.TemplateManager.
|
||||
tmplHandlers *tpl.TemplateHandlers
|
||||
|
||||
// The template funcs.
|
||||
TmplFuncMap map[string]any
|
||||
|
||||
// The file systems to use.
|
||||
Fs *hugofs.Fs `json:"-"`
|
||||
|
||||
@@ -83,10 +88,13 @@ type Deps struct {
|
||||
Metrics metrics.Provider
|
||||
|
||||
// BuildStartListeners will be notified before a build starts.
|
||||
BuildStartListeners *Listeners
|
||||
BuildStartListeners *Listeners[any]
|
||||
|
||||
// BuildEndListeners will be notified after a build finishes.
|
||||
BuildEndListeners *Listeners
|
||||
BuildEndListeners *Listeners[any]
|
||||
|
||||
// OnChangeListeners will be notified when something changes.
|
||||
OnChangeListeners *Listeners[identity.Identity]
|
||||
|
||||
// Resources that gets closed when the build is done or the server shuts down.
|
||||
BuildClosers *types.Closers
|
||||
@@ -98,6 +106,12 @@ type Deps struct {
|
||||
// TODO(bep) rethink this re. a plugin setup, but this will have to do for now.
|
||||
WasmDispatchers *warpc.Dispatchers
|
||||
|
||||
// The JS batcher client.
|
||||
JSBatcherClient js.BatcherClient
|
||||
|
||||
// The JS batcher client.
|
||||
// JSBatcherClient *esbuild.BatcherClient
|
||||
|
||||
isClosed bool
|
||||
|
||||
*globalErrHandler
|
||||
@@ -154,17 +168,21 @@ func (d *Deps) Init() error {
|
||||
}
|
||||
|
||||
if d.BuildStartListeners == nil {
|
||||
d.BuildStartListeners = &Listeners{}
|
||||
d.BuildStartListeners = &Listeners[any]{}
|
||||
}
|
||||
|
||||
if d.BuildEndListeners == nil {
|
||||
d.BuildEndListeners = &Listeners{}
|
||||
d.BuildEndListeners = &Listeners[any]{}
|
||||
}
|
||||
|
||||
if d.BuildClosers == nil {
|
||||
d.BuildClosers = &types.Closers{}
|
||||
}
|
||||
|
||||
if d.OnChangeListeners == nil {
|
||||
d.OnChangeListeners = &Listeners[identity.Identity]{}
|
||||
}
|
||||
|
||||
if d.Metrics == nil && d.Conf.TemplateMetrics() {
|
||||
d.Metrics = metrics.NewProvider(d.Conf.TemplateMetricsHints())
|
||||
}
|
||||
@@ -268,6 +286,23 @@ func (d *Deps) Compile(prototype *Deps) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MkdirTemp returns a temporary directory path that will be cleaned up on exit.
|
||||
func (d Deps) MkdirTemp(pattern string) (string, error) {
|
||||
filename, err := os.MkdirTemp("", pattern)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
d.BuildClosers.Add(
|
||||
types.CloserFunc(
|
||||
func() error {
|
||||
return os.RemoveAll(filename)
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
return filename, nil
|
||||
}
|
||||
|
||||
type globalErrHandler struct {
|
||||
logger loggers.Logger
|
||||
|
||||
@@ -306,15 +341,16 @@ func (e *globalErrHandler) StopErrorCollector() {
|
||||
}
|
||||
|
||||
// Listeners represents an event listener.
|
||||
type Listeners struct {
|
||||
type Listeners[T any] struct {
|
||||
sync.Mutex
|
||||
|
||||
// A list of funcs to be notified about an event.
|
||||
listeners []func()
|
||||
// If the return value is true, the listener will be removed.
|
||||
listeners []func(...T) bool
|
||||
}
|
||||
|
||||
// Add adds a function to a Listeners instance.
|
||||
func (b *Listeners) Add(f func()) {
|
||||
func (b *Listeners[T]) Add(f func(...T) bool) {
|
||||
if b == nil {
|
||||
return
|
||||
}
|
||||
@@ -324,12 +360,16 @@ func (b *Listeners) Add(f func()) {
|
||||
}
|
||||
|
||||
// Notify executes all listener functions.
|
||||
func (b *Listeners) Notify() {
|
||||
func (b *Listeners[T]) Notify(vs ...T) {
|
||||
b.Lock()
|
||||
defer b.Unlock()
|
||||
temp := b.listeners[:0]
|
||||
for _, notify := range b.listeners {
|
||||
notify()
|
||||
if !notify(vs...) {
|
||||
temp = append(temp, notify)
|
||||
}
|
||||
}
|
||||
b.listeners = temp
|
||||
}
|
||||
|
||||
// ResourceProvider is used to create and refresh, and clone resources needed.
|
||||
@@ -372,9 +412,11 @@ type DepsCfg struct {
|
||||
// The logging level to use.
|
||||
LogLevel logg.Level
|
||||
|
||||
// Where to write the logs.
|
||||
// Currently we typically write everything to stdout.
|
||||
LogOut io.Writer
|
||||
// Logging output.
|
||||
StdErr io.Writer
|
||||
|
||||
// The console output.
|
||||
StdOut io.Writer
|
||||
|
||||
// The file systems to use
|
||||
Fs *hugofs.Fs
|
||||
|
||||
@@ -22,8 +22,15 @@
|
||||
{{ $releases = where $releases "draft" false }}
|
||||
{{ $releases = where $releases "prerelease" false }}
|
||||
{{ range $releases | first 20 }}
|
||||
{{ $publishDate := .published_at | time.AsTime }}
|
||||
|
||||
{{/* Correct the v0.138.0 release date. See https://github.com/gohugoio/hugo/issues/13066. */}}
|
||||
{{ if eq .name "v0.138.0" }}
|
||||
{{ $publishDate = "2024-11-06T11:22:34Z" | time.AsTime }}
|
||||
{{ end }}
|
||||
|
||||
{{ $ctx := dict
|
||||
"Date" (.published_at | time.AsTime)
|
||||
"Date" $publishDate
|
||||
"Title" (printf "Release %s" .name)
|
||||
"Permalink" .html_url
|
||||
"Section" "news"
|
||||
|
||||
@@ -21,14 +21,21 @@
|
||||
{{- $releases = where $releases "draft" false }}
|
||||
{{- $releases = where $releases "prerelease" false }}
|
||||
{{- range $releases | first 20 }}
|
||||
{{- $publishDate := .published_at | time.AsTime }}
|
||||
|
||||
{{- /* Correct the v0.138.0 release date. See https://github.com/gohugoio/hugo/issues/13066. */}}
|
||||
{{- if eq .name "v0.138.0" }}
|
||||
{{- $publishDate = "2024-11-06T11:22:34Z" | time.AsTime }}
|
||||
{{- end }}
|
||||
|
||||
{{- $summary := printf
|
||||
"Hugo %s was released on %s. See [release notes](%s) for details."
|
||||
.tag_name
|
||||
(.published_at | time.AsTime | time.Format "2 Jan 2006")
|
||||
($publishDate | time.AsTime | time.Format "2 Jan 2006")
|
||||
.html_url
|
||||
}}
|
||||
{{- $ctx := dict
|
||||
"PublishDate" (.published_at | time.AsTime)
|
||||
"PublishDate" $publishDate
|
||||
"Title" (printf "Release %s" .name)
|
||||
"Permalink" .html_url
|
||||
"Section" "news"
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@
|
||||
<h2>{{ $heading }}</h2>
|
||||
<ul>
|
||||
{{- range . }}
|
||||
<li><a href="{{ .RelPermalink }}">{{ .Title }}</a></li>
|
||||
<li><a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a></li>
|
||||
{{- end }}
|
||||
</ul>
|
||||
{{- end }}
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
# github.com/gohugoio/gohugoioTheme v0.0.0-20241105120803-6c6e5fb8f8af
|
||||
# github.com/gohugoio/gohugoioTheme v0.0.0-20241119115653-b92d27ede3e1
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
# Do not remove front matter.
|
||||
_comment: Do not remove front matter.
|
||||
---
|
||||
|
||||
| Kind | Description | Example |
|
||||
|
||||
@@ -52,7 +52,7 @@ Hugo does not provide a built-in template for Mermaid diagrams. Create your own
|
||||
|
||||
{{< code file=layouts/_default/_markup/render-codeblock-mermaid.html >}}
|
||||
<pre class="mermaid">
|
||||
{{- .Inner | safeHTML }}
|
||||
{{- .Inner | htmlEscape | safeHTML }}
|
||||
</pre>
|
||||
{{ .Page.Store.Set "hasMermaid" true }}
|
||||
{{< /code >}}
|
||||
|
||||
@@ -94,6 +94,50 @@ Example usage:
|
||||
|
||||
Although you can call this shortcode using the `{{</* */>}}` notation, computationally it is more efficient to call it using the `{{%/* */%}}` notation as shown above.
|
||||
|
||||
### details
|
||||
|
||||
{{< new-in 0.140.0 >}}
|
||||
|
||||
{{% note %}}
|
||||
To override Hugo's embedded `details` shortcode, copy the [source code] to a file with the same name in the layouts/shortcodes directory.
|
||||
|
||||
[source code]: {{% eturl details %}}
|
||||
{{% /note %}}
|
||||
|
||||
Use the `details` shortcode to create a `details` HTML element. For example:
|
||||
|
||||
```text
|
||||
{{</* details summary="See the details" */>}}
|
||||
This is a **bold** word.
|
||||
{{</* /details */>}}
|
||||
```
|
||||
|
||||
Hugo renders this to:
|
||||
|
||||
```html
|
||||
<details>
|
||||
<summary>See the details</summary>
|
||||
<p>This is a <strong>bold</strong> word.</p>
|
||||
</details>
|
||||
```
|
||||
|
||||
The details shortcode accepts these named arguments:
|
||||
|
||||
summary
|
||||
: (`string`) The content of the child `summary` element rendered from Markdown to HTML. Default is `Details`.
|
||||
|
||||
open
|
||||
: (`bool`) Whether to initially display the content of the `details` element. Default is `false`.
|
||||
|
||||
class
|
||||
: (`string`) The value of the element's `class` attribute.
|
||||
|
||||
name
|
||||
: (`string`) The value of the element's `name` attribute.
|
||||
|
||||
title
|
||||
: (`string`) The value of the element's `title` attribute.
|
||||
|
||||
### figure
|
||||
|
||||
{{% note %}}
|
||||
|
||||
@@ -37,7 +37,9 @@ Please follow these guidelines:
|
||||
|
||||
### Style
|
||||
|
||||
Although we do not strictly adhere to the [Microsoft Writing Style Guide], it is an excellent resource for questions related to style, grammar, and voice.
|
||||
Please adhere to Google's [developer documentation style guide].
|
||||
|
||||
[developer documentation style guide]: https://developers.google.com/style
|
||||
|
||||
#### Terminology
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
# Do not remove front matter.
|
||||
_comment: Do not remove front matter.
|
||||
---
|
||||
|
||||
Path|Pattern|Match
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
# Do not remove front matter.
|
||||
_comment: Do not remove front matter.
|
||||
---
|
||||
|
||||
Hugo uses Go's [text/template] and [html/template] packages.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
# Do not remove front matter.
|
||||
_comment: Do not remove front matter.
|
||||
---
|
||||
|
||||
{{% note %}}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
# Do not remove front matter.
|
||||
_comment: Do not remove front matter.
|
||||
---
|
||||
|
||||
When specifying the regular expression, use a raw [string literal] (backticks) instead of an interpreted string literal (double quotes) to simplify the syntax. With an interpreted string literal you must escape backslashes.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
# Do not remove front matter.
|
||||
_comment: Do not remove front matter.
|
||||
---
|
||||
|
||||
Format a `time.Time` value based on [Go's reference time]:
|
||||
|
||||
@@ -124,6 +124,6 @@ module.exports = {
|
||||
```
|
||||
|
||||
[node.js]: https://nodejs.org/en/download
|
||||
[postcss plugins]: https://www.postcss.parts/
|
||||
[postcss plugins]: https://postcss.org/docs/postcss-plugins
|
||||
[supported file name]: https://github.com/postcss/postcss-load-config#usage
|
||||
[transpile to CSS]: /functions/css/sass/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
# Do not remove front matter.
|
||||
_comment: Do not remove front matter.
|
||||
---
|
||||
|
||||
The documentation for Go's [fmt] package describes the structure and content of the format string.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
# Do not remove front matter.
|
||||
_comment: Do not remove front matter.
|
||||
---
|
||||
|
||||
See Go's [text/template] documentation for more information.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
# Do not remove front matter.
|
||||
_comment: Do not remove front matter.
|
||||
---
|
||||
|
||||
The falsy values are `false`, `0`, any `nil` pointer or interface value, any array, slice, map, or string of length zero, and zero `time.Time` values.
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
---
|
||||
title: hugo.Store
|
||||
description: Returns a global, persistent "scratch pad" to store and manipulate data.
|
||||
categories: []
|
||||
keywords: []
|
||||
action:
|
||||
related:
|
||||
- methods/page/store
|
||||
- methods/site/store
|
||||
- functions/collections/NewScratch
|
||||
returnType: maps.Scratch
|
||||
signatures: [hugo.Store]
|
||||
toc: true
|
||||
---
|
||||
|
||||
{{< new-in 0.139.0 >}}
|
||||
|
||||
The global `hugo.Store` function creates a persistent [scratch pad] to store and manipulate data. To create a locally scoped, use the [`newScratch`] function.
|
||||
|
||||
[`Scratch`]: /functions/hugo/scratch/
|
||||
[`newScratch`]: /functions/collections/newscratch/
|
||||
[scratch pad]: /getting-started/glossary/#scratch-pad
|
||||
|
||||
## Methods
|
||||
|
||||
###### Set
|
||||
|
||||
Sets the value of a given key.
|
||||
|
||||
```go-html-template
|
||||
{{ hugo.Store.Set "greeting" "Hello" }}
|
||||
```
|
||||
|
||||
###### Get
|
||||
|
||||
Gets the value of a given key.
|
||||
|
||||
```go-html-template
|
||||
{{ hugo.Store.Set "greeting" "Hello" }}
|
||||
{{ hugo.Store.Get "greeting" }} → Hello
|
||||
```
|
||||
|
||||
###### Add
|
||||
|
||||
Adds a given value to existing value(s) of the given key.
|
||||
|
||||
For single values, `Add` accepts values that support Go's `+` operator. If the first `Add` for a key is an array or slice, the following adds will be appended to that list.
|
||||
|
||||
```go-html-template
|
||||
{{ hugo.Store.Set "greeting" "Hello" }}
|
||||
{{ hugo.Store.Add "greeting" "Welcome" }}
|
||||
{{ hugo.Store.Get "greeting" }} → HelloWelcome
|
||||
```
|
||||
|
||||
```go-html-template
|
||||
{{ hugo.Store.Set "total" 3 }}
|
||||
{{ hugo.Store.Add "total" 7 }}
|
||||
{{ hugo.Store.Get "total" }} → 10
|
||||
```
|
||||
|
||||
```go-html-template
|
||||
{{ hugo.Store.Set "greetings" (slice "Hello") }}
|
||||
{{ hugo.Store.Add "greetings" (slice "Welcome" "Cheers") }}
|
||||
{{ hugo.Store.Get "greetings" }} → [Hello Welcome Cheers]
|
||||
```
|
||||
|
||||
###### SetInMap
|
||||
|
||||
Takes a `key`, `mapKey` and `value` and adds a map of `mapKey` and `value` to the given `key`.
|
||||
|
||||
```go-html-template
|
||||
{{ hugo.Store.SetInMap "greetings" "english" "Hello" }}
|
||||
{{ hugo.Store.SetInMap "greetings" "french" "Bonjour" }}
|
||||
{{ hugo.Store.Get "greetings" }} → map[english:Hello french:Bonjour]
|
||||
```
|
||||
|
||||
###### DeleteInMap
|
||||
|
||||
Takes a `key` and `mapKey` and removes the map of `mapKey` from the given `key`.
|
||||
|
||||
```go-html-template
|
||||
{{ hugo.Store.SetInMap "greetings" "english" "Hello" }}
|
||||
{{ hugo.Store.SetInMap "greetings" "french" "Bonjour" }}
|
||||
{{ hugo.Store.DeleteInMap "greetings" "english" }}
|
||||
{{ hugo.Store.Get "greetings" }} → map[french:Bonjour]
|
||||
```
|
||||
|
||||
###### GetSortedMapValues
|
||||
|
||||
Returns an array of values from `key` sorted by `mapKey`.
|
||||
|
||||
```go-html-template
|
||||
{{ hugo.Store.SetInMap "greetings" "english" "Hello" }}
|
||||
{{ hugo.Store.SetInMap "greetings" "french" "Bonjour" }}
|
||||
{{ hugo.Store.GetSortedMapValues "greetings" }} → [Hello Bonjour]
|
||||
```
|
||||
|
||||
###### Delete
|
||||
|
||||
Removes the given key.
|
||||
|
||||
```go-html-template
|
||||
{{ hugo.Store.Set "greeting" "Hello" }}
|
||||
{{ hugo.Store.Delete "greeting" }}
|
||||
```
|
||||
|
||||
## Determinate values
|
||||
|
||||
The `Store` method is often used to set scratch pad values within a shortcode, a partial template called by a shortcode, or by a Markdown render hook. In all three cases, the scratch pad values are indeterminate until Hugo renders the page content.
|
||||
|
||||
If you need to access a scratch pad value from a parent template, and the parent template has not yet rendered the page content, you can trigger content rendering by assigning the returned value to a [noop] variable:
|
||||
|
||||
[noop]: /getting-started/glossary/#noop
|
||||
|
||||
```go-html-template
|
||||
{{ $noop := .Content }}
|
||||
{{ hugo.Store.Get "mykey" }}
|
||||
```
|
||||
|
||||
You can also trigger content rendering with the `ContentWithoutSummary`, `FuzzyWordCount`, `Len`, `Plain`, `PlainWords`, `ReadingTime`, `Summary`, `Truncated`, and `WordCount` methods. For example:
|
||||
|
||||
```go-html-template
|
||||
{{ $noop := .WordCount }}
|
||||
{{ hugo.Store.Get "mykey" }}
|
||||
```
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
# Do not remove front matter.
|
||||
_comment: Do not remove front matter.
|
||||
---
|
||||
|
||||
Apply the filter using the [`images.Filter`] function:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
# Do not remove front matter.
|
||||
_comment: Do not remove front matter.
|
||||
---
|
||||
|
||||
If you are a Windows user, and the path to your project contains a space, you must place the PostCSS configuration within the package.json file. See [this example] and issue [#7333].
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
# Do not remove front matter.
|
||||
_comment: Do not remove front matter.
|
||||
---
|
||||
|
||||
Format|Time zone
|
||||
|
||||
@@ -230,7 +230,7 @@ Let's add a `lang` attribute to the `title` nodes of our RSS feed, and a namespa
|
||||
<language>en-US</language>
|
||||
<atom:link href="https://example.org/books/index.xml" rel="self" type="application/rss+xml" />
|
||||
<item>
|
||||
<title lang="fr">The Hunchback of Notre Dame</title>
|
||||
<title lang="en">The Hunchback of Notre Dame</title>
|
||||
<description>Written by Victor Hugo</description>
|
||||
<isbn:number>9780140443530</isbn:number>
|
||||
<link>https://example.org/books/the-hunchback-of-notre-dame/</link>
|
||||
@@ -238,7 +238,7 @@ Let's add a `lang` attribute to the `title` nodes of our RSS feed, and a namespa
|
||||
<guid>https://example.org/books/the-hunchback-of-notre-dame/</guid>
|
||||
</item>
|
||||
<item>
|
||||
<title lang="en">Les Misérables</title>
|
||||
<title lang="fr">Les Misérables</title>
|
||||
<description>Written by Victor Hugo</description>
|
||||
<isbn:number>9780451419439</isbn:number>
|
||||
<link>https://example.org/books/les-miserables/</link>
|
||||
@@ -266,7 +266,7 @@ Each item node looks like this:
|
||||
"pubDate": "Mon, 09 Oct 2023 09:27:12 -0700",
|
||||
"title": {
|
||||
"#text": "The Hunchback of Notre Dame",
|
||||
"-lang": "fr"
|
||||
"-lang": "en"
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -290,8 +290,8 @@ Hugo renders this to:
|
||||
|
||||
```html
|
||||
<ul>
|
||||
<li>The Hunchback of Notre Dame (fr) 9780140443530</li>
|
||||
<li>Les Misérables (en) 9780451419439</li>
|
||||
<li>The Hunchback of Notre Dame (en) 9780140443530</li>
|
||||
<li>Les Misérables (fr) 9780451419439</li>
|
||||
</ul>
|
||||
```
|
||||
|
||||
|
||||
@@ -28,10 +28,10 @@ This controls the behavior of the `anchorize` function and the generation of hea
|
||||
Set `autoHeadingIDType` to one of:
|
||||
|
||||
github
|
||||
: Compatible with GitHub. This is the default, and strongly recommended.
|
||||
: Compatible with GitHub. This is the default.
|
||||
|
||||
github-ascii
|
||||
: Similar to the "github" setting, but removes non-ASCII characters.
|
||||
: Similar to the `github` setting, but removes non-ASCII characters.
|
||||
|
||||
blackfriday
|
||||
: Provided for backwards compatibility with Hugo v0.59.1 and earlier. This option will be removed in a future release.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
# Do not remove front matter.
|
||||
_comment: Do not remove front matter.
|
||||
---
|
||||
|
||||
The [`anchorize`] and [`urlize`] functions are similar:
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
---
|
||||
title: Host on AWS Amplify
|
||||
description: Develop and deploy a cloud-powered web app with AWS Amplify.
|
||||
categories: [hosting and deployment]
|
||||
keywords: [hosting,amplify]
|
||||
menu:
|
||||
docs:
|
||||
parent: hosting-and-deployment
|
||||
toc: true
|
||||
---
|
||||
|
||||
In this guide we'll walk through how to deploy and host your Hugo site using the [AWS Amplify Console](https://console.amplify.aws).
|
||||
|
||||
AWS Amplify is a combination of client library, CLI toolchain, and a Console for continuous deployment and hosting. The Amplify CLI and library allow developers to get up & running with full-stack cloud-powered applications with features like authentication, storage, serverless GraphQL or REST APIs, analytics, Lambda functions, & more. The Amplify Console provides continuous deployment and hosting for modern web apps (single page apps and static site generators). Continuous deployment allows developers to deploy updates to their web app on every code commit to their Git repository. Hosting includes features such as globally available CDNs, easy custom domain setup + HTTPS, feature branch deployments, and password protection.
|
||||
|
||||
## Pre-requisites
|
||||
|
||||
* [Sign up for an AWS Account](https://portal.aws.amazon.com/billing/signup?redirect_url=https%3A%2F%2Faws.amazon.com%2Fregistration-confirmation). There are no upfront charges or any term commitments to create an AWS account and signing up gives you immediate access to the AWS Free Tier.
|
||||
* You have an account with GitHub, GitLab, or Bitbucket.
|
||||
* You have completed the [Quick Start] or have a Hugo website you are ready to deploy and share with the world.
|
||||
|
||||
## Hosting
|
||||
|
||||
1. Log in to the [AWS Amplify Console](https://console.aws.amazon.com/amplify/home) and choose Get Started under Deploy.
|
||||

|
||||
|
||||
1. Connect a branch from your GitHub, Bitbucket, GitLab, or AWS CodeCommit repository. Connecting your repository allows Amplify to deploy updates on every code commit to a branch.
|
||||

|
||||
|
||||
1. Accept the default build settings. The Amplify Console automatically detects your Hugo build settings and output directory.
|
||||

|
||||
|
||||
1. Review your changes and then choose **Save and deploy**. The Amplify Console will pull code from your repository, build changes to the backend and frontend, and deploy your build artifacts at `https://master.unique-id.amplifyapp.com`. Bonus: Screenshots of your app on different devices to find layout issues.
|
||||
|
||||
## Using a newer version of Hugo
|
||||
|
||||
If you need to use a different, perhaps newer, version of Hugo than the version currently supported by AWS Amplify:
|
||||
|
||||
1. Visit the [AWS Amplify Console](https://console.aws.amazon.com/amplify/home), and click the app you would like to modify
|
||||
1. In the side navigation bar, Under App Settings, click **Build settings**
|
||||
1. On the Build settings page, near the bottom, there is a section called **Build image settings**. Click **Edit**
|
||||
1. Under **Live package updates**, click **Add package version override**
|
||||
1. From the selection, click **Hugo** and ensure the version field says `latest`
|
||||
1. Click **Save** to save the changes.
|
||||
|
||||
[Quick Start]: /getting-started/quick-start/
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 47 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 80 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 60 KiB |
@@ -0,0 +1,151 @@
|
||||
---
|
||||
title: Host on AWS Amplify
|
||||
description: Host your site on AWS Amplify with continuous deployment.
|
||||
categories: [hosting and deployment]
|
||||
keywords: [hosting]
|
||||
menu:
|
||||
docs:
|
||||
parent: hosting-and-deployment
|
||||
toc: true
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Please complete the following tasks before continuing:
|
||||
|
||||
1. [Create an AWS account]
|
||||
2. [Install Git]
|
||||
3. [Create a Hugo site] and test it locally with `hugo server`
|
||||
4. Commit the changes to your local repository
|
||||
5. Push the local repository to your [GitHub], [GitLab], or [Bitbucket] account
|
||||
|
||||
[Bitbucket]: https://bitbucket.org/product
|
||||
[Create a Hugo site]: /getting-started/quick-start/
|
||||
[Create an AWS account]: https://aws.amazon.com/resources/create-account/
|
||||
[GitHub]: https://github.com
|
||||
[GitLab]: https://about.gitlab.com/
|
||||
[Install Git]: https://git-scm.com/book/en/v2/Getting-Started-Installing-Git
|
||||
|
||||
## 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.
|
||||
|
||||
{{< code file=amplify.yml copy=true >}}
|
||||
version: 1
|
||||
env:
|
||||
variables:
|
||||
# Application versions
|
||||
DART_SASS_VERSION: 1.81.0
|
||||
GO_VERSION: 1.23.3
|
||||
HUGO_VERSION: 0.139.3
|
||||
# Time zone
|
||||
TZ: America/Los_Angeles
|
||||
# Cache
|
||||
HUGO_CACHEDIR: ${PWD}/.hugo
|
||||
NPM_CONFIG_CACHE: ${PWD}/.npm
|
||||
frontend:
|
||||
phases:
|
||||
preBuild:
|
||||
commands:
|
||||
# Install Dart Sass
|
||||
- curl -LJO https://github.com/sass/dart-sass/releases/download/${DART_SASS_VERSION}/dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz
|
||||
- sudo tar -C /usr/local/bin -xf dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz
|
||||
- rm dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz
|
||||
- export PATH=/usr/local/bin/dart-sass:$PATH
|
||||
|
||||
# Install Go
|
||||
- curl -LJO https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz
|
||||
- sudo tar -C /usr/local -xf go${GO_VERSION}.linux-amd64.tar.gz
|
||||
- rm go${GO_VERSION}.linux-amd64.tar.gz
|
||||
- export PATH=/usr/local/go/bin:$PATH
|
||||
|
||||
# Install Hugo
|
||||
- curl -LJO https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.tar.gz
|
||||
- sudo tar -C /usr/local/bin -xf hugo_extended_${HUGO_VERSION}_linux-amd64.tar.gz
|
||||
- rm hugo_extended_${HUGO_VERSION}_linux-amd64.tar.gz
|
||||
- export PATH=/usr/local/bin:$PATH
|
||||
|
||||
# Check installed versions
|
||||
- go version
|
||||
- hugo version
|
||||
- node -v
|
||||
- npm -v
|
||||
- sass --embedded --version
|
||||
|
||||
# Install Node.JS dependencies
|
||||
- "[[ -f package-lock.json || -f npm-shrinkwrap.json ]] && npm ci --prefer-offline || true"
|
||||
|
||||
# https://github.com/gohugoio/hugo/issues/9810
|
||||
- git config --add core.quotepath false
|
||||
build:
|
||||
commands:
|
||||
- hugo --gc --minify
|
||||
artifacts:
|
||||
baseDirectory: public
|
||||
files:
|
||||
- '**/*'
|
||||
cache:
|
||||
paths:
|
||||
- ${HUGO_CACHEDIR}/**/*
|
||||
- ${NPM_CONFIG_CACHE}/**/*
|
||||
{{< /code >}}
|
||||
|
||||
Step 3
|
||||
: Commit and push the change to your GitHub repository.
|
||||
|
||||
```sh
|
||||
git add -A
|
||||
git commit -m "Create amplify.yml"
|
||||
git push
|
||||
```
|
||||
|
||||
Step 4
|
||||
: Log in to your AWS account, navigate to the [Amplify Console], then press the **Deploy an app** button.
|
||||
|
||||
[Amplify Console]: https://console.aws.amazon.com/amplify/apps
|
||||
|
||||
Step 5
|
||||
: Choose a source code provider, then press the **Next** button.
|
||||
|
||||

|
||||
|
||||
Step 6
|
||||
: Authorize AWS Amplify to access your GitHub account.
|
||||
|
||||

|
||||
|
||||
Step 7
|
||||
: Select your personal account or relevant organization.
|
||||
|
||||

|
||||
|
||||
Step 8
|
||||
: Authorize access to one or more repositories.
|
||||
|
||||

|
||||
|
||||
Step 9
|
||||
: Select a repository and branch, then press the **Next** button.
|
||||
|
||||

|
||||
|
||||
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.
|
||||
|
||||
Step 11
|
||||
: On the "Review" page, scroll to the bottom then press the **Save and deploy** button.
|
||||
|
||||
Step 12
|
||||
: When your site has finished deploying, press the **Visit deployed URL** button to view your published site.
|
||||
|
||||

|
||||
@@ -12,6 +12,8 @@ aliases: [/tutorials/github-pages-blog/]
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Please complete the following tasks before continuing:
|
||||
|
||||
1. [Create a GitHub account]
|
||||
2. [Install Git]
|
||||
3. [Create a Hugo site] and test it locally with `hugo server`.
|
||||
@@ -53,10 +55,11 @@ Step 4
|
||||
{style="max-width: 280px"}
|
||||
|
||||
Step 5
|
||||
: Create an empty file in your local repository.
|
||||
: Create a file named `hugo.yaml` in a directory named `.github/workflows`.
|
||||
|
||||
```text
|
||||
.github/workflows/hugo.yaml
|
||||
mkdir -p .github/workflows
|
||||
touch hugo.yaml
|
||||
```
|
||||
|
||||
Step 6
|
||||
@@ -144,7 +147,13 @@ jobs:
|
||||
{{< /code >}}
|
||||
|
||||
Step 7
|
||||
: Commit the change to your local repository with a commit message of something like "Add workflow", and push to GitHub.
|
||||
: Commit and push the change to your GitHub repository.
|
||||
|
||||
```sh
|
||||
git add -A
|
||||
git commit -m "Create hugo.yaml"
|
||||
git push
|
||||
```
|
||||
|
||||
Step 8
|
||||
: From GitHub's main menu, choose **Actions**. You will see something like this:
|
||||
@@ -181,7 +190,7 @@ You may remove this step if your site, themes, and modules do not transpile Sass
|
||||
|
||||
[Dart Sass]: /hugo-pipes/transpile-sass-to-css/#dart-sass
|
||||
|
||||
## Additional resources
|
||||
## Other resources
|
||||
|
||||
- [Learn more about GitHub Actions](https://docs.github.com/en/actions)
|
||||
- [Caching dependencies to speed up workflows](https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows)
|
||||
|
||||
@@ -11,11 +11,13 @@ toc: true
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Please complete the following tasks before continuing:
|
||||
|
||||
1. [Create a Netlify account]
|
||||
2. [Install Git]
|
||||
3. [Create a Hugo site] and test it locally with `hugo server`
|
||||
4. Commit the changes to your local repository
|
||||
4. Push the local repository to your [GitHub], [GitLab], or [Bitbucket] account
|
||||
5. Push the local repository to your [GitHub], [GitLab], or [Bitbucket] account
|
||||
|
||||
[Bitbucket]: https://bitbucket.org/product
|
||||
[Create a Hugo site]: /getting-started/quick-start/
|
||||
@@ -34,64 +36,64 @@ Step 1
|
||||
Step 2
|
||||
: Select your deployment method.
|
||||
|
||||

|
||||

|
||||
|
||||
Step 3
|
||||
: Authorize Netlify to connect with your GitHub account by pressing the **Authorize Netlify** button.
|
||||
|
||||

|
||||

|
||||
|
||||
Step 4
|
||||
: Press the **Configure Netlify on GitHub** button.
|
||||
|
||||

|
||||

|
||||
|
||||
Step 5
|
||||
: Install the Netlify app by selecting your GitHub account.
|
||||
|
||||

|
||||

|
||||
|
||||
Step 6
|
||||
: Press the **Install** button.
|
||||
|
||||

|
||||

|
||||
|
||||
Step 7
|
||||
: Click on the site's repository from the list.
|
||||
|
||||

|
||||

|
||||
|
||||
Step 8
|
||||
: Set the site name and branch from which to deploy.
|
||||
|
||||

|
||||

|
||||
|
||||
Step 9
|
||||
: Define the build settings, press the **Add environment variables** button, then press the **New variable** button.
|
||||
|
||||

|
||||

|
||||
|
||||
Step 10
|
||||
: Create a new environment variable named `HUGO_VERSION` and set the value to the [latest version].
|
||||
|
||||
[latest version]: https://github.com/gohugoio/hugo/releases/latest
|
||||
|
||||

|
||||

|
||||
|
||||
Step 11
|
||||
: Press the "Deploy my new site" button at the bottom of the page.
|
||||
|
||||

|
||||

|
||||
|
||||
Step 12
|
||||
: At the bottom of the screen, wait for the deploy to complete, then click on the deploy log entry.
|
||||
|
||||

|
||||

|
||||
|
||||
Step 13
|
||||
: Press the **Open production deploy** button to view the live site.
|
||||
|
||||

|
||||

|
||||
|
||||
## Configuration file
|
||||
|
||||
|
||||
@@ -55,9 +55,11 @@ URL = "<FILL ME IN>"
|
||||
#URL = "gs://<Bucket Name>"
|
||||
|
||||
# Amazon Web Services S3; see https://gocloud.dev/howto/blob/#s3
|
||||
# For S3-compatible endpoints, see https://gocloud.dev/howto/blob/#s3-compatible
|
||||
#URL = "s3://<Bucket Name>?region=<AWS region>"
|
||||
|
||||
# For S3-compatible endpoints, see https://gocloud.dev/howto/blob/#s3-compatible
|
||||
#URL = "s3://<Bucket Name>?endpoint=https://my.minio.instance&awssdk=v2&use_path_style=true&disable_https=false
|
||||
|
||||
# Microsoft Azure Blob Storage; see https://gocloud.dev/howto/blob/#azure
|
||||
#URL = "azblob://$web"
|
||||
|
||||
|
||||
@@ -133,8 +133,6 @@ Also see the [CLI Doc](/commands/hugo_mod_clean/).
|
||||
|
||||
## Module workspaces
|
||||
|
||||
{{< new-in 0.109.0 >}}
|
||||
|
||||
Workspace support was added in [Go 1.18](https://go.dev/blog/get-familiar-with-workspaces) and Hugo got solid support for it in the `v0.109.0` version.
|
||||
|
||||
A common use case for a workspace is to simplify local development of a site with its theme modules.
|
||||
|
||||
@@ -88,7 +88,7 @@ HUGO_ENVIRONMENT
|
||||
: The value e.g. set with `hugo -e production` (defaults to `production` for `hugo` and `development` for `hugo server`).
|
||||
|
||||
HUGO_PUBLISHDIR
|
||||
: {{< new-in 0.109.0 >}} The absolute path to the publish directory (the `public` directory). Note that the value will always point to a directory on disk even when running `hugo server` in memory mode. If you write to this folder from PostCSS when running the server, you could run the server with one of these flags:
|
||||
: The absolute path to the publish directory (the `public` directory). Note that the value will always point to a directory on disk even when running `hugo server` in memory mode. If you write to this folder from PostCSS when running the server, you could run the server with one of these flags:
|
||||
|
||||
```sh
|
||||
hugo server --renderToDisk
|
||||
|
||||
@@ -42,7 +42,7 @@ transpiler
|
||||
targetPath
|
||||
: (`string`) If not set, the transformed resource's target path will be the original path of the asset file with its extension replaced by `.css`.
|
||||
|
||||
vars {{< new-in 0.109.0 >}}
|
||||
vars
|
||||
: (`map`) A map of key-value pairs that will be available in the `hugo:vars` namespace. Useful for [initializing Sass variables from Hugo templates](https://discourse.gohugo.io/t/42053/).
|
||||
|
||||
```scss
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
# Do not remove front matter.
|
||||
_comment: Do not remove front matter.
|
||||
---
|
||||
|
||||
Hugo is available in three editions: standard, extended, and extended/deploy. While the standard edition provides core functionality, the extended and extended/deploy editions offer advanced features.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
# Do not remove front matter.
|
||||
_comment: Do not remove front matter.
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
# Do not remove front matter.
|
||||
_comment: Do not remove front matter.
|
||||
---
|
||||
|
||||
## Prebuilt binaries
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
# Do not remove front matter.
|
||||
_comment: Do not remove front matter.
|
||||
---
|
||||
|
||||
## Build from source
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
# Do not remove front matter.
|
||||
_comment: Do not remove front matter.
|
||||
---
|
||||
|
||||
### Homebrew
|
||||
|
||||
@@ -192,6 +192,16 @@ sudo eopkg install hugo
|
||||
|
||||
[Solus]: https://getsol.us/
|
||||
|
||||
### Void Linux
|
||||
|
||||
To install the extended edition of Hugo on [Void Linux]:
|
||||
|
||||
```sh
|
||||
sudo xbps-install -S hugo
|
||||
```
|
||||
|
||||
[Void Linux]: https://voidlinux.org/
|
||||
|
||||
{{% include "installation/_common/04-build-from-source.md" %}}
|
||||
|
||||
## Comparison
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
---
|
||||
title: PageRef
|
||||
description: Returns the `pageRef` property of the given menu entry.
|
||||
categories: []
|
||||
keywords: []
|
||||
action:
|
||||
related:
|
||||
- /methods/menu-entry/URL
|
||||
returnType: string
|
||||
signatures: [MENUENTRY.PageRef]
|
||||
toc: true
|
||||
---
|
||||
|
||||
The use case for this method is rare.
|
||||
|
||||
In almost also scenarios you should use the [`URL`] method instead.
|
||||
|
||||
## Explanation
|
||||
|
||||
If you specify a `pageRef` property when [defining a menu entry] in your site configuration, Hugo looks for a matching page when rendering the entry.
|
||||
|
||||
If a matching page is found:
|
||||
|
||||
- The [`URL`] method returns the page's relative permalink
|
||||
- The [`Page`] method returns the corresponding `Page` object
|
||||
- The [`HasMenuCurrent`] and [`IsMenuCurrent`] methods on a `Page` object return the expected values
|
||||
|
||||
If a matching page is not found:
|
||||
|
||||
- The [`URL`] method returns the entry's `url` property if set, else an empty string
|
||||
- The [`Page`] method returns nil
|
||||
- The [`HasMenuCurrent`] and [`IsMenuCurrent`] methods on a `Page` object return `false`
|
||||
|
||||
{{% note %}}
|
||||
In almost also scenarios you should use the [`URL`] method instead.
|
||||
|
||||
[`URL`]: /methods/menu-entry/url/
|
||||
{{% /note %}}
|
||||
|
||||
[defining a menu entry]: /content-management/menus/#define-in-site-configuration
|
||||
[`Page`]: /methods/menu-entry/page/
|
||||
[`URL`]: /methods/menu-entry/url/
|
||||
[`IsMenuCurrent`]: /methods/page/ismenucurrent/
|
||||
[`HasMenuCurrent`]: /methods/page/hasmenucurrent/
|
||||
[`RelPermalink`]: /methods/page/relpermalink/
|
||||
|
||||
## Example
|
||||
|
||||
This example is contrived.
|
||||
|
||||
{{% note %}}
|
||||
In almost also scenarios you should use the [`URL`] method instead.
|
||||
|
||||
[`URL`]: /methods/menu-entry/url/
|
||||
{{% /note %}}
|
||||
|
||||
|
||||
Consider this content structure:
|
||||
|
||||
```text
|
||||
content/
|
||||
├── products.md
|
||||
└── _index.md
|
||||
```
|
||||
|
||||
And this menu definition:
|
||||
|
||||
{{< code-toggle file=hugo >}}
|
||||
[[menus.main]]
|
||||
name = 'Products'
|
||||
pageRef = '/products'
|
||||
weight = 10
|
||||
[[menus.main]]
|
||||
name = 'Services'
|
||||
pageRef = '/services'
|
||||
weight = 20
|
||||
{{< /code-toggle >}}
|
||||
|
||||
With this template code:
|
||||
|
||||
{{< code file=layouts/partials/menu.html >}}
|
||||
<ul>
|
||||
{{ range .Site.Menus.main }}
|
||||
<li><a href="{{ .URL }}">{{ .Name }}</a></li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
{{< /code >}}
|
||||
|
||||
Hugo render this HTML:
|
||||
|
||||
```html
|
||||
<ul>
|
||||
<li><a href="/products/">Products</a></li>
|
||||
<li><a href="">Services</a></li>
|
||||
</ul>
|
||||
```
|
||||
|
||||
In the above note that the `href` attribute of the second `anchor` element is blank because Hugo was unable to find the "services" page.
|
||||
|
||||
With this template code:
|
||||
|
||||
|
||||
{{< code file=layouts/partials/menu.html >}}
|
||||
<ul>
|
||||
{{ range .Site.Menus.main }}
|
||||
<li><a href="{{ or .URL .PageRef }}">{{ .Name }}</a></li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
{{< /code >}}
|
||||
|
||||
Hugo renders this HTML:
|
||||
|
||||
```html
|
||||
<ul>
|
||||
<li><a href="/products/">Products</a></li>
|
||||
<li><a href="/services">Services</a></li>
|
||||
</ul>
|
||||
```
|
||||
|
||||
In the above note that Hugo populates the `href` attribute of the second `anchor` element with the `pageRef` property as defined in the site configuration because the template code falls back to the `PageRef` method.
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
# Do not remove front matter.
|
||||
_comment: Do not remove front matter.
|
||||
---
|
||||
|
||||
In this site configuration we enable rendering of [emoji shortcodes], and add emoji shortcodes before (pre) and after (post) each menu entry:
|
||||
|
||||
@@ -16,8 +16,6 @@ action:
|
||||
signatures: [PAGE.Ancestors]
|
||||
---
|
||||
|
||||
{{< new-in 0.109.0 >}}
|
||||
|
||||
{{% include "methods/page/_common/definition-of-section.md" %}}
|
||||
|
||||
With this content structure:
|
||||
|
||||
@@ -141,6 +141,7 @@ Some providers perform deep clones by default, others allow you to configure the
|
||||
|
||||
Hosting service | Default clone depth | Configurable
|
||||
:-- | :-- | :--
|
||||
AWS Amplify | Deep | N/A
|
||||
Cloudflare Pages | Shallow | Yes [^CFP]
|
||||
DigitalOcean App Platform | Deep | N/A
|
||||
GitHub Pages | Shallow | Yes [^GHP]
|
||||
|
||||
@@ -28,4 +28,8 @@ If the `Page` object associated with the menu entry is a section, this method al
|
||||
|
||||
See [menu templates] for a complete example.
|
||||
|
||||
{{% note %}}
|
||||
When using this method you must either define the menu entry in front matter, or specify a `pageRef` property when defining the menu entry in your site configuration.
|
||||
{{% /note %}}
|
||||
|
||||
[menu templates]: /templates/menu/#example
|
||||
|
||||
@@ -26,4 +26,8 @@ aliases: [/functions/ismenucurrent]
|
||||
|
||||
See [menu templates] for a complete example.
|
||||
|
||||
{{% note %}}
|
||||
When using this method you must either define the menu entry in front matter, or specify a `pageRef` property when defining the menu entry in your site configuration.
|
||||
{{% /note %}}
|
||||
|
||||
[menu templates]: /templates/menu/#example
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
---
|
||||
title: Store
|
||||
linktitle: PAGE.Store
|
||||
description: Returns a persistent "scratch pad" on the given page to store and manipulate data.
|
||||
categories: []
|
||||
keywords: []
|
||||
action:
|
||||
related:
|
||||
- methods/page/scratch
|
||||
- methods/site/store
|
||||
- functions/hugo/store
|
||||
- functions/collections/NewScratch
|
||||
returnType: maps.Scratch
|
||||
signatures: [PAGE.Store]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
# Do not remove front matter.
|
||||
_comment: Do not remove front matter.
|
||||
---
|
||||
|
||||
A _section_ is a top-level content directory, or any content directory with an _index.md file.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
# Do not remove front matter.
|
||||
_comment: Do not remove front matter.
|
||||
---
|
||||
|
||||
Hugo determines the _next_ and _previous_ page by sorting the site's collection of regular pages according to this sorting hierarchy:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
# Do not remove front matter.
|
||||
_comment: Do not remove front matter.
|
||||
---
|
||||
|
||||
Hugo determines the _next_ and _previous_ page by sorting the current section's regular pages according to this sorting hierarchy:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
# Do not remove front matter.
|
||||
_comment: Do not remove front matter.
|
||||
---
|
||||
Hugo generates one or more files per page when building a site. For example, when rendering home, [section], [taxonomy], and [term] pages, Hugo generates an HTML file and an RSS file. Both HTML and RSS are built-in _output formats_. Create multiple output formats, and control generation based on [page kind], or by enabling one or more output formats for one or more pages. See [details].
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
# Do not remove front matter.
|
||||
_comment: Do not remove front matter.
|
||||
---
|
||||
|
||||
Get IDENTIFIER
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
# Do not remove front matter.
|
||||
_comment: Do not remove front matter.
|
||||
---
|
||||
|
||||
## Methods
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
# Do not remove front matter.
|
||||
_comment: Do not remove front matter.
|
||||
---
|
||||
|
||||
For the optional sort order, specify either `asc` for ascending order, or `desc` for descending order.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
# Do not remove front matter.
|
||||
_comment: Do not remove front matter.
|
||||
---
|
||||
|
||||
Hugo determines the _next_ and _previous_ page by sorting the page collection according to this sorting hierarchy:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
# Do not remove front matter.
|
||||
_comment: Do not remove front matter.
|
||||
---
|
||||
|
||||
{{% note %}}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
# Do not remove front matter.
|
||||
_comment: Do not remove front matter.
|
||||
---
|
||||
|
||||
## Process specification
|
||||
|
||||
@@ -11,6 +11,10 @@ action:
|
||||
|
||||
The `Ordinal` method returns the zero-based ordinal of the shortcode in relation to its parent. If the parent is the page itself, the ordinal represents the position of this shortcode in the page content.
|
||||
|
||||
{{% note %}}
|
||||
Hugo increments the ordinal with each shortcode call, regardless of the specific shortcode type. This means that the ordinal value is tracked sequentially across all shortcodes within a given page.
|
||||
{{% /note %}}
|
||||
|
||||
This method is useful for, among other things, assigning unique element IDs when a shortcode is called two or more times from the same page. For example:
|
||||
|
||||
{{< code file=content/about.md lang=md >}}
|
||||
|
||||
@@ -10,7 +10,17 @@ action:
|
||||
signatures: [SHORTCODE.Scratch]
|
||||
---
|
||||
|
||||
The `Scratch` method within a shortcode creates a [scratch pad] to store and manipulate data. The scratch pad is scoped to the shortcode, and is reset on server rebuilds.
|
||||
{{% deprecated-in 0.139.0 %}}
|
||||
Use the [`SHORTCODE.Store`] method instead.
|
||||
|
||||
This is a soft deprecation. This method will be removed in a future release, but the removal date has not been established. Although Hugo will not emit a warning if you continue to use this method, you should begin using `SHORTCODE.Store` as soon as possible.
|
||||
|
||||
Beginning with v0.139.0 the `SHORTCODE.Scratch` method is aliased to `SHORTCODE.Store`.
|
||||
|
||||
[`SHORTCODE.Store`]: /methods/shortcode/store/
|
||||
{{% /deprecated-in %}}
|
||||
|
||||
The `Scratch` method within a shortcode creates a [scratch pad] to store and manipulate data. The scratch pad is scoped to the shortcode.
|
||||
|
||||
{{% note %}}
|
||||
With the introduction of the [`newScratch`] function, and the ability to [assign values to template variables] after initialization, the `Scratch` method within a shortcode is obsolete.
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
---
|
||||
title: Store
|
||||
description: Returns a "Store pad" scoped to the shortcode to store and manipulate data.
|
||||
categories: []
|
||||
keywords: []
|
||||
action:
|
||||
related:
|
||||
- functions/collections/NewScratch
|
||||
- methods/page/Store
|
||||
- methods/site/Store
|
||||
- functions/hugo/Store
|
||||
returnType: maps.Store
|
||||
signatures: [SHORTCODE.Store]
|
||||
---
|
||||
|
||||
{{< new-in 0.139.0 >}}
|
||||
|
||||
The `Store` method within a shortcode creates a [scratch pad] to store and manipulate data. The scratch pad is scoped to the shortcode.
|
||||
|
||||
{{% note %}}
|
||||
With the introduction of the [`newScratch`] function, and the ability to [assign values to template variables] after initialization, the `Store` method within a shortcode is mostly obsolete.
|
||||
|
||||
[assign values to template variables]: https://go.dev/doc/go1.11#text/template
|
||||
[`newScratch`]: /functions/collections/newScratch/
|
||||
{{% /note %}}
|
||||
|
||||
[Store pad]: /getting-started/glossary/#scratch-pad
|
||||
|
||||
{{% include "methods/page/_common/scratch-methods.md" %}}
|
||||
@@ -0,0 +1,126 @@
|
||||
---
|
||||
title: Store
|
||||
linktitle: site.Store
|
||||
description: Returns a persistent "scratch pad" on the given site to store and manipulate data.
|
||||
categories: []
|
||||
keywords: []
|
||||
action:
|
||||
related:
|
||||
- methods/page/store
|
||||
- functions/hugo/store
|
||||
- functions/collections/NewScratch
|
||||
returnType: maps.Scratch
|
||||
signatures: [site.Store]
|
||||
toc: true
|
||||
---
|
||||
|
||||
{{< new-in 0.139.0 >}}
|
||||
|
||||
The `Store` method on a `Site` object creates a persistent [scratch pad] to store and manipulate data. To create a locally scoped scratch pad that is not attached to a `Site` object, use the [`newScratch`] function.
|
||||
|
||||
[`Scratch`]: /methods/site/scratch/
|
||||
[`newScratch`]: /functions/collections/newscratch/
|
||||
[scratch pad]: /getting-started/glossary/#scratch-pad
|
||||
|
||||
## Methods
|
||||
|
||||
###### Set
|
||||
|
||||
Sets the value of a given key.
|
||||
|
||||
```go-html-template
|
||||
{{ site.Store.Set "greeting" "Hello" }}
|
||||
```
|
||||
|
||||
###### Get
|
||||
|
||||
Gets the value of a given key.
|
||||
|
||||
```go-html-template
|
||||
{{ site.Store.Set "greeting" "Hello" }}
|
||||
{{ site.Store.Get "greeting" }} → Hello
|
||||
```
|
||||
|
||||
###### Add
|
||||
|
||||
Adds a given value to existing value(s) of the given key.
|
||||
|
||||
For single values, `Add` accepts values that support Go's `+` operator. If the first `Add` for a key is an array or slice, the following adds will be appended to that list.
|
||||
|
||||
```go-html-template
|
||||
{{ site.Store.Set "greeting" "Hello" }}
|
||||
{{ site.Store.Add "greeting" "Welcome" }}
|
||||
{{ site.Store.Get "greeting" }} → HelloWelcome
|
||||
```
|
||||
|
||||
```go-html-template
|
||||
{{ site.Store.Set "total" 3 }}
|
||||
{{ site.Store.Add "total" 7 }}
|
||||
{{ site.Store.Get "total" }} → 10
|
||||
```
|
||||
|
||||
```go-html-template
|
||||
{{ site.Store.Set "greetings" (slice "Hello") }}
|
||||
{{ site.Store.Add "greetings" (slice "Welcome" "Cheers") }}
|
||||
{{ site.Store.Get "greetings" }} → [Hello Welcome Cheers]
|
||||
```
|
||||
|
||||
###### SetInMap
|
||||
|
||||
Takes a `key`, `mapKey` and `value` and adds a map of `mapKey` and `value` to the given `key`.
|
||||
|
||||
```go-html-template
|
||||
{{ site.Store.SetInMap "greetings" "english" "Hello" }}
|
||||
{{ site.Store.SetInMap "greetings" "french" "Bonjour" }}
|
||||
{{ site.Store.Get "greetings" }} → map[english:Hello french:Bonjour]
|
||||
```
|
||||
|
||||
###### DeleteInMap
|
||||
|
||||
Takes a `key` and `mapKey` and removes the map of `mapKey` from the given `key`.
|
||||
|
||||
```go-html-template
|
||||
{{ site.Store.SetInMap "greetings" "english" "Hello" }}
|
||||
{{ site.Store.SetInMap "greetings" "french" "Bonjour" }}
|
||||
{{ site.Store.DeleteInMap "greetings" "english" }}
|
||||
{{ site.Store.Get "greetings" }} → map[french:Bonjour]
|
||||
```
|
||||
|
||||
###### GetSortedMapValues
|
||||
|
||||
Returns an array of values from `key` sorted by `mapKey`.
|
||||
|
||||
```go-html-template
|
||||
{{ site.Store.SetInMap "greetings" "english" "Hello" }}
|
||||
{{ site.Store.SetInMap "greetings" "french" "Bonjour" }}
|
||||
{{ site.Store.GetSortedMapValues "greetings" }} → [Hello Bonjour]
|
||||
```
|
||||
|
||||
###### Delete
|
||||
|
||||
Removes the given key.
|
||||
|
||||
```go-html-template
|
||||
{{ site.Store.Set "greeting" "Hello" }}
|
||||
{{ site.Store.Delete "greeting" }}
|
||||
```
|
||||
|
||||
## Determinate values
|
||||
|
||||
The `Store` method is often used to set scratch pad values within a shortcode, a partial template called by a shortcode, or by a Markdown render hook. In all three cases, the scratch pad values are indeterminate until Hugo renders the page content.
|
||||
|
||||
If you need to access a scratch pad value from a parent template, and the parent template has not yet rendered the page content, you can trigger content rendering by assigning the returned value to a [noop] variable:
|
||||
|
||||
[noop]: /getting-started/glossary/#noop
|
||||
|
||||
```go-html-template
|
||||
{{ $noop := .Content }}
|
||||
{{ site.Store.Get "mykey" }}
|
||||
```
|
||||
|
||||
You can also trigger content rendering with the `ContentWithoutSummary`, `FuzzyWordCount`, `Len`, `Plain`, `PlainWords`, `ReadingTime`, `Summary`, `Truncated`, and `WordCount` methods. For example:
|
||||
|
||||
```go-html-template
|
||||
{{ $noop := .WordCount }}
|
||||
{{ site.Store.Get "mykey" }}
|
||||
```
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
# Do not remove front matter.
|
||||
_comment: Do not remove front matter.
|
||||
---
|
||||
|
||||
Before we can use a `Taxonomy` method, we need to capture a `Taxonomy` object.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
# Do not remove front matter.
|
||||
_comment: Do not remove front matter.
|
||||
---
|
||||
|
||||
An ordered taxonomy is a slice, where each element is an object that contains the term and a slice of its weighted pages.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
# Do not remove front matter.
|
||||
_comment: Do not remove front matter.
|
||||
---
|
||||
|
||||
## PageInner details
|
||||
|
||||
@@ -122,7 +122,7 @@ For example, to create a code block render hook to render [Mermaid] diagrams:
|
||||
|
||||
{{< code file=layouts/_default/_markup/render-codeblock-mermaid.html copy=true >}}
|
||||
<pre class="mermaid">
|
||||
{{- .Inner | safeHTML }}
|
||||
{{- .Inner | htmlEscape | safeHTML }}
|
||||
</pre>
|
||||
{{ .Page.Store.Set "hasMermaid" true }}
|
||||
{{< /code >}}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
# Do not remove front matter.
|
||||
_comment: Do not remove front matter.
|
||||
---
|
||||
|
||||
{{% note %}}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user