Tutorial3 hours ago

3. Shipping a Slidev Deck, and the Default Build That Publishes Your Speaker Notes

We built our Slidev talk into a 6.7 MB site in 1.95 seconds, then found the default build lets anyone read the speaker notes at /presenter/. We also exported without the 554 MB Chromium download.

The WJS Desk

Sep 24, 2026 ยท 8 min read

Photo by Ihsan Adityawarman on Pexels

Our nine slide talk from Part 2 now exists in six forms: a static website that builds in about 2 seconds, the same site under a sub-path, a PDF, two kinds of PowerPoint, and a folder of PNGs. We also found a way to export all of them without the 554 MB Chromium download from Part 1, which is the single most useful thing in this course.

We also found the thing that should stop you publishing a deck before reading this: by default, the built website ships your speaker notes, and anyone who adds /presenter/3 to the address can read them.

What we shipped, in numbers

Every output below came from the same slides.md on the same Apple M4 Pro, Slidev 53.0.0. Times are wall clock for the whole command.

OutputCommand timeSizeText selectableKeeps clicks
Static site1.95 to 3.08 s6.7 MB, 142 filesyesyes
PDF6.21 s550 KB, 9 pagesyesno, unless --with-clicks
PPTX7.20 s2.93 MB, 20 slidesno, imagesyes, as extra slides
Editable PPTX3.78 s1.88 MB, 20 slidesyesyes, as extra slides
PNG5.19 s2.1 MB, 9 filesnono

The static site is the only format that keeps the talk as you built it. Everything else is a snapshot of it, and each snapshot loses something different.

Prerequisites

The Part 2 project: @slidev/cli, @slidev/theme-default, and playwright-chromium for the export formats. Python 3 for a throwaway static server (macOS ships it). About 30 minutes. We did not deploy to a real host for this part. Every hosting test below ran against local servers configured to behave like the hosts they stand in for, and we say which.

Step 1: build the website

npx slidev build

Three runs took 3.08, 1.96 and 1.95 seconds. The dist folder was 6.7 MB and 142 files, 125 of them JavaScript totalling 1.74 MB gzipped. For comparison, the starter tour from Part 1 built to 36 MB, because it uses the Monaco code editor and that ships its language workers. Our talk does not, so they are not included.

The folder contains index.html, 404.html, an assets folder, our photo, and a one line _redirects file:

