make-pdf: spurious blank first page when content (frontmatter or leading <style>) precedes the first H1
- Dominant language
- TypeScript
- Stars
- 133k
- Forks
- 19.9k
- Avg merge
- 18h 46m
- Merged PRs (30d)
- 26
Description
## Bug
`make-pdf` emits a spurious blank/near-blank **first page** whenever the markdown has *any* content before the first `
`. Two common triggers:
1. **YAML frontmatter** — a leading `---\n...\n---` block is not parsed/stripped, so `marked` renders it as a literal paragraph of body text on its own page (`title: ... type: ... tags: [...]`).
2. **A leading top-of-file `` block** — even though it renders nothing visible, it still produces an empty first page.
## Root cause
In `make-pdf/src/render.ts`, `wrapChaptersByH1()` treats everything before the first `<h1>` as a **preamble chapter**:
```ts
const preamble = html.slice(0, matches[0]);
if (preamble.trim().length > 0) {
chunks.push(`<section class="chapter">${preamble}</section>`);
}
```
Combined with the chapter CSS:
```css
.chapter { break-before: page; page-break-before: always; }
.chapter:first-of-type { break-before: auto; page-break-before: auto; }
```
When a preamble chapter exists it becomes `:first-of-type`, so the first *real* `<h1>` chapter no longer gets the `break-before: auto` exception — it inherits `break-before: page` and starts on page 2. The preamble (frontmatter text, or an invisible `<style>` block) occupies page 1. `preamble.trim().length > 0` is true even when the preamble contains only non-rendering markup (`<style>…`), so an invisible preamble still forces the break.
## Repro
```bash
printf 'h1{color:#000}\n\n# Hello\n\nBody.\n' > t.md
pdf generate t.md t.pdf
pdfinfo t.pdf # => Pages: 2 (page 1 blank)
printf '# Hello\n\nh1{color:#000}\n\nBody.\n' > t2.md
pdf generate t2.md t2.pdf
pdfinfo t2.pdf # => Pages: 1 (correct)
```
## Suggested fix (either/both)
1. **Strip YAML frontmatter** before `marked.parse` — a leading `^---\n[\s\S]*?\n---\n?` block.
2. **Don't create a preamble chapter for non-rendering content** — strip `/<script>/<link>/<meta>` from the preamble slice before the `preamble.trim().length > 0` check (or hoist a leading `<style>` into `<head>`), so an invisible preamble doesn't force a page break / empty first page.
## Workaround
Strip frontmatter caller-side and inject the width-fit `<style>` block *after* the first heading rather than prepending it. Confirmed to produce the correct page count.
Contributor guide
Research direction
Start in make-pdf/src/render.ts and inspect wrapChaptersByH1(), then reproduce the issue with the provided printf, pdf generate, and pdfinfo commands. Ensure frontmatter and non-rendering leading markup do not create a preamble chapter or blank first page, while content after the first heading still renders correctly; verify the affected examples produce one page.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- cli
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100