diff --git a/docs/guide/hosting.md b/docs/guide/hosting.md index 0a0c30d6e8..6ad35269c3 100644 --- a/docs/guide/hosting.md +++ b/docs/guide/hosting.md @@ -189,6 +189,40 @@ Create `vercel.json` in your project root with the following content: Then go to your [Vercel dashboard](https://vercel.com/) and create a new site with the repository. +### Cloudflare Pages + +Slidev automatically detects when you are deploying to [Cloudflare Pages](https://pages.cloudflare.com/) by looking for a `wrangler.toml` or `wrangler.json` file in your project root. + +When detected, Slidev generates the necessary `_redirects` and `_headers` files for optimal SPA hosting. + +Create a `wrangler.toml` in your project root: + +::: details wrangler.toml + +```toml +name = "my-slidev" +compatibility_date = "2026-04-29" +``` + +::: + +Then build and deploy: + +```bash +$ slidev build +$ npx wrangler pages deploy dist +``` + +#### Preview locally with Wrangler + +You can test the Cloudflare Pages build locally using [Wrangler](https://developers.cloudflare.com/workers/wrangler/): + +```bash +$ npx wrangler pages dev dist +``` + +The `_headers` file generated by Slidev sets long-term caching for hashed assets, ensuring optimal performance. + ### Zephyr Cloud {#zephyr-cloud} To deploy your Slidev deck on [Zephyr Cloud](https://zephyr-cloud.io/), you can add Zephyr support to an existing Slidev project with: diff --git a/packages/slidev/node/commands/build.ts b/packages/slidev/node/commands/build.ts index f02313508e..6066831f94 100644 --- a/packages/slidev/node/commands/build.ts +++ b/packages/slidev/node/commands/build.ts @@ -126,10 +126,26 @@ export async function build( // copy index.html to 404.html for GitHub Pages await fs.copyFile(resolve(outDir, 'index.html'), resolve(outDir, '404.html')) - // _redirects for SPA + + // _redirects for SPA (supported by Netlify and Cloudflare Pages) const redirectsPath = resolve(outDir, '_redirects') - if (!existsSync(redirectsPath)) - await fs.writeFile(redirectsPath, `${config.base}* ${config.base}index.html 200\n`, 'utf-8') + if (!existsSync(redirectsPath)) { + const base = config.base + await fs.writeFile( + redirectsPath, + `${base}index.html ${base}index.html 200\n${base}* ${base}index.html 200\n`, + 'utf-8', + ) + } + + // _headers for Cloudflare Pages (auto-detected via wrangler config) + const hasWranglerConfig = existsSync(resolve(options.userRoot, 'wrangler.toml')) || existsSync(resolve(options.userRoot, 'wrangler.json')) + if (hasWranglerConfig) { + const headersPath = resolve(outDir, '_headers') + if (!existsSync(headersPath)) { + await fs.writeFile(headersPath, `\n/assets/*\n Cache-Control: public, max-age=31536000, immutable\n`, 'utf-8') + } + } if ([true, 'true', 'auto'].includes(options.data.config.download)) { const { exportSlides, getExportOptions } = await import('./export') diff --git a/skills/slidev/references/core-hosting.md b/skills/slidev/references/core-hosting.md index 1ddb08bf9d..59a9d3ce92 100644 --- a/skills/slidev/references/core-hosting.md +++ b/skills/slidev/references/core-hosting.md @@ -88,6 +88,34 @@ Create `netlify.toml`: status = 200 ``` +## Cloudflare Pages + +Slidev auto-detects Cloudflare Pages when a `wrangler.toml` or `wrangler.json` is present in the project root. + +Create `wrangler.toml`: + +```toml +name = "my-slidev" +compatibility_date = "2026-04-29" +``` + +Build and deploy: + +```bash +slidev build +npx wrangler pages deploy dist +``` + +Cloudflare Pages supports Netlify-style `_redirects` out of the box. When detected, Slidev also generates a `_headers` file with optimal cache settings for hashed assets. + +### Local preview + +Test with Wrangler locally: + +```bash +npx wrangler pages dev dist +``` + ## Vercel Create `vercel.json`: