BatchExporter
Convert every markdown file in a folder to PDF in one go, with $...$ and $$...$$ rendered as KaTeX math — including math inside tables.
Usage
- Explorer: right-click a folder → Batch Export MD to PDF
- Command Palette: Batch Export MD to PDF: Whole Project (uses the workspace root)
Each .md becomes a .pdf next to it. A tab opens listing every file and its status as the batch runs:
| Mark |
Meaning |
| ○ |
waiting |
| spinner |
converting |
| ● |
done — click Open PDF to view it |
| ⊘ |
skipped (a PDF already exists, or the file has unsaved editor changes) |
| ✕ |
failed — the reason is shown in the Detail column |
Click a file name to open the markdown source. Cancel stops after the file currently being converted; closing the tab does the same.
Merging a folder into one PDF
Turn on batchExporter.mergeFolders to get one PDF per folder instead of one per file. Each folder's markdown files are combined in name order; every file starts on a new page under its file name as a large title.
Every PDF of the run is collected in a new pdf_YYmmdd_HHMMSS folder inside the folder you right-clicked, and is named after the path from that folder down to the one holding the files, joined with double underscores:
Notes/ ← right-clicked
├── 2024/algebra/*.md
├── 2024/*.md
├── *.md
└── pdf_260802_133045/ ← created by the run
├── Notes.pdf
├── Notes__2024.pdf
└── Notes__2024__algebra.pdf
Nothing is written next to the sources, and each run gets its own folder, so an earlier export is never overwritten.
The progress tab lists one row per folder, showing how many files each PDF merges. If any file in a folder has unsaved editor changes, that whole folder is skipped.
Rendering
PDFs are produced by headless Chromium, so anything Chrome can lay out — tables, images, code blocks, CJK text — comes out as you would expect. On the first run BatchExporter looks for an installed Chrome, Edge, or Chromium; if none is found it offers to download a private copy (about 150 MB) into the extension's global storage and reuses it afterwards. Set batchExporter.chromePath to point at a specific browser instead.
YAML front matter is stripped rather than printed, and its title: is used for the PDF title (falling back to the first heading, then the file name).
Settings
| Setting |
Default |
Description |
batchExporter.recursive |
true |
Include subfolders |
batchExporter.overwrite |
true |
Overwrite existing PDFs; when off those files are skipped |
batchExporter.mergeFolders |
false |
Merge each folder's markdown files into one PDF, collected in a timestamped folder |
batchExporter.exclude |
[".git", "node_modules"] |
Names or globs to skip |
batchExporter.pageFormat |
A4 |
Paper size |
batchExporter.margin |
20mm |
Page margin, any CSS length |
batchExporter.landscape |
false |
Landscape orientation |
batchExporter.displayHeaderFooter |
false |
Print the title and page numbers |
batchExporter.chromePath |
"" |
Browser executable to render with |
exclude supports glob wildcards: * (within a path segment), ** (across segments), and ? (one character). A pattern without a slash matches by base name at any depth (*.draft.md); a pattern with a slash matches the path relative to the scanned folder (archive/**).
Notes
- Files with unsaved changes in an editor are skipped, so a PDF never captures stale content. Save first and re-run.
- A
| inside inline math breaks the surrounding table row, because the table is split into cells before the math is parsed. Escape it as \| — | $P(A\|B)$ | renders correctly. This matches VSCode's own markdown preview.
- A formula KaTeX cannot parse is printed in red in place rather than failing the file, so one typo never stops the batch.
Development
npm install
npm run compile # or: npm run watch
# F5 in VSCode → "Run Extension"
npm test # headless checks (skips the PDF stage if no browser is installed)
npm run package # build .vsix