Static Site Exporter
The Static Site Exporter converts your markdown notes into an interactive, beautiful HTML wiki. It packages pages, styling, search capabilities, theme preferences, backlinks, and graph pages into a self-contained _site/ directory ready for deployment.
1. Overview
Markdown notes are highly portable, but sharing an entire folder vault with non-developers or hosting it on the web can be difficult. The static site exporter solves this by packaging your vault into a modern, static web application:
- Converts Markdown: Translates markdown notes into fully responsive HTML files.
- Backlinks & TOC: Dynamically lists backlinks and compiles a Table of Contents (TOC) for every note.
- Fuzzy Search: Generates a clientside search index (
search-index.json) for real-time text and tag search. - Interactive Preview: Generates preview metadata (
preview-data.json) to display hover popovers (showing note summaries/snippets) when hovering over internal wiki links. - D3 Interactive Graph: Generates a dedicated knowledge graph page identical to the VS Code extension view.
2. Under the Hood & Code Walkthrough
2.1 Crawling and Asset Packaging
When triggered, the exporter deletes the existing _site/ folder, recreates the output directories, copies pre-packaged CSS (prism, styling) and JS (D3, graph rendering, search, hover previews, theme switching) from extension resources, parses markdown files, and generates tag maps:
export async function exportSite(workspaceRoot: string, extensionPath: string): Promise<string> {
const siteDir = path.join(workspaceRoot, '_site');
if (fs.existsSync(siteDir)) {
await fsp.rm(siteDir, { recursive: true });
}
fs.mkdirSync(path.join(siteDir, 'notes'), { recursive: true });
fs.mkdirSync(path.join(siteDir, 'tags'), { recursive: true });
fs.mkdirSync(path.join(siteDir, 'css'), { recursive: true });
fs.mkdirSync(path.join(siteDir, 'js'), { recursive: true });
// Copy CSS & JS assets from extension resources ...
const notes = await gatherSiteNotes(workspaceRoot);
const allTags = collectTags(notes);
// Resolve backlinks
for (const note of notes) {
note.backlinks = findBacklinks(note, notes);
}
// Render markdown and write pages ...
}
2.2 Generating Search and Preview Indices
To power interactive search and link hovers in the browser, the exporter outputs two JSON index files at the root of the site:
// 1. Generate search-index.json for fuzzy search queries
const searchIndex = notes.map(n => ({
title: n.slug,
tags: n.tags,
summary: n.summary,
content: n.content.slice(0, 500),
url: `notes/${n.slug}.html`
}));
await fsp.writeFile(path.join(siteDir, 'search-index.json'), JSON.stringify(searchIndex), 'utf8');
// 2. Generate preview-data.json for popup preview cards
const previewData = {};
for (const n of notes) {
previewData[n.slug] = {
title: n.slug,
summary: n.summary,
snippet: n.htmlContent.replace(/<[^>]+>/g, '').slice(0, 200)
};
}
await fsp.writeFile(path.join(siteDir, 'preview-data.json'), JSON.stringify(previewData), 'utf8');