Commit Graph

140 Commits

Author SHA1 Message Date
Bjørn Erik Pedersen 8d6145f3c3 Fix filename dimension identifiers (_role_X_, _version_X_) to replace mount config
Filename identifiers for roles and versions were parsed but never applied
to the SitesMatrix. Now they replace the mount's configuration for that
dimension, matching how language identifiers already worked.

Fixes #14756

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 20:34:34 +02:00
Bjørn Erik Pedersen 9747724222 Fix it so we never auto-fallback to page resources in other roles/versions
This is some logic that's left behind from when we had only one dimension (language) where the common case would be to have one resource set (e.g. an image) and many content translation.

After this commit:

* For sites matrix defined in the content filename (e.g. data.en.js) or in its mount definition, we may use that as a fallback for e.g. German languages if we don't find a better match.
* For content adapters, this is not relevant: Here you must be explicit about this.
* We never auto-fallback on resources from a role/version to another.
* When a page bundle spans multiple roles (e.g. via roles = "*"), we clone its resources to all roles so each gets role-specific paths.

Fixes #14749
Fixes #14752
2026-04-14 16:33:38 +02:00
Bjørn Erik Pedersen d88a29e002 npm: Use workspaces to simplify hugo mod npm pack
Rewrite `hugo mod npm pack` to use npm workspaces. Module deps are now
written to packages/hugoautogen/package.json and the root package.json
gets a "workspaces" reference. A hugo_packagemeta.json sidecar stores a
hash of all input package files so regular commands can warn when npm
deps are out of sync.

Other changes:
- Workspace glob patterns (*, **, {a,b}) are resolved via gobwas/glob.
- Workspaces defined in package.hugo.json are supported.
- package.hugo.json is only recognised at module roots, not in workspaces.
- When package.hugo.json exists, package.json is not mounted or vendored.
- packages/hugoautogen is not mounted or vendored from dependencies.
- Add usePackageJSON import option (auto/always/never) to control whether
  a module's npm deps are included. "auto" checks for Hugo config files
  or package.hugo.json.
- The staleness check is skipped when running `hugo mod npm pack` itself.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 16:00:50 +01:00
Bjørn Erik Pedersen dfece5b674 Add Page.GitInfo support for content from Git modules
Use blobless git clone (--filter=blob:none --no-checkout) to fetch
commit history for content from Git modules, then map it using the
existing gitmap library.  Cloned repos are cached in the modulegitinfo file cache.

