✨ Highlights
Drei koordinierte Fixes, die die Nachmeldungen zu #175 aus v0.8.15 schließen. Keine Breaking Changes, keine neuen Konfigurationsschlüssel, keine Pflichtmigration. Bestehende Projekte bauen und liefern unverändert.
🐛 Fix: Dev-Server respektiert die Produktions-URL
v0.8.15 leitet base automatisch aus dem Pfadanteil von url ab, sodass eine GitHub-Pages-Projektseite unter https://user.github.io/repo automatisch base = /repo/ erhält und subpath-bewusste Asset-URLs erzeugt. Der Dev-Server liefert das Ausgabeverzeichnis jedoch immer an der Wurzel (/) aus — somit lieferte jedes Asset auf localhost einen 404, sobald url einen Subpath enthielt.
Der bekannte Workaround war "base": "/", der den Dev-Betrieb reparierte, aber die Auto-Ableitung abschaltete und damit die Suche im Produktivdeploy brach. Beide Zustände waren je in einer Umgebung kaputt.
Der Fix: Im Dev-Modus wird base = / erzwungen, sobald der Wert automatisch abgeleitet wurde. Die Überschreibung greift nur, wenn:
isDev: truegesetzt ist (der Build-Pfad bleibt unangetastet)_baseAutoDerivedgesetzt ist (eine explizitebasein der Konfiguration wird immer respektiert)- die Umgebungsvariable
DOCMD_PROJECT_PREFIXfehlt (Workspace-Dev nutzt sie)
Anwender brauchen keinen base-Eintrag mehr in ihrer Konfiguration.
🗂 Fix: Alle Suchdaten wandern nach .docmd-search/
Schlüsselwort- und semantische Suche nutzen nun denselben Ausgabeordner:
- Vorher:
search-index.jsonlag an der Ausgabewurzel, die semantischen Dateien unter.docmd-search/. - Nachher: Beide liegen unter
.docmd-search/. Standard-Locale:.docmd-search/search-index.json. Andere Locales:.docmd-search/<locale>/search-index.json.
Das hält die Ausgabewurzel sauber und vereinheitlicht den Vertrag, gegen den der Client lädt — Voraussetzung für den nächsten Fix.
🐛 Fix: Laufzeit-HEAD-Probe auf manifest.json entfernt
Der Suchclient hat bei jedem Seitenaufruf .docmd-search/manifest.json per HEAD angefordert, um den engen Fall abzufangen, dass semantische Abhängigkeiten mitten im Build installiert wurden. Auf jeder reinen Schlüsselwortsuche lieferte diese Probe einen 404 — genau der Fehler, den Anwender gemeldet hatten.
Der Fix: Der semantische Modus wird ausschließlich über das Build-zeit-Flag data-semantic am Suchmodal entschieden. Das Flag wird in onConfigResolved aus semanticUsable berechnet, sodass Build und Client übereinstimmen. Der seltene Mid-Build-Fall löst sich beim nächsten Rebuild (der Dev-Modus löst ihn automatisch aus).
🐛 Fix: Schlüsselwortindex wird immer als Fallback erzeugt
Nachdem die Laufzeit-Probe entfernt war, trat ein weiterer Race auf: Wenn die semantische Indizierung erfolgreich war, wurde der Schlüsselwort-search-index.json komplett übersprungen. War das data-semantic-Flag am Modal veraltet (war beim Rendern auf false gesetzt, weil die Abhängigkeiten noch nicht installiert waren), fiel der Client auf den Schlüsselwortmodus zurück und erhielt einen 404, weil kein Schlüsselwortindex existierte.
Der Fix: Der Schlüsselwortindex wird immer erzeugt, auch nach einem erfolgreichen semantischen Build. Der Index ist winzig (wenige KB bei den meisten Projekten) und dient als Laufzeit-Sicherheitsnetz. TUI-Meldungen werden unterdrückt, wenn Semantic bereits lief; das Log bleibt sauber.
🐛 Fix: data-semantic-Flag wird post-build gestempelt
Das Attribut data-semantic="true" am Suchmodal wird zur Renderzeit aus semanticUsable berechnet, das prüft, ob docmd-search auflösbar ist. Bei einer Neuinstallation werden die Abhängigkeiten in onPostBuild installiert — nachdem die Seiten bereits ohne das Flag gerendert wurden. Der Client bleibt dann im Schlüsselwortmodus, obwohl der semantische Index existiert.
Der Fix: Nachdem der semantische Index erfolgreich gebaut wurde, wird jede HTML-Seite nachbearbeitet, sodass das Modal data-semantic="true" trägt. Das schließt die Race, ohne die Laufzeit-HEAD-Probe zurückzubringen. Der Post-Build-Walk überspringt .docmd-search/ und node_modules/, um auch bei großen Seiten schnell zu bleiben.
🧰 Auto-Installation blockt Workspace-Sub-Projekte nicht mehr vorab
Die Vorab-Prüfung, die vor dem Spawnen des Paketmanagers nach package.json in cwd suchte, wurde entfernt. npm, pnpm, yarn und bun wandern selbst die Verzeichnisstruktur nach oben, um die Projektwurzel zu finden — die Vorab-Prüfung lag also in zwei Fällen falsch, die sie eigentlich abfangen sollte:
- Workspace-Sub-Projekte (z. B.
docs/docmd-search/, wenndocs/package.jsoneine Ebene höher liegt). - Jeder Fall, in dem ein Plugin oder Template installieren muss und die Projektwurzel mehrere Verzeichnisse tief liegt.
Der Fix: Der Spawn wird immer versucht. Der hilfreiche Hinweis „kein package.json gefunden" erscheint nur noch, wenn der Spawn tatsächlich scheitert und in keinem Vorgängerverzeichnis eine package.json existiert. Templates laufen über denselben Pfad wie Plugins.
Ende-zu-Ende mit einem frischen Brutetest verifiziert, der @docmd/template-summer und plugins.search.semantic: true nutzt: Beide installieren sich beim ersten Build lautlos, Summer-CSS/-JS landen in site/assets/template/, und der semantische Index schreibt nach site/.docmd-search/.
🏗 Portable Deploys über kanonischen <base href>
Builds ohne --offline mit Subpath (siteRootAbs !== '/') emittieren jetzt genau ein <base href="/<repo>/">-Tag im <head>. Asset-URLs im Head nutzen einfach-relativen Pfad (assets/foo.css); das <base>-Tag verschiebt sie zur Laufzeit an die korrekte Stelle, unabhängig davon, wo die Site gehostet wird.
Warum das wichtig ist: Die vorherige Lösung codierte den Subpath in jede Asset-URL. Der Rename-Flow lief so — Repo umbenennen, der nächste Build gibt weiterhin /old-name/assets/... aus, bis config.url aktualisiert und neu gebaut wird. Mit <base> wird der Pfad einmal aus der Deploy-Stelle berechnet und uniform angewendet. Eine Site zwischen Repos, Hosts oder Ordner-Mounts zu verschieben erfordert keinen Eingriff in config.url, sofern url bereits für das aktuelle Deploy korrekt ist.
Drei-Modus-Grenze, um das sauber zu halten:
| Modus | <base> |
Assets |
|---|---|---|
build (Subpath) |
emittiert | einfach-relativ 'assets/foo.css' |
build (Root-Deploy) |
keins (Dokument-Default) | einfach-relativ 'assets/foo.css' |
dev |
keins | tiefenbewusst ./ oder ../ |
build --offline |
keins (file:// hat keinen Host) | tiefenbewusst ./ oder ../ |
Der Kanonisierer (normaliseBaseTag in packages/parser/src/utils/url-utils.ts) entfernt jedes vorhandene <base>-Tag aus älteren Templates oder Drittanbieter-Plugins und fügt genau eines an der kanonischen Position direkt nach </title> ein. Die Deploy-Form wird an einer Stelle entschieden; Templates müssen nichts darüber wissen.
📦 Upgrade
npx @docmd/core@0.8.16 build
Keine Konfigurationsänderung nötig. Wer als Workaround für v0.8.15 "base": "/" gesetzt hat, kann das entfernen — der Dev-Server passt sich nun automatisch an.