Skip to content

feat(engine): stop preloading docs-nav on every page; one documented registration - #108

Merged
mhenrixon merged 2 commits into
mainfrom
issue-107-docs-nav-preload
Oct 19, 2026
Merged

mhenrixon merged 2 commits into
mainfrom
issue-107-docs-nav-preload

Conversation

@mhenrixon

@mhenrixon mhenrixon commented Oct 19, 2026 •

Copy link
Copy Markdown
Collaborator

Closes #107

Summary

The engine's auto-pin took importmap-rails' default preload: true, so every page of a host whose docs share the application's import map carried a <link rel="modulepreload"> for docs_nav_controller.js (24 KB). A plain host pin … preload: false couldn't override it, because pin_all_from directories expand over plain pins. The README and the pin file's header also gave three different registration recipes, and one of them (lazyLoadControllersFrom("docs_kit/controllers", …)) logs an autoload error for every host controller identifier.

  • config.docs_kit.preload (default false) sets the pin's preload:. true restores 1.4's behaviour. An entry-point name such as "docs" preloads it only where that entry point is rendered (importmap-rails 2.x).
  • config.docs_kit.controllers_under (default "docs_kit/controllers") sets the module namespace. With "controllers" the module becomes controllers/docs_nav_controller and the host's own loader finds it by convention: with lazyLoadControllersFrom("controllers", …), only on pages that render docs-nav. The asset path doesn't change.
  • config/importmap.rb reads both from DocsKit::Engine.config.docs_kit. Its header now points at a new README section, Registering the controller, which covers eager registration, registration through the host's loader, preloading, and a warning against a second lazy loader on docs_kit/controllers. The auto-TOC section, the dedicated-import-map section and the upgrade table point at it.
  • CHANGELOG [Unreleased] has an "Upgrading from 1.4" note. The one visible change for an eager-registering site: docs-nav comes from the eager loader's import() instead of the preload cache, one request later. To get the preload back, set config.docs_kit.preload = true.

Before / after: <head> of /docs/overview in the dogfood app (defaults)

 <link rel="modulepreload" href="/assets/stimulus-loading-1fc53fe7.js">
-<link rel="modulepreload" href="/assets/docs_kit/controllers/docs_nav_controller-2c0d75d3.js">
 <link rel="modulepreload" href="/assets/daisy_ui/controllers/daisy_dropdown_controller-d98bf51b.js">

No DocsUI:: chrome changed and the rendered page looks the same, so there are no screenshots. The diff above is the evidence.

Test plan

  • spec/docs_kit/importmap_pin_spec.rb (new): draws the real pin file into an Importmap::Map (importmap-rails 2.2.3, now a dev/test dependency). Covers the default name and asset, no default preload, preload = true preloading on every entry point, preload = "docs" preloading for docs only, and controllers_under = "controllers" mapping to the same asset. Three examples were RED before the change.
  • spec/docs_kit/engine_spec.rb: defaults for both options (RED before the change).
  • docs/spec/requests/docs_nav_pin_spec.rb (new): a docs page's import map maps docs_kit/controllers/docs_nav_controller, and no modulepreload names it. RED on main: the preload list contained it.
  • docs/spec/system/docs_chrome_spec.rb: docs-nav still connects with eager registration and no preload, and it builds the on-this-page TOC (criterion 4). The example is RED when the eager docs_kit/controllers line is commented out.
  • Manual check, criterion 3 (not committed): in the dogfood app I temporarily set config.docs_kit.controllers_under = "controllers", changed index.js to lazyLoadControllersFrom("controllers", application) and added a throwaway /plain page (javascript_importmap_tags + data-controller="hello"). Playwright performance.getEntriesByType("resource"):
    DOCS preloads: []
    DOCS importmap docs-nav key: ["controllers/docs_nav_controller"]
    DOCS fetched: [".../assets/docs_kit/controllers/docs_nav_controller-2c0d75d3.js"]   (TOC built)
    PLAIN preloads: []
    PLAIN fetched docs_nav: []
    PLAIN fetched hello: [".../assets/controllers/hello_controller-708796bd.js"]
    
    preloaded_module_paths grep for docs_nav: []. All of it was reverted afterwards.
  • Manual check, criterion 2: config.docs_kit.preload = true in the dogfood app puts /assets/docs_kit/controllers/docs_nav_controller-2c0d75d3.js back in preloaded_module_paths.
  • bundle exec rspec: 1181 examples, 0 failures (93.2% line coverage)
  • bundle exec rubocop: no offenses, in the gem and in docs/
  • cd docs && bundle exec rspec: 17 examples, 0 failures (request + Playwright)
  • bundle exec conformance-kit check: passed (locally on Ruby 3.4.2; CI runs 4.0)

