Skip to content

feat(utilities): add UniqueID helper, adopt AddModule#345

Merged
markdumay merged 2 commits into
mainfrom
feat/unique-id
Jul 15, 2026
Merged

feat(utilities): add UniqueID helper, adopt AddModule#345
markdumay merged 2 commits into
mainfrom
feat/unique-id

Conversation

@markdumay

Copy link
Copy Markdown
Collaborator

Adds two shared partials that the rest of the ecosystem depends on.

UniqueID.html

Returns a page-unique, build-stable element id of the form <prefix>-UID-<n>, from a per-prefix counter held in the page's Store.

It replaces two broken patterns found across the ecosystem:

  • md5(delimit (slice . now) "-") — hashing the current time, so the id changed on every build. Any page carrying such a component emitted different HTML each time, defeating output diffing and making caches treat an unchanged page as changed.
  • .Ordinal — which restarts at 0 inside an embedded RenderString (exactly what the example shortcode performs), so two components in two {{< example >}} blocks on one page collide.

page.Store was measured to survive the embedded-RenderString boundary where .Ordinal does not.

The UID segment is load-bearing, not decoration. Hugo derives heading anchors with anchorize, which lowercases and de-duplicates repeated headings by appending -1, -2. A page with two "FAQ" headings emits faq then faq-1 — which would collide head-on with a bare faq-1 container id, and Bootstrap's querySelector would bind the accordion to the heading instead. An uppercase segment is unreachable for anchorize, so the collision cannot occur.

AddModule.html

Moved here from Hinode. No gethinode module declares a dependency on Hinode, yet mod-blocks' list component calls AddModule — so a partial in Hinode reached it only because the final site merges Hinode's layouts, an undeclared inverted dependency that breaks each module's own exampleSite build. It carries the two fixes it received recently: it appends-and-deduplicates rather than replacing the dependency list, and it honours an explicitly-passed page.

Release ordering

This is step 1 of three: mod-utils → mod-blocks → Hinode. mod-blocks and Hinode both bump their mod-utils pin to this release before they merge.

🤖 Generated with Claude Code

markdumay and others added 2 commits July 14, 2026 19:00
UniqueID returns a page-unique, build-stable element id from a per-prefix
counter in the page's Store. It replaces hashing `now` (which changes the id on
every build, so a page carrying the component never renders byte-identically)
and `.Ordinal` (which restarts at 0 inside an embedded RenderString, so ids
collide).

AddModule moves here from Hinode. No gethinode module declares a dependency on
Hinode, so a partial there reaches them only because the site merges Hinode's
layouts - an undeclared inverted dependency that breaks each module's own
exampleSite build.
Hugo de-duplicates repeated headings by appending "-1", "-2", ..., so a page
with two "FAQ" headings emits `faq` and `faq-1` - colliding head-on with the
old bare `<prefix>-<n>` id shape. Insert a literal, uppercase "UID" segment
that `anchorize` can never produce, making the collision structurally
impossible.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@markdumay markdumay merged commit 0bb63ef into main Jul 15, 2026
11 checks passed
@markdumay markdumay deleted the feat/unique-id branch July 15, 2026 03:48
@markdumay

Copy link
Copy Markdown
Collaborator Author

🎉 This PR is included in version 6.5.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant