This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

Implementation

Code-level structure, Hugo/Docsy templates, SCSS/JS customizations, patches, and internal shims

Subsystems

  • Script loading: the plugin loop’s shim contract, shape guards, build pipeline, and the security rules Docsy’s own plugins follow

Patches and workarounds

1 - Script loading

The plugin loop’s shim contract, shape guards, build pipeline, and the security rules Docsy’s own plugins follow

_partials/scripts/plugins.html implements params.docsy.plugins. For the configuration reference and the plugin file contract, see the plugins guide; for the design rationale, the design notes; for the tests that pin this contract, the quality notes.

Loop mechanics

The template’s comments carry the mechanics and their rationale. The loop reads the theme’s schema through hugo.Data; the guide renders the same file, so the entry contract has one home.

Shims

For when to add or replace a shim, see the guide’s Adjust a plugin per page; this section is the contract.

The loop resolves a shim by registry name with the schema’s reserved _docsy-shim suffix and, when the partial exists, invokes it with (dict "Page" PAGE "Plugin" ENTRY): the page being rendered, and the merged, normalized entry. The call comes after normalization and name validation, so a shim cannot reorder emission. It comes before the required-field and version guards, the enable check, and asset lookup, so a shim runs for a disabled entry too, and what it returns is what those two guards test.

The partial must return the entry it received, adjusted with merge so the fields it leaves alone keep their normalized values; anything but a map fails the build.

A shim is also where a plugin gates itself: on a page that doesn’t need the plugin, it returns the entry with enable false (Gating decisions). When support for a deprecated parameter ends, remove its mapping and warning from the shim and keep the rest.

Shape guards

Enforcement is hand-coded in the loop against the schema; what each guard warns about, ignores, or empties is the guide’s Warnings list. A refused version skips the entry.

Build and emission

The file contract is the guide’s; the pipeline adds one step beyond it, minification in production (why companions first).

Security constraints

Docsy’s own plugins follow the guide’s rules for plugin authors. In addition:

  • Validate a configuration value against an allowlist before it reaches a fetch URL: the loop does this for every supplied entry version, so a companion only checks that its plugin provides a pin.
  • Residual exposure, disclosed in the guide’s MarkMap version section: the autoloader’s runtime libraries.
  • Imported Hugo modules are trusted: their params merge into the site’s, so a module can register or turn off plugins, and its layouts can shim them, as it already supplies layouts and assets.

2 - ScrollSpy patch

Runtime patch for Bootstrap ScrollSpy to handle invalid CSS selector IDs.

As of Docsy 0.13.0

Problem

As of Bootstrap 5.3.8 (the version used by Docsy 0.13.0), ScrollSpy fails if a page contains a heading ID that is not also a valid CSS # selector. This can happen, for example, if a heading ID starts with a digit. For technical details about this bug, see #2329.

Solution

Docsy 0.13.0 implements a runtime patch for ScrollSpy that intercepts ScrollSpy’s initialization to properly handle heading IDs starting with digits or containing other characters that form invalid CSS selectors. This allows active TOC entry tracking to work correctly without altering the original heading IDs, so links to headings continue to work as expected.

The patch is automatically applied when ScrollSpy is enabled (which is the default). For implementation details, see #2382, #2383.

Maintenance

CI/CD automatically keeps the patch up-to-date when Bootstrap is updated. The _test:full:pre script extracts the method from Bootstrap, applies the patch, and updates the runtime patch file. If the Bootstrap method code has changed to a degree that the patch no longer works, CI will fail, indicating that the patch file needs manual review and updates.

Until the upstream ScrollSpy fix is released in a future Bootstrap version, this patch ensures that active TOC entry tracking works reliably for all pages.

References