From 741ac0a44b5e0e26a8efb71eca315261919eb6c8 Mon Sep 17 00:00:00 2001 From: James Devine Date: Tue, 23 Jun 2026 10:13:18 +0100 Subject: [PATCH] docs(site): fix presenter-mode navigation on deployed deck MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Presenter mode on the published deck duplicated the path segment when advancing slides (…/#/presenter/presenter/2). Slidev's getSlidePath() prepends the Vite base (import.meta.env.BASE_URL) to every router target, so any non-root base leaks into — or, for nested presenter routes, compounds in — the hash route. Build the deck with the default base / (so BASE_URL stays / and hash routes resolve cleanly as /N and /presenter/N for both play and presenter), emit relative asset URLs via Vite experimental.renderBuiltUrl, and post-build rewrite the entry HTML's /assets/ references to ./assets/ so the bundle still loads from /ado-aw/slides/. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- site/slides/package.json | 2 +- site/slides/postbuild.mjs | 33 +++++++++++++++++++++++++++++++++ site/slides/vite.config.ts | 17 +++++++++++++++++ 3 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 site/slides/postbuild.mjs create mode 100644 site/slides/vite.config.ts diff --git a/site/slides/package.json b/site/slides/package.json index 7bcfcb8e..d4b0b6b8 100644 --- a/site/slides/package.json +++ b/site/slides/package.json @@ -6,7 +6,7 @@ "description": "Short intro deck for ado-aw — Continuous AI for Azure DevOps", "scripts": { "dev": "slidev --open", - "build": "slidev build --base ./ --out ../public/slides", + "build": "slidev build --out ../public/slides && node postbuild.mjs ../public/slides", "export": "slidev export --wait 1500 --wait-until networkidle --output dist/ado-aw-intro.pdf" }, "dependencies": { diff --git a/site/slides/postbuild.mjs b/site/slides/postbuild.mjs new file mode 100644 index 00000000..19cdd1f9 --- /dev/null +++ b/site/slides/postbuild.mjs @@ -0,0 +1,33 @@ +// Post-build step for the sub-path deployment of the Slidev deck. +// +// The deck is built with the default Vite base "/" so that Slidev's in-app +// navigation (getSlidePath → import.meta.env.BASE_URL) produces clean hash +// routes (/N and /presenter/N) for both play and presenter mode. JS/CSS asset +// URLs are emitted relative via experimental.renderBuiltUrl (see vite.config.ts). +// +// The only thing left pointing at an absolute "/assets/…" path is the entry +// markup in the generated HTML files. Rewrite those to "./assets/…" so the +// bundle also loads correctly when served from …/ado-aw/slides/. +import { readdir, readFile, writeFile } from 'node:fs/promises' +import path from 'node:path' + +const outDir = process.argv[2] +if (!outDir) { + console.error('usage: node postbuild.mjs ') + process.exit(1) +} + +const entries = await readdir(outDir, { withFileTypes: true }) +let patched = 0 +for (const e of entries) { + if (!e.isFile() || !e.name.endsWith('.html')) continue + const fp = path.join(outDir, e.name) + const src = await readFile(fp, 'utf8') + const out = src.replaceAll('="/assets/', '="./assets/') + if (out !== src) { + await writeFile(fp, out) + patched++ + console.log(` rewrote ${e.name}`) + } +} +console.log(`postbuild: relative-ized assets in ${patched} HTML file(s)`) diff --git a/site/slides/vite.config.ts b/site/slides/vite.config.ts new file mode 100644 index 00000000..d0e67c73 --- /dev/null +++ b/site/slides/vite.config.ts @@ -0,0 +1,17 @@ +import { defineConfig } from 'vite' + +// Deploy the deck under a sub-path (…/ado-aw/slides/) without breaking Slidev's +// in-app navigation. Slidev's getSlidePath() prepends import.meta.env.BASE_URL +// to every router target, so a non-"/" Vite base leaks into (or doubles in) the +// route path — which breaks presenter mode in particular. +// +// Fix: keep the Vite base at "/" (so BASE_URL stays "/", and hash routes resolve +// cleanly as /N and /presenter/N), but emit *relative* asset URLs via +// renderBuiltUrl so the bundle still loads correctly from the sub-path. +export default defineConfig({ + experimental: { + renderBuiltUrl() { + return { relative: true } + }, + }, +})