Deviations & judgment calls

  • Judgment call: the pin file reads DocsKit::Engine.config.docs_kit, not Rails.application.config.docs_kit as the issue sketched. Both are the same OrderedOptions (Railtie config options are shared; verified equal? in the docs app), and the engine's reads in a gem spec where no app is booted.
  • Discovery: importmap-rails draws the engine's pin file in its "importmap" initializer, so preload/controllers_under must be set in config/application.rb (like auto_pin), not in config/initializers/.
  • Judgment call: importmap-rails joins the root Gemfile's development/test group (require: false) so the pin-file spec draws a real Importmap::Map. The root lockfile is untracked; it is not a gemspec dependency, so docs/Gemfile.lock is unaffected.
  • Discovery: Importmap::Map#preloaded_module_paths caches under one cache_key for every entry point unless told otherwise; javascript_importmap_module_preload_tags passes cache_key: entry_point. The pin spec does the same, or the entry-point example reads a stale cached result.
  • Judgment call: the README frames controllers_under = "controllers" as "through the host's own loader", not "lazy (recommended)". The stock stimulus-rails index.js is eagerLoadControllersFrom("controllers", ...), so the setting only gives lazy loading where the host already lazy-loads its own controllers.
  • Judgment call: the install generator is unchanged: it still injects eagerLoadControllersFrom("docs_kit/controllers", application), which stays supported. On a host that set controllers_under = "controllers", --sync would still inject that line after an eager anchor (dead, harmless) or warn on a lazy-only index.js. Teaching it to read config/application.rb is a possible follow-up.
  • Judgment call: criterion 3 (lazy path fetches nothing on a page without docs-nav) is a documented manual check, not a committed spec: the dogfood app has no page without docs-nav, and the lazy setup can't coexist with the default one in one boot. Evidence is in the Test plan. The dogfood app keeps the defaults (eager, no preload), which the new request and system specs cover.
  • Judgment call: the CHANGELOG entry is split into Added (controllers_under), Changed (the preload default) and Fixed (the contradictory registration docs), with an "Upgrading from 1.4" note, rather than one Changed bullet.
  • Scope: the docs site's own pages are untouched. None documents the engine options; installation.rb's "Registers the docs-nav Stimulus controller (eager-loaded)" stays true.

Summary by cubic

Stops the engine from preloading the docs-nav controller on every page, and collapses three conflicting registration recipes into one documented section.

The auto-pin took importmap-rails' default preload: true, so every page of a host whose docs share the application's import map carried a 24 KB <link rel="modulepreload"> for docs_nav_controller.js, and a host pin with preload: false couldn't override it.

New engine options

  • config.docs_kit.preload (default false) is the pin's preload:; true restores 1.4's behavior, an entry-point name preloads only where that entry point renders.
  • config.docs_kit.controllers_under (default "docs_kit/controllers") lets the host's own loader find the controller by convention; the asset path never changes.

Eager-registering sites now fetch the controller one request later on docs pages; set config.docs_kit.preload = true to keep the preload. The README no longer recommends lazyLoadControllersFrom("docs_kit/controllers", ...), which logged an autoload error for every host controller identifier.

Written for commit 8d70c11. Summary will update on new commits.

View guided diff Turn on auto-fix

The auto-pin took importmap-rails' default `preload: true`, so in a host
whose docs share the application's import map every page carried a
modulepreload for docs_nav_controller.js, and a plain host pin could not
override it (pin_all_from directories expand over plain pins).

Two engine options, read by config/importmap.rb at draw time:

- config.docs_kit.preload (default false): the pin's preload:. true
  restores 1.4's behaviour; an entry-point name preloads it only where
  that entry point is rendered (importmap-rails 2.x).
- config.docs_kit.controllers_under (default "docs_kit/controllers"):
  the module namespace. "controllers" lets the host's own loader find
  docs-nav by convention; the asset path never changes.

The pin file reads DocsKit::Engine.config.docs_kit, the same shared
OrderedOptions as Rails.application.config.docs_kit, so it draws in a
spec with no booted app.

Refs #107
README gains a "Registering the controller" section (eager, or through
the host's own loader with controllers_under, plus a warning against
lazyLoadControllersFrom("docs_kit/controllers", ...) in a host with its
own controllers). The auto-TOC and dedicated-import-map sections and the
upgrade table point at it. CHANGELOG [Unreleased] names the lost
preload hint and the one-line opt-back.

Refs #107
@mhenrixon mhenrixon added enhancement New feature or request docs-site The documentation site under docs/ core Configuration, registry, scoping, versions and the Rails engine labels Oct 19, 2026
@gitar-bot

gitar-bot Bot commented Oct 19, 2026

Copy link
Copy Markdown

Important

You are using the Gitar free plan. Upgrade to unlock code review, CI analysis, auto-apply, custom automations, and more.

Gitar

@mhenrixon
mhenrixon merged commit bfdaea6 into main Oct 19, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core Configuration, registry, scoping, versions and the Rails engine docs-site The documentation site under docs/ enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Engine pin: stop preloading docs-nav on every page, and document one registration that loads it only where rendered

1 participant