Closes #14431
Fixes #5533
2026-02-23 17:43:17 +01:00
Bjørn Erik Pedersen c1b2e58bfb Fix file mount specifity issue within the same module
Fixes #14405
2026-01-20 13:15:33 +01:00
Bjørn Erik Pedersen 608ed09a0a Rename common/maps to common/hmaps (#14384)
Go's stdlid now has a maps package, which is very useful. We have been using imports on the form `xmaps "maps"`, but auto import tools doesn't handle this, which is annoying.

I have been thinking about this for some time, but have been holding back because of all the import changes. However, now is a good time to do this, with very little unmerged code.
2026-01-16 11:47:46 +01:00
Bjørn Erik Pedersen d4c0e4452c Fix error with _content.gotmpl file with index.md siblings
Regression introduced in Hugo 0.153.0.

Note that this is a very uncommon setup, but it worked before.

Fixes #14299
2025-12-25 14:22:14 +01:00
Bjørn Erik Pedersen 168bf17e70 Revert deprecation logging for contentDir per language
It was accidentally introduced because we compile it to file mounts, and `lang` on file mounts is deprecated in favor of `sites.matrix`.

But contentDir per language is something we have had for a long time, and is to useful too to deprecate.

Fixes #14287
2025-12-20 14:59:46 +01:00
Bjørn Erik Pedersen 555dfa207a Speedup and simplify page assembly for deeper content trees
This commit moves to a forked version go-radix (fork source has not had any updates in 3 years.), whith 2 notable changes:

* It's generic (using Go generics) and thus removes a lot of type conversions/assertions.
* It allows nodes to be replaced during walk, which allows to partition the tree for parallel processing without worrying about locking.

For this repo, this means:

* The assembly step now processes nested sections in parallel, which gives a speedup for deep content trees with a slight allocation penalty (see benchmarks below).
* Nodes that needs to be reinserted are inserted directly.
* Also, there are some drive-by fixes of some allocation issues, e.g. avoid wrapping mutexes in returned anonomous functions, a common source of hidden allocations.

```
                                                                                   │ master.bench │           perf-p3.bench            │
                                                                                   │    sec/op    │   sec/op     vs base               │
AssembleDeepSiteWithManySections/depth=1/sectionsPerLevel=1/pagesPerSection=50-10     6.958m ± 3%   7.015m ± 3%        ~ (p=0.589 n=6)
AssembleDeepSiteWithManySections/depth=1/sectionsPerLevel=6/pagesPerSection=100-10    14.25m ± 1%   14.56m ± 8%        ~ (p=0.394 n=6)
AssembleDeepSiteWithManySections/depth=1/sectionsPerLevel=6/pagesPerSection=500-10    48.07m ± 3%   49.23m ± 3%        ~ (p=0.394 n=6)
AssembleDeepSiteWithManySections/depth=2/sectionsPerLevel=6/pagesPerSection=100-10    66.66m ± 4%   66.47m ± 6%        ~ (p=0.485 n=6)
AssembleDeepSiteWithManySections/depth=4/sectionsPerLevel=2/pagesPerSection=100-10    59.57m ± 4%   50.73m ± 5%  -14.85% (p=0.002 n=6)
geomean                                                                               28.54m        27.92m        -2.18%

                                                                                   │ master.bench │           perf-p3.bench            │
                                                                                   │     B/op     │     B/op      vs base              │
AssembleDeepSiteWithManySections/depth=1/sectionsPerLevel=1/pagesPerSection=50-10    4.513Mi ± 0%   4.527Mi ± 0%  +0.33% (p=0.002 n=6)
AssembleDeepSiteWithManySections/depth=1/sectionsPerLevel=6/pagesPerSection=100-10   15.35Mi ± 0%   15.49Mi ± 0%  +0.94% (p=0.002 n=6)
AssembleDeepSiteWithManySections/depth=1/sectionsPerLevel=6/pagesPerSection=500-10   62.50Mi ± 0%   63.19Mi ± 0%  +1.10% (p=0.002 n=6)
AssembleDeepSiteWithManySections/depth=2/sectionsPerLevel=6/pagesPerSection=100-10   86.78Mi ± 0%   87.73Mi ± 0%  +1.09% (p=0.002 n=6)
AssembleDeepSiteWithManySections/depth=4/sectionsPerLevel=2/pagesPerSection=100-10   62.96Mi ± 0%   63.66Mi ± 0%  +1.12% (p=0.002 n=6)
geomean                                                                              29.84Mi        30.11Mi       +0.92%

                                                                                   │ master.bench │           perf-p3.bench           │
                                                                                   │  allocs/op   │  allocs/op   vs base              │
AssembleDeepSiteWithManySections/depth=1/sectionsPerLevel=1/pagesPerSection=50-10     60.44k ± 0%   60.97k ± 0%  +0.87% (p=0.002 n=6)
AssembleDeepSiteWithManySections/depth=1/sectionsPerLevel=6/pagesPerSection=100-10    205.8k ± 0%   211.4k ± 0%  +2.70% (p=0.002 n=6)
AssembleDeepSiteWithManySections/depth=1/sectionsPerLevel=6/pagesPerSection=500-10    831.1k ± 0%   858.3k ± 0%  +3.27% (p=0.002 n=6)
AssembleDeepSiteWithManySections/depth=2/sectionsPerLevel=6/pagesPerSection=100-10    1.157M ± 0%   1.197M ± 0%  +3.41% (p=0.002 n=6)
AssembleDeepSiteWithManySections/depth=4/sectionsPerLevel=2/pagesPerSection=100-10    839.9k ± 0%   867.8k ± 0%  +3.31% (p=0.002 n=6)
geomean                                                                               398.5k        409.3k       +2.71%
```
2025-11-25 11:37:05 +01:00
Bjørn Erik Pedersen 04650ce778 all: Run modernize -fix ./...
Closes #14107
2025-11-05 21:05:42 +01:00
Bjørn Erik Pedersen 264022a75a Add roles and versions as new dimensions (in addition to language)
See the main issue #13776 for details.

Fixes #519
Fixes #13680
Fixes #13663
Fixes #13776
Fixes #13855
Fixes #13648
Fixes #13996
Fixes #14001
Fixes #14031
Fixes #13818
Fixes #13196
2025-11-05 20:39:25 +01:00
Bjørn Erik Pedersen 809ebe01fa hugofs: Make node_modules a "special case" mount
For this and similar mounts in a theme:

```toml
[[module.mounts]]
source = 'node_modules/bootstrap'
target = 'assets/vendor/bootstrap'
```

We first check the theme itself, then the project root.

For backwards compatibility, we also make any `../../node_modules/...` `source` paths into `node_modules/...` paths when defined in themes/modules.

Fixes #14089
2025-10-24 17:12:46 +02:00
Bjørn Erik Pedersen a8e0ca9254 hugofs: Make sure that non-project module mounts are local paths
Fixes #14069
2025-10-19 20:27:10 +02:00
Bjørn Erik Pedersen 521911a576 all: Run modernize -fix ./... 2025-02-26 11:44:25 +01:00
Bjørn Erik Pedersen 77824d704c Fix same resource file published more than once
This may still happen, though, in low memory situations or very big sites, but I'm not sure it's worth spending time on fixing that. Writing the same file more than once isn't harmful, the negative effect is the false path warning.
 We may find a way to detect that situation if this becomes a real problem.

Fixes #13164
2024-12-27 18:55:24 +01:00
Bjørn Erik Pedersen fcdc454cc5 Do not watch directories with no mounted files in it
Fixes #12912
Fixes #13007
2024-11-04 12:44:07 +01:00
Bjørn Erik Pedersen 2168c5b125 Upgrade to Go 1.23
Fixes #12763
2024-08-15 10:18:19 +02:00
Bjørn Erik Pedersen fb8909d5b0 Use xxHash for the change detector
Much faster compared to MD5:

```
name          old time/op    new time/op    delta
HashingFs-10    21.3µs ± 2%     3.2µs ±17%  -84.96%  (p=0.029 n=4+4)

name          old alloc/op   new alloc/op   delta
HashingFs-10    12.9kB ± 0%    12.8kB ± 1%   -1.31%  (p=0.029 n=4+4)

name          old allocs/op  new allocs/op  delta
HashingFs-10      10.0 ± 0%       7.0 ± 0%  -30.00%  (p=0.029 n=4+4)
```

Updates #12643
2024-07-06 16:57:16 +02:00
Bjørn Erik Pedersen 6cd0784e44 Implement defer
Closes #8086
Closes #12589
2024-06-23 11:25:47 +02:00
Bjørn Erik Pedersen e2d66e3218 Create pages from _content.gotmpl
Closes #12427
Closes #12485
Closes #6310
Closes #5074
2024-05-14 13:12:08 +02:00
Christian Oliff 78178d0c2a all: Typo fixes 2024-03-15 17:25:52 +01:00
Bjørn Erik Pedersen 2b2f2b75ef hugofs: Fix vertical mount merge issue
Fixes #12175
2024-03-01 17:10:13 +01:00
Bjørn Erik Pedersen 0d6e593ffb Fix and add integration test for the Bootstrap SCSS module for both Dart Sass and Libsass
This fixes the reverse filesystem lookup (absolute filename to path relative to the composite filesystem).

The old logic had some assumptions about the locality of the actual files that didn't work in more complex scenarios.

This commit now also adds the popular Bootstrap SCSS Hugo module to the CI build (both for libsass and dartsass transpiler), so we can hopefully avoid similar future breakage.

Fixes #12178
2024-03-01 14:18:52 +01:00
Bjørn Erik Pedersen 4a502f7eb4 Fix assets vs data issue
And possibly some other related file mount issues.

Fixes #12133
2024-02-28 19:26:55 +01:00
Bjørn Erik Pedersen a322282e70 Fix single mount rename panic
Fixes #12141
2024-02-28 13:38:12 +01:00
Bjørn Erik Pedersen 189b72331e tocss: Fix the import resolving from absolute to relative assets paths
Fixes #12137
2024-02-24 16:41:18 +01:00
Bjørn Erik Pedersen 16406d9d77 Fix regression on handling of overlapping file mounts
But note that the overlay file system is set up horizontally (project -> module1 -> module2), so I would not recommend too complex overlapping mount setups within the same module.

But this worked in v0.122.0, so we should fix it.

Fixes #12103
2024-02-22 15:36:27 +01:00
Christian Oliff 168d375784 all: Fix typos and some URLs 2024-02-18 12:16:30 +01:00
Bjørn Erik Pedersen 639073e4fe Fix rebuild with resources.Concat
Fixes #12017
2024-02-16 13:17:53 +01:00
Bjørn Erik Pedersen 0851c175ad Move the duplicate page/resource filter
Move the removal of duplicate content and resource files after we have determined if we're inside a leaf bundle or not.

Note that these would eventually have been filtered out as duplicates when  inserting them into the document store, but doing it here will preserve a consistent ordering.

Fixes #12013
2024-02-08 20:11:17 +01:00
Bjørn Erik Pedersen 9df7b295bc Filter dot files etc. in i18n
Closes #11993
2024-02-05 14:54:02 +01:00
Bjørn Erik Pedersen 4174a7866b Fix disabled languages regression
Fixes #11959
2024-02-01 19:42:55 +01:00
Bjørn Erik Pedersen bd66d30295 Filter out duplicate content resource files
We do a slight normalisation of the content paths (lower case, replacing " " with "-") and remove andy language identifier before inserting them into the content tree.

This means that, given that that the default content language is `en`:

```
index.md
index.html
Foo Bar.txt
foo-bar.txt
foo-bar.en.txt
Foo-Bar.txt
```

The bundle above will be reduced to one content file with one resource (`foo-bar.txt`).

Before this commit, what version of the `foo-bar.txt` you ended up with was undeterministic. No  we pick the first determined by sort order.

Note that the sort order is stable, but we recommend avoiding situations like the above.

Closes #11946
2024-01-31 10:06:04 +01:00
Bjørn Erik Pedersen a795acbcd8 all: Run gofumpt -l -w . 2024-01-28 23:14:09 +01:00
Bjørn Erik Pedersen 7285e74090 all: Rework page store, add a dynacache, improve partial rebuilds, and some general spring cleaning
There are some breaking changes in this commit, see #11455.

Closes #11455
Closes #11549

This fixes a set of bugs (see issue list) and it is also paying some technical debt accumulated over the years. We now build with Staticcheck enabled in the CI build.

The performance should be about the same as before for regular sized Hugo sites, but it should perform and scale much better to larger data sets, as objects that uses lots of memory (e.g. rendered Markdown, big JSON files read into maps with transform.Unmarshal etc.) will now get automatically garbage collected if needed. Performance on partial rebuilds when running the server in fast render mode should be the same, but the change detection should be much more accurate.

A list of the notable new features:

* A new dependency tracker that covers (almost) all of Hugo's API and is used to do fine grained partial rebuilds when running the server.
* A new and simpler tree document store which allows fast lookups and prefix-walking in all dimensions (e.g. language) concurrently.
* You can now configure an upper memory limit allowing for much larger data sets and/or running on lower specced PCs.
We have lifted the "no resources in sub folders" restriction for branch bundles (e.g. sections).
Memory Limit
* Hugos will, by default, set aside a quarter of the total system memory, but you can set this via the OS environment variable HUGO_MEMORYLIMIT (in gigabytes). This is backed by a partitioned LRU cache used throughout Hugo. A cache that gets dynamically resized in low memory situations, allowing Go's Garbage Collector to free the memory.

New Dependency Tracker: Hugo has had a rule based coarse grained approach to server rebuilds that has worked mostly pretty well, but there have been some surprises (e.g. stale content). This is now revamped with a new dependency tracker that can quickly calculate the delta given a changed resource (e.g. a content file, template, JS file etc.). This handles transitive relations, e.g. $page -> js.Build -> JS import, or $page1.Content -> render hook -> site.GetPage -> $page2.Title, or $page1.Content -> shortcode -> partial -> site.RegularPages -> $page2.Content -> shortcode ..., and should also handle changes to aggregated values (e.g. site.Lastmod) effectively.

This covers all of Hugo's API with 2 known exceptions (a list that may not be fully exhaustive):

Changes to files loaded with template func os.ReadFile may not be handled correctly. We recommend loading resources with resources.Get
Changes to Hugo objects (e.g. Page) passed in the template context to lang.Translate may not be detected correctly. We recommend having simple i18n templates without too much data context passed in other than simple types such as strings and numbers.
Note that the cachebuster configuration (when A changes then rebuild B) works well with the above, but we recommend that you revise that configuration, as it in most situations should not be needed. One example where it is still needed is with TailwindCSS and using changes to hugo_stats.json to trigger new CSS rebuilds.

Document Store: Previously, a little simplified, we split the document store (where we store pages and resources) in a tree per language. This worked pretty well, but the structure made some operations harder than they needed to be. We have now restructured it into one Radix tree for all languages. Internally the language is considered to be a dimension of that tree, and the tree can be viewed in all dimensions concurrently. This makes some operations re. language simpler (e.g. finding translations is just a slice range), but the idea is that it should also be relatively inexpensive to add more dimensions if needed (e.g. role).

Fixes #10169
Fixes #10364
Fixes #10482
Fixes #10630
Fixes #10656
Fixes #10694
Fixes #10918
Fixes #11262
Fixes #11439
Fixes #11453
Fixes #11457
Fixes #11466
Fixes #11540
Fixes #11551
Fixes #11556
Fixes #11654
Fixes #11661
Fixes #11663
Fixes #11664
Fixes #11669
Fixes #11671
Fixes #11807
Fixes #11808
Fixes #11809
Fixes #11815
Fixes #11840
Fixes #11853
Fixes #11860
Fixes #11883
Fixes #11904
Fixes #7388
Fixes #7425
Fixes #7436
Fixes #7544
Fixes #7882
Fixes #7960
Fixes #8255
Fixes #8307
Fixes #8863
Fixes #8927
Fixes #9192
Fixes #9324
2024-01-27 16:28:14 +01:00
Bjørn Erik Pedersen 8adba648cc all: Remove unused code
Using x/tools/cmd/deadcode
2023-12-18 19:51:26 +01:00
Bjørn Erik Pedersen 7ae62f4aa3 Create hugo_stats.json if it's mounted but does not exists
A common pattern for Tailwind 3 is to mount that file to get it on the server watch list.

A common pattern is also to add hugo_stats.json to .gitignore.

This has meant that the first time you start the server (no hugo_stats.json), it just doesn't work as expected.

Fixes #11264
2023-07-19 19:50:37 +02:00
Bjørn Erik Pedersen 7917961d59 Misc permalinks adjustments
* Move config loading to the page package
* Fix a lower bound panic for the `:sections` slice syntax.
* Always return the `:title`
* Add some permalinks integration tests
* Also see issues below

Fixes #9448
Fixes #11184
See #8523
2023-06-29 10:14:19 +02:00
Mai-Lapyst cc14c6a52c resources/page: Allow section and taxonomy pages to have a permalink configuration
Allows using permalink configuration for sections (branch bundles) and
also for taxonomy pages. Extends the current permalink configuration to
be able to specified per page kind while also staying backward compatible:
all permalink patterns not dedicated to a certain kind, get automatically
added for both normal pages and term pages.

Fixes #8523
2023-06-26 15:31:01 +02:00
Oleksandr Redko 9009c8cdca all: Fix typos in function names and comments 2023-06-19 09:26:29 +02:00
Bjørn Erik Pedersen 7c9fada778 Replace the old log setup, with structured logging etc.
Fixes #11124
2023-06-18 13:03:04 +02:00
Bjørn Erik Pedersen e96cdfe966 Don't create the public folder unless needed
Fixes #11031
2023-05-28 12:55:44 +02:00
Bjørn Erik Pedersen 2c3d4dfb74 Add cache busting config to support Tailwind 3
Fixes #10974
2023-05-22 14:14:35 +02:00
cui fliter 4003c7903f Fix some spelling mistakes 2023-05-19 08:40:08 +02:00
Oleksandr Redko 610cedaa61 all: Fix comments for exported functions and packages 2023-05-18 21:25:27 +02:00
Bjørn Erik Pedersen 241b21b0fd Create a struct with all of Hugo's config options
Primary motivation is documentation, but it will also hopefully simplify the code.

Also,

* Lower case the default output format names; this is in line with the custom ones (map keys) and how
it's treated all the places. This avoids doing `stringds.EqualFold` everywhere.

Closes #10896
Closes #10620
2023-05-16 18:01:29 +02:00
Oleksandr Redko 36ce3a4a9d Correct typos in Go comments 2023-03-02 16:32:32 +01:00
Oleksandr Redko d453c12742 Replace deprecated ioutil with io and os
https://pkg.go.dev/io/ioutil is deprecated since Go 1.16.
2023-03-01 16:28:43 +01:00
Bjørn Erik Pedersen e402d91ee1 Misc doc, code refactoring to improve documentation 2023-01-04 18:01:26 +01:00
Bjørn Erik Pedersen ad2059878a Also consider wrapped errors when checking for file IsNotExist errors
Fixes #10534
2022-12-14 13:51:06 +01:00