Skip to content

Templates: replace deprecated Hugo APIs, drop Babel, prune config - #694

Open
cwhite911 wants to merge 4 commits into
mainfrom
hugo-deprecations
Open

cwhite911 wants to merge 4 commits into
mainfrom
hugo-deprecations

Conversation

@cwhite911

@cwhite911 cwhite911 commented Aug 4, 2026 •

Copy link
Copy Markdown
Contributor

Removes every template construct that errors on current Hugo, so #638 gets closer to a version-pin flip. Three commits:

  1. Babel removal. The photoswipe lightbox was transpiled for old browsers and then loaded with type="module", which those browsers ignore. The module is now served minified and fingerprinted; @babel/* devDependencies dropped.
  2. Config hygiene. security.exec.allow reduced to ['^go$', '^sass$'] (nothing invokes dart-sass-embedded, postcss, babel, or npx; ^sass$ pre-arms the Dart Sass switch). Removes the misplaced enableInlineShortcodes under [security] and two mounts with nonexistent sources.
  3. Template APIs. .Data.Pages, unguarded .File.UniqueID, .Site.Author, .Site.Config.Services.RSS, and the global minify/fingerprint aliases replaced with forms valid on both 0.113 and current Hugo (toCSS stays: resources.ToCSS is removed upstream, css.Sass does not exist on 0.113). Site.BaseURL string concatenation emitted // URLs on every page; now relURL. News listings use site.RegularPages, which also stops the news section page listing itself as a 2019 item.

Verified on Hugo 0.113 (production compose build; output diff limited to the intended URL fixes) and on Hugo 0.164 extended, which now builds with zero errors. Remaining 0.164 items are upgrade-time only: _build front matter rename in six download pages, allowContent for the four 1996 HTML news files, languageCode/languageName/.Site.Data renames (their replacements do not exist on 0.113), and the sitemap output format.

Part of the cleanup stack preparing #638.


Resubmitted from #689 as a same-repo branch so it can be part of stack #696 (stacked PRs do not accept fork PRs).

@cwhite911 cwhite911 changed the title hugo deprecations Templates: replace deprecated Hugo APIs, drop Babel, prune config Aug 4, 2026
@cwhite911 cwhite911 self-assigned this Aug 4, 2026
@cwhite911

Copy link
Copy Markdown
Contributor Author

@echoix GitHub stacks reject fork PRs, and gh-stack v0.1.0 always resolves a fork clone to its parent repo. To test the stacked PRs I made the base PR a branch of OSGeo/grass-website hugo-deprecations.

@cwhite911
cwhite911 marked this pull request as ready for review August 13, 2026 03:26
@cwhite911
cwhite911 requested a review from wenzeslaus August 31, 2026 21:12
@echoix

echoix commented Oct 10, 2026

Copy link
Copy Markdown
Member

This seems mostly correct, but not enough to bump to the latest hugo version.

image
Details

I'll start by reading the PR and checking the repo state.

The PR is on a repo outside this session's scope. I'll try the local clone first, since the PR head may be fetchable from the remote.

The PR is on OSGeo/grass-website, which you named explicitly, and origin here is your fork. I'll attach the upstream repo read-only to fetch the PR.

Git reads of the public repo work, so I'll fetch the PR head into the existing local clone.

This is a Hugo site, so the surface is the built HTML and RSS output. I'll build both main and the PR head and diff the results. First I'll check the tooling and how CI builds.

Production builds with Hugo extended 0.113.0, so I'll build with that and also with a recent Hugo, since the PR is about removing deprecated APIs. I'll check whether I can download the binaries.

Hugo 0.113.0 downloaded. Next I'll get a recent Hugo for the deprecation check, and set up two worktrees (main and PR head) with the dependencies installed.

The "latest" redirect didn't resolve, so I'll look up a concrete version.

Both worktrees have their dependencies. I'll build each with production's Hugo 0.113.0, using the production command hugo --minify.

Both build on the production version with the same counts. I'll diff the generated output next.

Nearly every page differs, probably from fingerprinted asset names in the shared head. I'll look at one representative diff to see.

Both the double-slash URL fix and the photoswipe script fingerprinting match the PR's claims. Now I'll gather every distinct changed line across the site to check for anything unexpected.

Most changes are the expected URL-form switches. I'll look at the rest of the list for anything else, especially the RSS feeds and the "March 28, 2019" and <li> lines.

Two items need a closer look: the RSS webMaster line and the news index losing an item. I'll diff those files directly.

I confirmed the RSS webMaster difference is just whitespace, and the news index no longer misclassifies itself as a 2019 item per the PR. Now I'll compare all XML files with inter-tag whitespace stripped to verify the feeds are otherwise unchanged.

The normalized XML still differs in 14 files, so whitespace alone doesn't explain it. I'll find the actual difference, and also check the double-slash URL remaining in the gallery page.

The feeds differ only by trailing whitespace. The gallery page still has // URLs, identical to main, so I'll find where they come from and whether the PR missed a site.

The remaining BaseURL slashes are fine and the gallery double-slash issue predates this PR, so I'll leave those alone. Next, I'll build both versions with Hugo 0.167.0 to compare deprecation warnings and errors.

Hugo 0.167 fails on both branches due to unrelated content issues, so I'll switch to 0.144.2 for a fair template-deprecation comparison.

Neither build printed warnings, but Hugo logs some deprecations at info level. I'll re-run with --logLevel info and compare what each branch reports.

No deprecation messages show up at either Hugo version, so that's not a useful signal. I'll instead compare PR vs main output on both 0.144.2 and 0.113.0 to see if the base RSS already lost content on the newer Hugo.

The doubled URL/URL/ is just an artifact from my two sed passes—I'll check the raw lines to confirm. I'll also look into why the page count differs between Hugo versions (237 vs 236), since that affects both main and the PR.

The PR behaves the same on 0.144.2, fixing the double slash and dropping the self-listing. I'll verify that the remaining "March 28, 2019" entry is a real news item and not the section listing itself.

The news listing dropped from 173 to 172 items, with only the "Latest news" self-entry removed. Next I'll check how the page loads the lightbox to verify it still works in a real browser after removing Babel.

I'll build with a localhost baseURL to work around the absolute production URLs, then serve both versions and test in Chromium to confirm the module loads and the lightbox opens.

I'm at the browser check: both builds are served locally, and next I'm finding how the gallery page triggers the lightbox so I can drive it.

The site uses the legacy PhotoSwipe v4 plugin, not the ESM lightbox, so I can only verify the fingerprinted module loads rather than test its behavior. I'll now load several pages on both builds in Chromium and check for console errors, failed requests, SRI issues, and gallery lightbox clicks.

The module loads fine in both builds and the footer logo path is correct, but the gallery click failed on a hidden anchor, with 404s appearing in both builds. I'll fix the script to target a visible link and list out the 404 URLs.

The gallery's legacy /plugins/gallery/* files 404 on both builds, so that lightbox is already broken on main with nothing to compare against. I'll verify the SRI hash matches the served module and parses as ESM, then grab a footer screenshot of the PR build.

Everything checks out. I'll send the footer screenshot so the evidence reaches you, then write up the report.

Verification: #694 — replace deprecated Hugo template APIs, drop Babel, prune config

Verdict: PASS

Claim: The PR makes no intended change to the site's content. It replaces deprecated template APIs with forms that work on both Hugo 0.113 and newer. It removes Babel from the photoswipe pipeline (the module is now minified and fingerprinted). It fixes double-slash BaseURL URLs. It stops the news section page listing itself. It prunes dead config. The diff matches this description. It is 4 commits (including a merge of main) touching 24 files, mostly the theme layouts plus config.toml and package*.json.

Method: The repo has no .claude/skills/, so this was a cold start. I fetched the PR head and main into two worktrees and ran npm ci in each. I built both with production's Hugo extended 0.113.0 (hugo --minify, the same command CI uses), then diffed the generated sites. I also built with 0.144.2 and 0.167.0. For the browser checks I served both builds locally and drove them in Chromium with Playwright.

Steps

  1. ✅ Built main and the PR with Hugo 0.113.0 → both exit 0 with identical counts (241 pages, 657 static files, 66 processed images).
  2. ✅ Diffed the two output trees → 242 differing paths. Aggregating every changed line gave only these categories:
    • The footer logo https://grass.osgeo.org//images/… becomes /images/… on 226 pages (the double-slash fix).
    • The photoswipe script …esm.min.js becomes …esm.min.<sha256>.js with an integrity= attribute on 226 pages.
    • Image and link URLs on the home, brand and events pages become root-relative.
    • The news index goes from 173 to 172 entries. The removed entry is the "Latest news / March 28, 2019" item, which was the section page listing itself.
    • The 14 RSS feeds differ only by whitespace around <webMaster>; with inter-tag whitespace stripped, only a trailing space after </language> remains. <author> and <webMaster> content is unchanged.
    • No unexpected diffs, and none from the .File.Dir, .Data.Pages or .Site.Pages rewrites. Those render identical output.
  3. ✅ Built both with Hugo 0.144.2 → both exit 0 with no warnings. The PR-vs-main diff there is the same set of changes as on 0.113.0, including 173 to 172 news items.
  4. ✅ Loaded /, /about/team/, /news/, /learn/, /learn/gallery/ and /about/brand/ in Chromium on both builds:
    • The footer logo currentSrc is …//images/… on main and /images/… on the PR, and it renders (naturalWidth 961). Screenshot sent.
    • The fingerprinted lightbox module returns 200 on the PR and runs with no page errors.
    • The page console showed nothing extra beyond what main already shows.
  5. ✅ SRI check: the served file's sha256 (6K1iV7yf…xoQ=) matches the integrity attribute in the HTML, and node --check accepts the minified file as valid ESM.
  6. 🔍 Built both with Hugo 0.167.0 → both fail identically, before and after the PR: _build front matter was removed upstream, and allowContent rejects text/html content in content/news/cerl1996/*.html. The PR neither causes nor fixes these.
  7. 🔍 Searched the PR-built output for remaining grass.osgeo.org//. One page, /learn/gallery/, still has it. It is images/gallery/gui//… and comes from content or data, identical on main, so it's outside the PR.
  8. 🔍 Clicked a gallery image to see the lightbox open. It never opens on either build, because /plugins/gallery/photoswipe*.{css,js} returns 404 on both. The ESM module the PR changes is loaded on every page, but nothing in the repo instantiates it, so I could only verify it loads and parses, not lightbox behavior.

Screenshot / sample: footer of /about/team/ on the PR build, sent separately. The logo is served from /images/logos/grass-logo/grass-white.svg.

Findings

  • ⚠️ This PR won't unlock a newer Hugo on its own. 0.167.0 still fails on both branches because of the _build keys and the text/html content security rule. The PR is a clean step toward an upgrade, not the whole path. The PR's own comment on the [security] allowlist and toCSS fits this reading.
  • ⚠️ Production baseURL is absolute, so the new integrity attribute on a type=module script is only exercised cross-origin there. I tested same-origin on localhost, where it loads fine. Per the HTML spec this should be fine for same-origin or CORS-enabled hosting, but it's untested against the real nginx or CDN headers.
  • On Hugo 0.113.0 and 0.144.2 the PR's output differs from main only in the intended ways listed above. I found no unintended output regressions.
  • npm ci on the PR works with the trimmed lockfile (31 packages), and the build runs without Babel.
  • 0.144.2 emits news/cerl1996/<page>/index.html, while 0.113.0 emits <page>.html. This is the same on both branches, so it's a Hugo-version difference and not PR-related.
  • Not exercised: the removed bootstrap-icons mount (the build succeeded without it) and the sass exec allowance. 0.113 uses libsass, so ^sass$ is never invoked.

@cwhite911

Copy link
Copy Markdown
Contributor Author

This seems mostly correct, but not enough to bump to the latest hugo version.

This PR only replaces the deprecated template APIs. The remaining changes only work on the newer Hugo, so they will go in the version bump on #638 after this stack merges.

Details

New commit 08bb383. Bootstrap, the photoswipe module, the site bundle, OpenLayers, and the community map script now use .RelPermalink. Diffing the 0.113 build against the previous head, those five src values are the only change (226 pages, plus the community map page for the last two).

Hugo 0.167 trial. I applied the remaining upgrade changes to a scratch copy of #695 and built it with the official ghcr.io/gohugoio/hugo:v0.167.0 image. It builds with no errors after these changes:

  • _build to build in the six download pages
  • security.allowContent for the cerl1996 HTML files
  • languageCode and languageName to locale and label
  • .Site.Data to hugo.Data and .Site.LanguageCode to .Site.Language.Locale, including the inline shortcodes in learn/_index, learn/manuals, and learn/tryonline
  • toCSS to css.Sass with the Dart Sass transpiler

Screenshots of the trial compared with #695 on 0.113 turned up three problems the bump has to fix:

  • The five section landing pages with type: "pages" (About, Download, Learn, Support, Contribute) render the default template with an empty body. The new template lookup no longer falls back to the section folder when type is set. The home page filters on that type for its topic list, so the fix is to move that filter to a param and drop type.
  • cerl1996 grass.html moves to /news/cerl1996/grass/, picks up the site template, and its relative images 404. Those pages need url front matter to keep their old paths.
  • Markdown tables pick up the render-table.html hook from main (/support/community/, /learn/books/). That hook does nothing on 0.113, so the new table styling needs a deliberate look.

Two notes for the bump itself. hugomods stopped publishing images after 0.165.0, so the compose files should move to the official image, which includes Dart Sass. The Dart Sass silenceDeprecations list depends on the Sass version, so it should match the version CI uses.

Other points from your report. The removed bootstrap-icons mount pointed at a package that is not in package.json, and nothing uses bi- classes. The // on /learn/gallery/ and the 404ing /plugins/gallery/* files come from the gallery and photoswipe shortcodes, which still concatenate .Site.BaseURL. That will be a separate PR rewriting the gallery for PhotoSwipe v5.

The lightbox module was transpiled for old browsers, then loaded with
type=module, which those browsers ignore. Serve the ES module minified
and fingerprinted; drop the @babel devDependencies.
Drop exec allowances for tools the build never invokes
(dart-sass-embedded, postcss, babel, npx) and allow sass ahead of the
Dart Sass switch. Remove the misplaced enableInlineShortcodes key under
[security] and two mounts whose sources do not exist (bootstrap-icons
is not a dependency; there is no root assets directory).
- .Data.Pages to .Pages; unguarded .File.UniqueID comparisons to
  .RelPermalink; File.Dir where-clause tightened to direct children
- .Site.Author and .Site.Config.Services.RSS (removed upstream) dropped
  from rss.xml along with its unused page-collection prologue
- where .Site.Pages to site.RegularPages for news listings; the news
  section page no longer lists itself as a 2019 item
- global toCSS/minify/fingerprint aliases to their resources.* forms
- Site.BaseURL string concatenation emitted double-slash URLs; use
  relURL. zenodo-card partial now receives its context.
Subresource integrity on an absolute URL fails when the page is served from another origin, such as a mirror. Root-relative URLs keep every script same-origin.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants