✨ Highlights

Diese Version schließt den Kreis um drei Issues, die gegen 0.8.10–0.8.12 gemeldet wurden: den #175-GH-Pages-Asset-Pfad-Regress, den #177-Offline-Modus-<base>-Bruch und den #167-Offline-Link-Rewrite. Die Grundursache aller drei war, dass die <base>-Tag-Entscheidung über die Templates verstreut war – 0.8.13 macht den Generator zur einzigen Quelle der Wahrheit.

Als Bonus schlägt der Auto-Install-Wiederholungspfad auf der Linux-CI nicht mehr fehl für @docmd/template-summer, docmd-search und andere On-Demand-Deps, da der Post-Install-Load nun einen manuellen node_modules-Walk-up nutzt, statt sich auf Nodes veralteten require.resolve-Cache zu verlassen.

Keine Breaking Changes. Keine neue erforderliche Config. Bestehende Configs, Plugins und CI-Pipelines funktionieren unverändert.

🐛 Fix: <base>-Tag-Entscheidung im Generator zentralisiert (#175, #167, #177)

0.8.10 fügte ein unbedingtes <base href="/"> zum Layout-Template hinzu. Das behob ein Workspace-Asset-Problem, brach aber gleichzeitig drei andere Dinge:

  • #175 (GH-Pages-Subpfad): wenn ein Benutzer url: "https://user.github.io/repo" setzte, hätte <base> "/repo/" sein sollen, nicht "/". 0.8.10 wurde für Subpfad repariert, aber der Root-Deploy-Fall gab weiterhin das unnötige <base href="/"> aus.
  • #167 (Offline-Link-Rewrite): der Markdown-Post-Prozessor schrieb /destination/ im Offline-Modus korrekt zu ./destination/index.html um, aber das <base href="/"> wies den Browser dann an, diese relativen Pfade gegen den Dateisystem-Root über file:// neu zu rooten. Die Links “funktionierten” im HTML-Quelltext, schlugen aber im Browser mit 404 fehl.
  • #177 (Offline-CSS/Assets): das Öffnen von site/index.html von der Festplatte produzierte aus den gleichen Gründen ungestylte Seiten – das <base> re-rootete ./assets/css/... zum Dateisystem-Root, was 404 ergibt.

Der Fix (0.8.13): der Generator berechnet nun die kanonische <base>-Entscheidung basierend auf (isOfflineMode, siteRootAbs) und wendet sie nach dem Template-Rendering an. Templates geben selbst kein <base> mehr aus. Die Entscheidungstabelle:

Szenario <base> ausgegeben Warum
build (online, Root-Deploy) nein Relative URLs lösen gegen die Dokument-URL auf, was wir wollen
build (online, GH-Pages-Subpfad) <base href="/repo/"> Browser muss wissen, dass es auf einem Subpfad ist
build --offline nein file://-Auflösung muss dokument-relativ sein
file:// (direkte Festplattenansicht) n/a Search-Client zeigt die hilfreiche Offline-Meldung stattdessen

Keine Template-Änderungen für bestehende Benutzer erforderlich – die Build-Ausgabe ist nun standardmäßig korrekt. Die Änderung ist unsichtbar, sofern Sie sich nicht auf ein Template verlassen, das sein eigenes <base> ausgibt (was kein offizielles Template tat).

🔧 Auto-Install-Wiederholung überlebt jetzt Nodes veralteten Resolve-Cache

Der Auto-Install-Pfad (tryLoadAfterInstall) verwendete ein bloßes import(packageName) für den Post-Install-Load. Auf Linux-CI gab Nodes interner require.resolve-Cache ein veraltetes “not found” zurück, selbst nachdem npm install das Paket in node_modules platziert hatte. Das Ergebnis: der Build installierte @docmd/template-summer und docmd-search erfolgreich und schlug dann fehl mit Could not load @docmd/template-summer after auto-install (das war der CI-Fehler, der GH-Pages-Deployments in 0.8.12 brach).

Der Fix: ein neues manualResolvePackageEntry() durchläuft den node_modules-Verzeichnisbaum mit frischen fs.existsSync()-Prüfungen und umgeht Nodes Resolve-Cache vollständig. Der neue Ablauf ist:

  1. Versuche createRequire(consumerCwd).resolve(name) (schnell, beachtet das exports-Feld).
  2. Falls das fehlschlägt, durchsuche von consumerCwd aufwärts nach node_modules/<name>/package.json (zuverlässig, cache-frei).

Als Bonus überschreibt eine neue Umgebungsvariable DOCMD_INSTALL_VERSION die in npm install <name>@<version> verwendete Version, sodass Benutzer auf eine bestimmte Version festlegen oder latest verwenden können, unabhängig davon, was lokal installiert ist.

🐛 Fix: Search-Client zeigt hilfreiche Meldung auf file://

Sowohl die Keyword-Suche als auch die semantische Suche verwenden fetch(), um Indexdateien zu laden. Browser blockieren fetch() von file://-URLs (CORS), sodass das Öffnen von site/index.html von der Festplatte Failed to load search index. zeigte – eine irreführende Fehlermeldung, die den Eindruck erweckte, etwas sei kaputt.

0.8.13 erkennt window.location.protocol === 'file:' vor jedem fetch und zeigt stattdessen eine klare Meldung:

Search requires a web server. Open this site via http://localhost instead of file:// to enable search.

Das macht die Einschränkung explizit, statt den Benutzer rätseln zu lassen, warum die Suche offline “nicht funktioniert”. Ein echter Offline-Index ist ein separates Feature (separat verfolgen, falls gewünscht).

🧹 Test- und Lint-Bereinigung

  • eslint.config.mjs ignoriert jetzt _-präfixierte Variablen/Argumente/catched Errors (Standard-Konvention)
  • tools/prep.js Test-Runner streamt Test-Output live, statt ihn stillschweigend zu capturen
  • tools/simulate-consumer.mjs leerer catch-Block hat einen erklärenden Kommentar
  • packages/plugins/openapi/ entfernte ein toter const r = ... Binding und eine veraltete eslint-disable-Direktive
  • Entfernte tote summariseTests() / extractFailures() Helfer aus prep.js (durch Streaming ersetzt)

Migration

Null. Bestehende Configs, Plugins und CI-Pipelines funktionieren unverändert. Die <base>-Änderung ist vollständig rückwärtskompatibel für jede Site, deren url-Config mit der tatsächlichen Deployment-URL übereinstimmt.

Vollständiges Changelog: https://github.com/docmd-io/docmd/compare/0.8.12...0.8.13