/*    /index.html   200

That file matters more than it looks. The deck is a single page app: /3 is not a real file, the JavaScript works out that it means slide 3. The _redirects line tells a host to answer every path with index.html. Netlify and Cloudflare Pages read that file. A plain file server does not.

Step 2: the refresh that kills your talk

We served dist with the simplest static server there is:

cd dist
python3 -m http.server 8801

Then we drove it with a headless browser: open the deck, press the right arrow three times, reload. The first load worked and the arrows moved us to /3?clicks=1. The reload returned the server's Error response page with a 404. On stage that is the moment you press Cmd+R because a video stalled, and the deck is gone.

The docs recommend testing with Vite's preview server, which does fall back to index.html. With that, a direct request for /5 returned 200. So "it worked when I tested it" and "it breaks on my host" can both be true. If your host does not understand _redirects (plain S3, a university web folder, an nginx box you do not control), use hash routing:

npx slidev build --router-mode hash

URLs become /#/3, the server only ever sees /, and our reload test landed back on slide 3 with its heading on screen.

Step 3: hosting under a sub-path

GitHub Pages puts a project at username.github.io/repo-name/, so the deck lives under a folder, not at the root. We copied the default build into a talk folder under the static server and opened /talk/. We got a blank page and 12 failed requests, every one of them to /assets/ at the site root instead of /talk/assets/. The fix is to tell the build where it will live:

npx slidev build --base /talk/

That took 2.50 seconds and the deck loaded at /talk/1. A refresh on a plain server still returned 404, so for a dumb host under a sub-path you want both flags:

npx slidev build --base /talk/ --router-mode hash

In Part 2 we told you to keep the leading slash on image paths because this is where relative paths would bite. We tested it, and we were wrong to expect trouble. Both image: /terminal.jpg and image: terminal.jpg were rewritten to /talk/terminal.jpg and loaded with a 200. The slash is still the form the docs use, but it is style, not a fix.

The hosting docs include a complete GitHub Actions workflow that builds with --base /${{github.event.repository.name}}/. We read it but did not run it, because it needs a real repository with Pages enabled and we test locally.

Step 4: strip your speaker notes before you publish

We opened /presenter/3 on the built site, the same address a presenter uses. It worked with no password, and the notes pane showed our note for that slide: "Click through one line at a time. The punchline is line 3: GNU never left." The note text also sits in plain text inside dist/assets/index-*.js, where grep found it.

Notes are often where people put the things they would not put on a slide. The fix is one flag, and the hosting docs do mention it:

npx slidev build --without-notes

After that, grep found nothing and the presenter pane said "No notes." The presenter view itself is still reachable, it just has nothing to show.

Gotcha: the website build flag for the output folder is --out (or -o), not --output. slidev build also accepts --output without complaint, because it is one of the export options, and ignores it for the folder. We ran npx slidev build --without-notes --output dist-nonotes, and it quietly overwrote our main dist with a notes-free build. We spent a round of contradictory test results on it before we read --help properly.

Step 5: PowerPoint, twice

For the colleague who needs a .pptx:

npx slidev export --format pptx --output talk

7.20 seconds, 2.93 MB. We unzipped it: 20 slides, 21 media files, 20 notes pages, and the word "SIGSEGV" appears nowhere in the slide XML. Each slide is a picture. Clicks are on by default for this format, so our 9 slides became 20. The notes did come across, which is the redeeming feature.

53.0.0 also has an editable format:

npx slidev export --format pptx-editable --output talk-editable

3.78 seconds, 1.88 MB, 20 slides, only 3 media files, and "SIGSEGV" is real, searchable text on 2 slides. We opened it by converting it through LibreOffice, and it held up: tables, the two columns, the photo, the dimmed code lines. One flaw: code is set in Fira Code, which this Mac does not have installed. LibreOffice fell back to a proportional font and the columns of our dpkg listing no longer lined up. Anyone opening it without Fira Code will see the same. We did not open either file in PowerPoint or Keynote, only LibreOffice.

Step 6: skip the 554 MB download

Every export so far needed Playwright's own Chromium. The export command has a flag, --executable-path, that points it at a browser you already have. We tested it properly: new folder, install without the browser download, then move Playwright's cached Chromium out of the way so it could not be quietly reused.

PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 npm i -D @slidev/cli @slidev/theme-default playwright-chromium

That install took 38.65 seconds on a warm npm cache, with no browser download. A normal export then failed as it should, exit 1, browserType.launch: Executable doesn't exist. Then:

npx slidev export --executable-path "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"

5.90 seconds, 9 pages, 550,044 bytes, against 549,946 bytes from Playwright's Chromium. Same deck, 98 bytes apart, with Chrome 153.0.8010.53. We restored the cache afterwards.

Confirmed: if you have Google Chrome installed, you do not need the 5 minute 29 second, 554 MB download from Part 1. Skip it at install time and pass --executable-path.

We only tested Google Chrome at that one version. We did not try Edge, Brave or Arc.

What broke

Most of this part's failures are listed where they happened, so here they are together:

  • Refresh on a plain server: 404 on any slide but the first. Fix: --router-mode hash, or a host that reads _redirects.
  • Sub-path without --base: blank page, 12 failed asset requests. Fix: --base /your-path/, with slashes at both ends.
  • Notes published by default: readable at /presenter/ and in the JavaScript. Fix: --without-notes.
  • Our own --output mistake: accepted silently, wrote to the wrong folder. The tool was fine. It just did not warn us.
  • Editable PPTX without Fira Code: misaligned code columns in LibreOffice.

One thing that did not break: we blocked every request that was not to our local server and reloaded the deck, to simulate a venue with no Wi-Fi. Exactly one request failed, the Google Fonts stylesheet. Code fell back to the system monospace font with its columns intact, and headings did not change, because the default theme prefers Avenir Next, which is installed on macOS, and only fetches Nunito Sans from Google when Avenir is missing. On Windows or Linux the offline result will look different, and we did not test either.

Common mistakes

  • Testing with vite preview and deploying to a host that does not rewrite paths.
  • Forgetting the trailing slash: the docs say --base must begin and end with /.
  • Sending the image PPTX to someone who needs to edit it. Use pptx-editable, and warn them about the code font.
  • Publishing the default build of a talk whose notes say anything you would not say on stage.
  • Assuming a PDF has your clicks. It has the final state of each slide, as Part 2 showed.

What we did not test

No real deploy to GitHub Pages, Netlify, Vercel or Cloudflare Pages: those were simulated with local servers. No Windows or Linux. No PowerPoint or Keynote, only LibreOffice. No browser exporter at /export, only the CLI. No --dark, --with-toc or --per-slide exports. Timings are from one machine and single digit runs, so treat differences under a second as noise.

Next

Part 4 is the verdict. We put the same talk through Marp, the closest alternative, with a stopwatch on both, and give you a straight answer on who should adopt Slidev and who should not.

Share

The default Slidev build publishes your speaker notes to anyone who opens /presenter/. One flag fixes it. We also skipped a 554 MB download with another. #Slidev #OpenSource #WebDev #GitHubPages

Never miss a ship

The best stuff that shipped this week, delivered every Thursday. Free, no spam. We read all the boring stuff so you get the fun parts.

Keep reading