NNicheStackTutorials
← All tutorials
VitePress

VitePress Static Export Without SSR Surprises

Pure static HTML output — what runs at build vs browser, and avoiding window is not defined.

·9 min read·VitePress
VitePress Static Export Without SSR Surprises cover

Tested on: VitePress 1.6.3, no SSR server in production Myth: VitePress needs Node server. Reality: vitepress build emits static files only.

Build = SSG

npm run docs:build
ls docs/.vitepress/dist
# index.html, assets/*.js, guide/**/index.html

Deploy dist to any static host. No vitepress serve in production.

Client-only code guard

Error in build:

ReferenceError: window is not defined

Custom component accessed window at module top level.

Fix:

<script setup>
import { onMounted } from 'vue'
onMounted(() => {
  // window access here only
})
</script>

Or:

if (typeof window !== 'undefined') { ... }

theme index.ts setup

export default {
  ...DefaultTheme,
  setup() {
  if (typeof document === 'undefined') return
    // client-only listeners
  }
}

Dynamic imports

<script setup>
import { defineAsyncComponent } from 'vue'
const Chart = defineAsyncComponent(() => import('./Chart.vue'))
</script>

Chart won't render meaningful HTML in view-source — acceptable for interactive widgets.

mpaMode (optional)

VitePress 1.x default is SPA with prefetch. For maximum static simplicity, still one JS bundle hydrates.

Don't confuse with ssr: true — VitePress docs site doesn't use SSR by default.

Verify static

npm run docs:build
npx serve docs/.vitepress/dist -p 8080
# disconnect network → site still loads (except external fonts)

View source on /guide/foo/ — content HTML present (SEO OK).

CI check

grep -r "window." docs/.vitepress/theme --include="*.vue" --include="*.ts"
# audit top-level usage

Result

Hosted on S3 static website + CloudFront. Zero Node runtime. Lighthouse SEO 100.

Tags: VitePressSSGStatic ExportVue