Navigation Script generate-navigation.js - So funktioniert's
Wie das Script alle Navigationen, Header, Footer und Sidebars automatisch generiert – Schritt für Schritt.
Was macht das Script?
Das generate-navigation.js Script ist das Herzstück der
automatischen
Navigation auf DevPanicZone. Es durchsucht alle Tutorial-Dateien und erstellt automatisch:
- Header & Footer auf allen Seiten
- Main Navigation (Dropdown-Menü mit allen Kategorien)
- Breadcrumbs (Navigationspfad: Home › Kategorie › Tutorial)
- Prev/Next Navigation (Vorheriges/Nächstes Tutorial)
- Sidebar TOC (Inhaltsverzeichnis aus Überschriften)
- Sidebar Tutorial-Liste (Alle Tutorials der Kategorie)
- Tutorial-Buttons (Übersicht auf Kategorieseiten)
Stell dir vor, du müsstest bei jedem neuen Tutorial ALLE anderen Tutorial-Seiten manuell
aktualisieren! Das Script macht das automatisch mit einem einzigen Befehl: npm run build
Aufbau des Scripts
Das Script ist in logische Abschnitte unterteilt. Lass uns jeden einzelnen durchgehen!
1. Konfiguration & Setup
Ganz am Anfang werden die wichtigsten Einstellungen definiert:
const fs = require('fs');
const path = require('path');
const { JSDOM } = require('jsdom');
// Pfade vom scripts/ Ordner aus
const tutorialsDir = path.join(__dirname, '..', 'tutorials');
const assetsDir = path.join(__dirname, '..', 'assets');
// Blacklist: Diese Ordner werden ignoriert
const BLACKLIST_FOLDERS = ['noupload', 'node_modules', '.git', 'assets'];
Was passiert hier?
fs→ Zum Lesen und Schreiben von Dateienpath→ Zum Arbeiten mit DateipfadenJSDOM→ Zum Parsen und Manipulieren von HTML
tutorialsDir→ Zeigt auf den/tutorialsOrdnerBLACKLIST_FOLDERS→ Ordner, die das Script ignorieren soll
Das Script liegt in /scripts/generate-navigation.js. Um
auf
/tutorials zu kommen, muss es einen Ordner HOCH .. und dann in
den tutorials Ordner.
2. Deine Konfiguration
Diese Konstanten definierst DU - sie steuern, wie die Navigationen aussehen:
// Kategorie-Namen für Main-Navigation
const CATEGORY_NAMES = {
'html': 'HTML',
'css': 'CSS',
'javascript': 'JavaScript'
};
// Reihenfolge der Tutorials
const TUTORIAL_ORDER = {
'tutorials/html/html-basics': [
'html-basics.html',
'html-grundgeruest.html'
]
};
// Eigene Titel für Links
const CUSTOM_TITLES = {
'tutorials/html/html-basics/html-basics.html': 'Was ist HTML?'
};
Das bedeutet:
CATEGORY_NAMES→ Welche Kategorien im Dropdown erscheinenTUTORIAL_ORDER→ In welcher Reihenfolge Tutorials erscheinen (wichtig für Prev/Next!)CUSTOM_TITLES→ Alternative Namen für Links (z.B. statt "html-basics" → "Was ist HTML?")
3. Latest Tutorials für die Startseite
Die "Neueste Tutorials" auf der Startseite werden manuell gepflegt:
const LATEST_TUTORIALS = [
'tutorials/css/css-specials/css-organization.html',
'tutorials/javascript/javascript-basics/js-security.html',
'tutorials/misc/web/console-security.html',
'tutorials/php/php-basics/php-security.html'
];
- Die ersten 4 Einträge erscheinen auf der Startseite
- Reihenfolge im Array = Reihenfolge auf der Startseite
- Neues Tutorial featuren? → An Position 1 einfügen, letztes entfernen
4. Header & Footer Templates
Das Script hat fertige HTML-Templates für Header und Footer gespeichert:
const HEADER_TEMPLATE = `<!-- Header -->
<header class="site-header">
<div class="container">
<!-- Logo, Theme Toggle, Navigation... -->
</div>
</header>`;
const FOOTER_TEMPLATE = `<footer class="site-footer">
<div class="container">
<!-- Copyright, Links... -->
</div>
</footer>`;
Vorteil: Wenn du den Header ändern willst, änderst du ihn nur HIER - dann wird er auf ALLEN Seiten aktualisiert!
5. Akronyme automatisch kapitalisieren
Das Script erkennt Akronyme und kapitalisiert sie korrekt in allen Navigationstiteln:
const ACRONYMS = {
'html': 'HTML',
'css': 'CSS',
'php': 'PHP',
'js': 'JS',
'javascript': 'JavaScript',
'seo': 'SEO',
'ftp': 'FTP',
'devpaniczone': 'DevPanicZone'
};
function capitalizeWithAcronyms(text) {
return text.split('-')
.map(word => {
const lower = word.toLowerCase();
if (ACRONYMS[lower]) {
return ACRONYMS[lower];
}
return word.charAt(0).toUpperCase() + word.slice(1);
})
.join(' ');
}
Beispiel: Der Ordner html-basics wird zu
"HTML
Basics" (nicht "Html Basics").
Hilfsfunktionen
Das Script hat kleine Helferlein, die bestimmte Aufgaben übernehmen:
findHtmlFiles() - HTML-Dateien finden
function findHtmlFiles(dir, fileList = []) {
const files = fs.readdirSync(dir);
files.forEach(file => {
const filePath = path.join(dir, file);
const stat = fs.statSync(filePath);
if (stat.isDirectory()) {
// Blacklist-Ordner ignorieren
if (BLACKLIST_FOLDERS.includes(file)) {
return;
}
// Rekursiv in Unterordner gehen
findHtmlFiles(filePath, fileList);
} else if (file.endsWith('.html')) {
fileList.push(filePath);
}
});
return fileList;
}
Was macht die Funktion?
- Liest alle Dateien in einem Ordner
- Ist es ein Ordner? → Prüfe, ob er auf der Blacklist steht
- Ist es keine Blacklist? → Gehe rekursiv in den Ordner (Funktion ruft sich selbst auf!)
- Ist es eine HTML-Datei? → Füge sie zur Liste hinzu
Die Funktion ruft sich selbst auf! Das ermöglicht es, durch ALLE Unterordner zu gehen, egal wie tief verschachtelt.
getCategoryFromPath() - Kategorie ermitteln
function getCategoryFromPath(filePath) {
const relativePath = path.relative(tutorialsDir, filePath);
const parts = relativePath.split(path.sep);
return parts[0]; // Erste Ebene (html, css, etc.)
}
Beispiel:
- Pfad:
/tutorials/html/html-basics/html-basics.html - Relative Pfad:
html/html-basics/html-basics.html
- Aufteilen:
['html', 'html-basics', 'html-basics.html'] - Erste Ebene:
html← Das ist die Kategorie!
getSubcategoryFromPath() - Unterkategorie ermitteln
function getSubcategoryFromPath(filePath) {
const relativePath = path.relative(tutorialsDir, filePath);
const parts = relativePath.split(path.sep);
if (parts.length >= 2) {
return 'tutorials/' + parts.slice(0, 2).join('/');
}
return 'tutorials/' + parts[0];
}
Beispiel:
- Pfad:
/tutorials/html/html-basics/html-basics.html - Parts:
['html', 'html-basics', 'html-basics.html']
- Erste 2 Ebenen:
['html', 'html-basics'] - Ergebnis:
tutorials/html/html-basics
Warum wichtig?
Das Script braucht diese Info, um in TUTORIAL_ORDER
die richtige Reihenfolge zu finden!
Navigation-Generierung
Jetzt wird's interessant! Diese Funktionen erstellen die eigentlichen Navigationen:
generateMainNavigation() – Dropdown mit Submenus
Die neue Version erstellt verschachtelte Submenus für jede Kategorie:
function generateMainNavigation() {
const categories = Object.keys(CATEGORY_NAMES);
const navItems = [];
categories.forEach(category => {
const categoryName = CATEGORY_NAMES[category];
const subcategories = getSubcategoriesForCategory(category);
if (Object.keys(subcategories).length > 0) {
let navItem = `<li class="nav-item-nested">
<a href="/tutorials/${category}/" class="nav-link">
${categoryName}
<span class="submenu-icon">▸</span>
</a>
<ul class="dropdown-submenu">`;
// Unterkategorien hinzufügen
Object.keys(subcategories).forEach(subKey => {
const sub = subcategories[subKey];
navItem += `
<li><a href="/tutorials/${category}/#${subKey}">${sub.name}</a></li>`;
});
navItem += `
</ul>
</li>`;
navItems.push(navItem);
}
});
return navItems;
}
Was ist neu?
.nav-item-nested– Kategorie mit aufklappbarem Submenu.dropdown-submenu– Liste der Unterkategorien.submenu-icon– Pfeil-Symbol (▸) zeigt Submenu an- Links zu Ankern:
/tutorials/html/#html-basics
Ergebnis im Dropdown:
Tutorials ▾
├── HTML ▸
│ ├── HTML Basics
│ └── HTML Advanced
├── CSS ▸
│ ├── CSS Basics
│ └── CSS Specials
└── JavaScript ▸
├── JavaScript Basics
└── JavaScript Projects
generateBreadcrumbs() - Navigationspfad
function generateBreadcrumbs(filePath, currentTitle) {
const category = getCategoryFromPath(filePath);
const categoryName = CATEGORY_NAMES[category] || category;
const basename = path.basename(filePath);
// Kategorieseite: Home › Kategorie
if (basename === 'index.html') {
return `<a href="/">Home</a>
<span>›</span>
<span>${categoryName}</span>`;
}
// Tutorial-Seite: Home › Kategorie › Tutorial
return `<a href="/">Home</a>
<span>›</span>
<a href="/tutorials/${category}/">${categoryName}</a>
<span>›</span>
<span>${currentTitle}</span>`;
}
Unterschied:
- Kategorieseite:
Home › CSS(CSS ist nicht klickbar) - Tutorial-Seite:
Home › CSS › Flexbox(CSS ist klickbar!)
generatePrevNextNav() – Kategorieübergreifend
Die Prev/Next-Navigation führt durch alle Tutorials einer Hauptkategorie, nicht nur innerhalb einer Unterkategorie:
function generatePrevNextNav(filePath) {
const category = getCategoryFromPath(filePath);
const currentSubcategory = getSubcategoryFromPath(filePath);
const allTutorials = getAllTutorialsFlat(category); // Alle Tutorials der Kategorie!
const currentIndex = allTutorials.findIndex(t => t.filePath === filePath);
if (currentIndex === -1) return '';
const prev = currentIndex > 0 ? allTutorials[currentIndex - 1] : null;
const next = currentIndex < allTutorials.length - 1 ? allTutorials[currentIndex + 1] : null;
let navHtml = '';
// PREV Button
if (prev) {
const prevSubcategory = `tutorials/${category}/${prev.subcategory}`;
const isNewCategory = prevSubcategory !== currentSubcategory;
const categoryClass = isNewCategory ? ' is-new' : '';
navHtml += `<div class="tutorial-nav-prev">
<a href="${prev.url}">
<span class="tutorial-nav-label">← Vorheriges</span>
<span class="tutorial-nav-link">${prev.title}</span>
<span class="tutorial-nav-category${categoryClass}">${prev.subcategoryDisplay}</span>
</a>
</div>`;
} else {
navHtml += '<div class="tutorial-nav-prev"></div>';
}
// NEXT Button (analog)
if (next) {
const nextSubcategory = `tutorials/${category}/${next.subcategory}`;
const isNewCategory = nextSubcategory !== currentSubcategory;
const categoryClass = isNewCategory ? ' is-new' : '';
navHtml += `<div class="tutorial-nav-next">
<a href="${next.url}">
<span class="tutorial-nav-label">Nächstes →</span>
<span class="tutorial-nav-link">${next.title}</span>
<span class="tutorial-nav-category${categoryClass}">${next.subcategoryDisplay}</span>
</a>
</div>`;
} else {
navHtml += '<div class="tutorial-nav-next"></div>';
}
return navHtml;
}
Was ist neu gegenüber der alten Version?
Alt (vor v2.2):
- Nur innerhalb einer Unterkategorie
- Am Ende von "HTML Basics" → Sackgasse
- Kein Hinweis auf Kategorie-Wechsel
Neu (v2.2):
- Durch alle Tutorials der Hauptkategorie
- "HTML Basics" → weiter zu "HTML Advanced"
- Badge zeigt Unterkategorie an
.is-newKlasse bei Kategorie-Wechsel
Beispiel-Output:
<div class="tutorial-nav-prev">
<a href="/tutorials/html/html-basics/html-listen.html">
<span class="tutorial-nav-label">← Vorheriges</span>
<span class="tutorial-nav-link">HTML Listen</span>
<span class="tutorial-nav-category">HTML Basics</span>
</a>
</div><div class="tutorial-nav-next">
<a href="/tutorials/html/html-advanced/html-semantik.html">
<span class="tutorial-nav-label">Nächstes →</span>
<span class="tutorial-nav-link">HTML Semantik</span>
<span class="tutorial-nav-category is-new">HTML Advanced</span>
</a>
</div>
Diese Funktion sammelt alle Tutorials einer Hauptkategorie (z.B. "html") als flache,
geordnete Liste – über alle Unterkategorien hinweg. Die Reihenfolge folgt der
Definition
in TUTORIAL_ORDER.
addIdsToHeadingsAndGenerateSidebar() - Sidebar TOC
Diese Funktion macht mehrere Dinge auf einmal:
- Findet alle
<h2>und<h3>Überschriften - Fügt ihnen IDs hinzu (falls keine vorhanden)
- Prüft ob Custom Titles in TOC_CUSTOM_TITLES definiert sind
- Erstellt die Sidebar-Links mit Custom oder Original-Titel
function addIdsToHeadingsAndGenerateSidebar(html, filename) {
const dom = new JSDOM(html);
const doc = dom.window.document;
const headings = doc.querySelectorAll('h2, h3');
const anchors = [];
const usedIds = new Set();
headings.forEach(heading => {
// Überschriften mit class="no-toc" überspringen
if (heading.classList.contains('no-toc')) return;
let id = heading.id;
// ID generieren wenn keine vorhanden
if (!id) {
id = heading.textContent.trim().toLowerCase()
.replace(/[äöüÄÖÜß]/g, match => {
const map = {
'ä': 'ae', 'ö': 'oe', 'ü': 'ue',
'Ä': 'Ae', 'Ö': 'Oe', 'Ü': 'Ue', 'ß': 'ss'
};
return map[match];
})
.replace(/[^\w\s-]/g, '') // Sonderzeichen entfernen
.replace(/\s+/g, '-'); // Leerzeichen → Bindestriche
// Duplikate vermeiden
let finalId = id;
let counter = 1;
while (usedIds.has(finalId)) {
finalId = `${id}-${counter}`;
counter++;
}
// ID ins Heading einfügen!
heading.id = finalId;
id = finalId;
}
usedIds.add(id);
const level = heading.tagName === 'H2' ? 'toc-level-1' : 'toc-level-2';
// Custom Title verwenden falls vorhanden, sonst Original-Text
let displayTitle = heading.textContent.trim();
if (TOC_CUSTOM_TITLES[filename] && TOC_CUSTOM_TITLES[filename][id]) {
displayTitle = TOC_CUSTOM_TITLES[filename][id];
}
// Sidebar-Link erstellen
anchors.push(
`<li class="${level}"><a href="#${id}">${displayTitle}</a></li>`
);
});
return {
html: dom.serialize(), // HTML mit IDs!
anchors: anchors.join('\n')
};
}
Beispiel Normal:
- Überschrift:
<h2>Was ist CSS?</h2> - Wird zu:
<h2 id="was-ist-css">Was ist CSS?</h2> - Sidebar-Link:
<a href="#was-ist-css">Was ist CSS?</a>
Beispiel mit Custom Title:
- Überschrift:
<h2 id="die-top-15-tags">HTML Cheat Sheet - Die Top 15 Tags</h2> - Custom Title in TOC_CUSTOM_TITLES:
'die-top-15-tags': 'Top 15 Tags' - Sidebar-Link:
<a href="#die-top-15-tags">Top 15 Tags</a>(gekürzt!)
Lange Überschriften können in der Sidebar zu breit werden. Mit TOC_CUSTOM_TITLES kannst du kurze, prägnante Titel für die Sidebar definieren, während die Original-Überschrift im Haupttext erhalten bleibt:
const TOC_CUSTOM_TITLES = {
'html-basics.html': {
'die-top-15-tags': 'Top 15 Tags',
'html-attribute-erklaert': 'HTML Attribute'
},
'css-farben.html': {
'rgb-rgba-hex': 'Farbformate'
}
};
Wichtig:
Die ID muss die finale ID sein (nach
Slug-Generierung), also z.B. 'die-top-15-tags' nicht
'die-Top-15-Tags'.
IDs wie #für-anfänger können in URLs Probleme machen.
Besser:
#fuer-anfaenger
generateSidebarNavList() – Gruppierte Tutorial-Liste
Die rechte Sidebar zeigt alle Tutorials der Hauptkategorie, gruppiert nach Unterkategorien:
function generateSidebarNavList(filePath) {
const category = getCategoryFromPath(filePath);
const currentUrl = getRelativeUrl(filePath);
const allTutorials = getAllTutorialsForCategory(category);
let html = '';
Object.keys(allTutorials).forEach(subcategoryKey => {
const group = allTutorials[subcategoryKey];
// Gruppen-Überschrift
html += `<li class="sidebar-group-title">${group.displayName}</li>\n`;
// Tutorials dieser Gruppe
group.tutorials.forEach(tutorial => {
const isActive = tutorial.url === currentUrl;
const activeClass = isActive ? ' class="active"' : '';
html += `<li><a href="${tutorial.url}"${activeClass}>${tutorial.title}</a></li>\n`;
});
});
return html.trim();
}
Ergebnis in der Sidebar:
<li class="sidebar-group-title">HTML Basics</li>
<li><a href="/tutorials/html/html-basics/html-basics.html">HTML Basics</a></li>
<li><a href="/tutorials/html/html-basics/html-grundgeruest.html">HTML Grundgerüst</a></li>
<li class="sidebar-group-title">HTML Advanced</li>
<li><a href="/tutorials/html/html-advanced/html-semantik.html" class="active">HTML Semantik</a></li>
<li><a href="/tutorials/html/html-advanced/html-formulare.html">HTML Formulare</a></li>
.sidebar-group-title– Visuelle Gruppierung nach Unterkategorie- Zeigt alle Tutorials der Hauptkategorie (nicht nur aktuelle Unterkategorie)
- Bessere Übersicht beim Navigieren zwischen Unterkategorien
tutorials.json Generierung (NEU in v2.2)
Das Script generiert automatisch eine JSON-Datei mit allen Tutorial-Metadaten:
/assets/data/tutorials.json
extractHeroExcerpt() – Excerpt aus Hero ziehen
function extractHeroExcerpt(html) {
const dom = new JSDOM(html);
const document = dom.window.document;
// Versuche verschiedene Selektoren
const selectors = [
'.hero-subtitle',
'.hero-text',
'.hero p',
'.tutorial-hero p'
];
for (const selector of selectors) {
const element = document.querySelector(selector);
if (element) {
let text = element.textContent.trim();
// Kürze auf max 160 Zeichen
if (text.length > 160) {
text = text.substring(0, 157) + '...';
}
return text;
}
}
return null;
}
generateLatestTutorialsJSON() – JSON erstellen
Diese Funktion sammelt alle Tutorial-Metadaten und speichert sie als JSON:
{
"generated": "2025-01-06T12:00:00.000Z",
"total": 42,
"all": [...], // Alle Tutorials
"latest": [...], // Die 4 aus LATEST_TUTORIALS
"byCategory": { // Gruppiert
"html": [...],
"css": [...],
"javascript": [...]
}
}
Die JSON-Datei wird bei jedem npm run generate neu
erstellt.
Du musst sie nie manuell bearbeiten!
HTML aktualisieren
Die Hauptfunktion updateHtmlFile() koordiniert alle Updates:
function updateHtmlFile(filePath) {
// HTML-Datei einlesen
let html = fs.readFileSync(filePath, 'utf8');
// Metadaten sammeln
const category = getCategoryFromPath(filePath);
const basename = path.basename(filePath);
const currentTitle = CUSTOM_TITLES[basename] || extractTitle(html);
// WICHTIG: ZUERST IDs zu Headings hinzufügen (nur für Tutorial-Seiten)
let sidebarAnchorsHtml = '';
if (basename !== 'index.html') {
const result = addIdsToHeadingsAndGenerateSidebar(html, basename);
html = result.html; // Nutze das HTML mit IDs!
sidebarAnchorsHtml = result.anchors;
}
// 1. HEADER AKTUALISIEREN
html = updateHeader(html);
// 2. FOOTER AKTUALISIEREN
html = updateFooter(html);
// 3. TUTORIAL BUTTONS (nur bei Kategorieseiten!)
if (basename === 'index.html') {
html = updateTutorialButtons(html, category);
}
// 4. Main Navigation einfügen
const mainNavItems = generateMainNavigation();
html = html.replace(
/<!-- Main-Nav-Start -->.*?<!-- Main-Nav-End -->/s,
`<!-- Main-Nav-Start -->\n${mainNavItems.join('\n')}\n<!-- Main-Nav-End -->`
);
// 5. Breadcrumbs (nur für Tutorial-Seiten)
const relativePath = path.relative(path.join(__dirname, '..'), filePath);
const isInTutorials = relativePath.includes('tutorials');
if (isInTutorials) {
const breadcrumbs = generateBreadcrumbs(filePath, currentTitle);
html = html.replace(
/<nav class="breadcrumbs">.*?<\/nav>/s,
`<nav class="breadcrumbs">${breadcrumbs}</nav>`
);
}
// 6. Latest Tutorials Section (nur Tutorial-Seiten, nicht index.html)
if (basename !== 'index.html') {
const latestSection = generateLatestTutorialsSection(category);
// ... (ersetzt oder fügt "Mehr aus X" Section ein)
}
// 7. Prev/Next Navigation (nur Tutorial-Seiten)
if (basename !== 'index.html') {
const prevNext = generatePrevNextNav(filePath);
html = html.replace(
/<nav class="tutorial-nav">.*?<\/nav>/s,
`<nav class="tutorial-nav">${prevNext}</nav>`
);
}
// 8. Sidebar Anchors (TOC)
if (basename !== 'index.html') {
html = html.replace(
/<!-- Sidebar-Anchor-Start -->.*?<!-- Sidebar-Anchor-End -->/s,
`<!-- Sidebar-Anchor-Start -->\n${sidebarAnchorsHtml}\n<!-- Sidebar-Anchor-End -->`
);
}
// 9. Sidebar Navigation List
if (basename !== 'index.html') {
const navList = generateSidebarNavList(filePath);
html = html.replace(
/<ul class="sidebar-nav-list">.*?<\/ul>/s,
`<ul class="sidebar-nav-list">\n${navList}\n</ul>`
);
}
// 10. Datei speichern
fs.writeFileSync(filePath, html, 'utf8');
}
- Zuerst IDs zu Headings hinzufügen
- Dann Header/Footer ersetzen
- Danach alle Navigationen einfügen
- Zum Schluss Datei speichern
Die Sidebar-Links verweisen auf IDs #meine-ueberschrift.
Diese
IDs müssen also
existieren, BEVOR die Sidebar generiert wird!
Regex Patterns erklärt
Das Script nutzt Regular Expressions (Regex), um HTML zu finden und zu ersetzen. Das sieht kompliziert aus, ist aber logisch:
Pattern für Kommentar-Marker
/<!-- Main-Nav-Start -->.*?<!-- Main-Nav-End -->/s
Aufschlüsselung:
/→ Start des Regex<!-- Main-Nav-Start -->→ Findet den Start-Kommentar.*?→ Findet ALLES dazwischen (aber so wenig wie möglich)<!-- Main-Nav-End -->→ Findet den End-Kommentar/s→ "Dotall" Mode -.matched auch Zeilenumbrüche
Beispiel:
<!-- Main-Nav-Start -->
<li><a href="/tutorials/html/">HTML</a></li>
<li><a href="/tutorials/css/">CSS</a></li>
<!-- Main-Nav-End -->
Das Regex findet ALLES zwischen den Markern und ersetzt es mit neuem HTML!
Pattern für HTML-Tags
/<nav class="breadcrumbs">.*?<\/nav>/s
Aufschlüsselung:
<nav class="breadcrumbs">→ Findet das öffnende Tag.*?→ Findet den Inhalt<\/nav>→ Findet das schließende Tag (/muss escaped werden!)/s→ Dotall Mode
Die Hauptlogik
Ganz am Ende des Scripts steht die Funktion, die alles startet:
function generateAllNavigation() {
console.log('🚀 Starte Navigation-Generierung...\n');
// 1. Alle HTML-Dateien finden
const tutorialFiles = findHtmlFiles(tutorialsDir);
console.log(`📄 Gefundene Tutorial-Dateien: ${tutorialFiles.length}\n`);
// 2. Jede Datei aktualisieren
tutorialFiles.forEach(filePath => {
const relativePath = path.relative(tutorialsDir, filePath);
console.log(` ✓ Aktualisiere: ${relativePath}`);
updateHtmlFile(filePath);
});
console.log('\n✅ Navigation erfolgreich generiert!');
}
// Script ausführen!
generateAllNavigation();
Ablauf:
- Finde alle HTML-Dateien im
/tutorialsOrdner - Für jede gefundene Datei: Rufe
updateHtmlFile()auf - Zeige Fortschritt im Terminal
- Fertig!
Mit npm run build wird das Script ausgeführt und es
aktualisiert ALLE Seiten automatisch! 🎉
Best Practices & Tipps
1. Immer vor dem Committen ausführen
Gewöhne dir an, vor jedem Git-Commit npm run build
auszuführen.
So sind alle Navigationen garantiert aktuell!
2. Teste nach Änderungen
Nach größeren Änderungen am Script:
- Führe
npm run buildaus - Öffne mehrere Tutorial-Seiten
- Prüfe Prev/Next, Sidebar, Breadcrumbs
- Teste die Links!
3. Backup vor Script-Änderungen
Wenn du das Script änderst:
- Erstelle eine Kopie:
generate-navigation-backup.js - Teste deine Änderungen auf einer Datei
- Erst dann auf allen Dateien ausführen
4. Console-Logs nutzen
Füge bei Problemen Console-Logs hinzu:
console.log('Aktuelle Kategorie:', category);
console.log('Gefundene Tutorials:', tutorials);
console.log('Current Index:', currentIndex);
Häufige Probleme
Problem: Script findet keine Dateien
Ursache:
- Blacklist oder Pfad falsch
Lösung:
- Prüfe
BLACKLIST_FOLDERS - Prüfe ob Script in
/scripts/liegt - Teste:
console.log(tutorialsDir)
Problem: Prev/Next zeigt falsches Tutorial
Ursache:
- Reihenfolge in
TUTORIAL_ORDERfalsch
Lösung:
- Öffne
generate-navigation.js - Finde die richtige Unterkategorie
- Korrigiere die Reihenfolge
- Führe
npm run buildaus
Problem: Sidebar-Links führen nirgends hin
Ursache:
- IDs wurden nicht zu Headings hinzugefügt
Lösung:
- Prüfe ob
addIdsToHeadingsAndGenerateSidebarausgeführt wird - Prüfe ob
html = result.htmlverwendet wird - Führe
npm run buildnochmal aus
Problem: Dropdown fehlt eine Kategorie
Ursache:
- Keine Tutorials in
TUTORIAL_ORDERfür diese Kategorie
Lösung:
- Füge Tutorials zu
TUTORIAL_ORDERhinzu - Oder: Entferne die Kategorie aus
CATEGORY_NAMES
Zusammenfassung
Das generate-navigation.js Script ist ein mächtiges Werkzeug, das
dir
viel manuelle
Arbeit abnimmt:
Was es macht:
- Findet alle HTML-Dateien
- Erstellt Header & Footer
- Generiert alle Navigationen
- Fügt IDs zu Überschriften hinzu
- Aktualisiert alle Seiten
Was du tun musst:
- Neue Tutorials in
TUTORIAL_ORDEReintragen - Optional: Custom-Titel in
CUSTOM_TITLES npm run buildausführen- Fertig!
Mehr aus DevPanicZone!
Tutorials werden geladen...