MPA Mode
Learn about Multi-Page Application (MPA) mode in VitePress and when to use it.
What is MPA Mode?
Traditional SPA vs MPA
VitePress by default generates a Single Page Application (SPA), but also supports Multi-Page Application (MPA) mode:
SPA Mode (Default):
- Client-side routing
- Faster navigation after initial load
- Shared JavaScript context
- Better for interactive applications
MPA Mode:
- Server-side routing
- Each page is a separate HTML file
- No shared JavaScript context
- Better for content-heavy sites
- Improved SEO and performance
When to Use MPA Mode
Consider MPA mode when:
- You have a large content-heavy site
- SEO is critical
- You want faster initial page loads
- You don't need client-side interactivity
- You want better performance on low-end devices
Enabling MPA Mode
Configuration
Enable MPA mode in your config:
// .vitepress/config.js
export default {
mpa: true,
// Other configuration options
title: 'My MPA Site',
description: 'A multi-page application built with VitePress'
}
Build Output
In MPA mode, VitePress generates:
dist/
├── index.html
├── guide/
│ ├── index.html
│ ├── getting-started.html
│ └── configuration.html
├── api/
│ └── reference.html
└── assets/
├── style.css
└── app.js
Differences from SPA Mode
Navigation
In MPA mode, navigation triggers full page reloads:
// SPA mode - client-side routing
router.push('/guide/getting-started')
// MPA mode - full page navigation
window.location.href = '/guide/getting-started.html'
JavaScript Context
Each page has its own JavaScript context:
// In SPA mode, this persists across pages
let globalState = { count: 0 }
// In MPA mode, this resets on each page load
let pageState = { count: 0 }
Vue Components
Components work differently in MPA mode:
<!-- This component is re-initialized on each page -->
<script setup>
import { ref, onMounted } from 'vue'
const count = ref(0)
// This runs on every page load in MPA mode
onMounted(() => {
console.log('Component mounted')
})
</script>
<template>
<div>
<p>Count: {{ count }}</p>
<button @click="count++">Increment</button>
</div>
</template>
Performance Considerations
Initial Load Performance
MPA mode typically has better initial load performance:
// .vitepress/config.js
export default {
mpa: true,
// Optimize for MPA performance
vite: {
build: {
rollupOptions: {
output: {
manualChunks: undefined // Disable code splitting
}
}
}
}
}
Caching Strategy
Implement proper caching for MPA sites:
// .vitepress/config.js
export default {
mpa: true,
vite: {
build: {
rollupOptions: {
output: {
// Generate consistent file names for better caching
entryFileNames: 'assets/[name].js',
chunkFileNames: 'assets/[name].js',
assetFileNames: 'assets/[name].[ext]'
}
}
}
}
}
SEO Optimization
Meta Tags
Each page gets its own meta tags:
---
title: Getting Started Guide
description: Learn how to get started with our platform
head:
- - meta
- name: keywords
content: getting started, tutorial, guide
- - meta
- property: og:title
content: Getting Started Guide
- - meta
- property: og:description
content: Learn how to get started with our platform
---
# Getting Started
Your content here...
Structured Data
Add structured data to individual pages:
---
head:
- - script
- type: application/ld+json
- |
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "Getting Started Guide",
"author": {
"@type": "Person",
"name": "John Doe"
},
"datePublished": "2024-01-15"
}
---
Sitemap Generation
Generate comprehensive sitemaps:
// .vitepress/config.js
export default {
mpa: true,
sitemap: {
hostname: 'https://example.com',
transformItems: (items) => {
// Add additional metadata for MPA pages
return items.map(item => ({
...item,
changefreq: 'weekly',
priority: item.url === '/' ? 1.0 : 0.8
}))
}
}
}
Limitations and Trade-offs
No Client-side Routing
Navigation is slower due to full page reloads:
// This won't work in MPA mode
import { useRouter } from 'vitepress'
const router = useRouter()
router.push('/new-page') // Not available in MPA mode
No Shared State
State doesn't persist between pages:
// This pattern doesn't work in MPA mode
import { reactive } from 'vue'
// Global state is lost on page navigation
const globalStore = reactive({
user: null,
preferences: {}
})
Limited Interactivity
Complex interactive features are more challenging:
<!-- This component resets on every page load -->
<script setup>
import { ref } from 'vue'
// This state is lost when navigating to another page
const formData = ref({
name: '',
email: ''
})
</script>
Hybrid Approaches
Progressive Enhancement
Start with MPA and add interactivity:
// .vitepress/config.js
export default {
mpa: true,
vite: {
define: {
__MPA_MODE__: true
}
}
}
<script setup>
import { ref, onMounted } from 'vue'
const enhanced = ref(false)
onMounted(() => {
// Add progressive enhancement
if (typeof window !== 'undefined') {
enhanced.value = true
}
})
</script>
<template>
<div>
<!-- Basic functionality for MPA -->
<form v-if="!enhanced" action="/submit" method="post">
<input name="email" type="email" required>
<button type="submit">Submit</button>
</form>
<!-- Enhanced functionality when JavaScript loads -->
<form v-else @submit.prevent="handleSubmit">
<input v-model="email" type="email" required>
<button type="submit">Submit</button>
</form>
</div>
</template>
Selective SPA Islands
Use SPA mode for specific sections:
// .vitepress/config.js
export default {
mpa: true,
// Define SPA-like behavior for specific routes
vite: {
define: {
__SPA_ROUTES__: JSON.stringify(['/dashboard', '/app'])
}
}
}
Migration Strategies
From SPA to MPA
When migrating from SPA to MPA:
- Audit Dependencies: Remove client-side routing dependencies
- Update Navigation: Change internal links to use full URLs
- Refactor State Management: Move to page-level state
- Update Components: Make components stateless where possible
From MPA to SPA
When migrating from MPA to SPA:
- Add Client-side Routing: Implement Vue Router
- Implement State Management: Add global state management
- Update Navigation: Use programmatic navigation
- Optimize Bundle Splitting: Implement code splitting
Best Practices
Performance
- Minimize JavaScript bundle size
- Optimize images and assets
- Implement proper caching headers
- Use CDN for static assets
SEO
- Ensure each page has unique meta tags
- Implement structured data
- Generate comprehensive sitemaps
- Optimize for Core Web Vitals
User Experience
- Provide loading indicators for forms
- Implement proper error handling
- Ensure accessibility compliance
- Test on various devices and connections
Development
- Use TypeScript for better development experience
- Implement proper testing strategies
- Monitor performance metrics
- Document MPA-specific patterns