VuePress
GitHub Overview
vuejs/vuepress
📝 Minimalistic Vue-powered static site generator
Topics
Star History
Documentation Tool
VuePress
Overview
VuePress is a static site generator based on Vue.js. It combines Markdown-based content creation with the power of Vue.js to build fast and beautiful documentation sites.
Details
VuePress was developed by Evan You (creator of Vue.js) in 2018 and was born as the official documentation tool for the Vue.js ecosystem. While based on Markdown files, it can leverage the powerful features of Vue.js components. It achieves fast display speeds through static site generation (SSG) while providing rich user experiences as a Single Page Application (SPA). The plugin system allows you to add diverse functionality such as search, PWA support, blog features, and multi-language support. The theme system allows you to either use the beautiful default theme or create completely custom themes. It's closely integrated with the Vue.js ecosystem, allowing direct use of Vue components within Markdown. As of 2025, it's adopted as the official documentation tool for many Vue.js projects including Vue.js, Element Plus, and Ant Design Vue. VuePress 2 significantly improves the development experience with Vite integration, providing much faster builds and development servers. It comes standard with modern documentation site features including version control, multi-language site building, and SEO optimization. VuePress 2 offers better TypeScript support, improved plugin architecture, and enhanced theme development capabilities.
Advantages and Disadvantages
Advantages
- Vue.js Integration: Seamless combination of Markdown and Vue components
- Fast Display: Excellent performance and SEO through static site generation
- SPA Experience: Rich user experience and navigation during page transitions
- Rich Plugins: Official plugins for search, PWA, blog, and multi-language support
- Beautiful Default Theme: Clean and sophisticated design ready to use
- Vue.js Ecosystem: Integration with existing Vue component libraries
- Developer Experience: Fast development server and hot reload with Vite integration
Disadvantages
- Vue.js Dependency: Requires Vue.js knowledge, learning curve exists
- Node.js Environment: Node.js environment required for development and building
- Build Time: Increased build time for large-scale sites
- Plugin Limitations: Limited plugin choices outside the Vue.js ecosystem
- Customization Complexity: Advanced customization requires understanding of Vue.js and Webpack/Vite
- Memory Usage: High memory consumption during development for large sites
Key Links
- VuePress Official Site
- VuePress 2.x Documentation
- GitHub Repository
- Official Plugin List
- Community Themes
- VuePress Next (v2)
Usage Examples
Project Initialization
# Create VuePress project
yarn create vuepress-site my-docs
# or
npx create-vuepress-site my-docs
# Project structure
my-docs/
├── docs/ # Documentation directory
│ ├── .vuepress/ # VuePress configuration directory
│ │ ├── config.js # Site configuration file
│ │ ├── components/ # Custom Vue components
│ │ ├── theme/ # Custom theme
│ │ └── public/ # Static assets
│ ├── guide/ # Guide section
│ └── README.md # Home page
└── package.json
Basic Configuration File (config.js)
// docs/.vuepress/config.js
module.exports = {
// Basic site information
title: 'Project Documentation',
description: 'Vue.js-based documentation site',
base: '/',
lang: 'en-US',
// Head configuration
head: [
['link', { rel: 'icon', href: '/favicon.ico' }],
['meta', { name: 'theme-color', content: '#3eaf7c' }],
['meta', { name: 'apple-mobile-web-app-capable', content: 'yes' }],
['meta', { name: 'apple-mobile-web-app-status-bar-style', content: 'black' }]
],
// Theme configuration
themeConfig: {
// Navigation bar
nav: [
{ text: 'Home', link: '/' },
{ text: 'Guide', link: '/guide/' },
{ text: 'API', link: '/api/' },
{ text: 'GitHub', link: 'https://github.com/username/project' }
],
// Sidebar
sidebar: {
'/guide/': [
'',
'getting-started',
'installation',
'configuration',
'deployment'
],
'/api/': [
'',
'components',
'directives',
'utilities'
]
},
// Git repository configuration
repo: 'username/project',
repoLabel: 'GitHub',
docsDir: 'docs',
docsBranch: 'main',
editLinks: true,
editLinkText: 'Edit this page',
// Last updated timestamp
lastUpdated: 'Last Updated',
// Search configuration
search: true,
searchMaxSuggestions: 10,
// Algolia DocSearch configuration
algolia: {
apiKey: 'your-api-key',
indexName: 'your-index-name'
}
},
// Plugin configuration
plugins: [
'@vuepress/back-to-top',
'@vuepress/medium-zoom',
['@vuepress/pwa', {
serviceWorker: true,
updatePopup: {
message: "New content is available.",
buttonText: "Update"
}
}],
['@vuepress/google-analytics', {
'ga': 'UA-XXXXXXXXX-X'
}]
],
// Markdown configuration
markdown: {
lineNumbers: true,
anchor: { permalink: true },
toc: { includeLevel: [1, 2, 3] },
plugins: [
'markdown-it-container',
'markdown-it-footnote',
'markdown-it-deflist'
]
},
// Build configuration
evergreen: true,
dest: 'dist',
// Multi-language configuration
locales: {
'/': {
lang: 'en-US',
title: 'Project Documentation',
description: 'Vue.js-powered documentation site'
},
'/ja/': {
lang: 'ja-JP',
title: 'プロジェクトドキュメント',
description: 'Vue.jsベースのドキュメントサイト'
}
}
}
Markdown and Vue.js Component Integration
# VuePress Usage Guide
## Basic Markdown
VuePress extends Markdown to provide various features.
### Custom Containers
::: tip Tip
This is a helpful tip.
:::
::: warning Warning
This requires attention.
:::
::: danger Danger
This is a warning about dangerous operations.
:::
::: details Click to see details
Detailed explanation appears here.
:::
### Code Blocks
```javascript{2-4}
function example() {
// These lines will be highlighted
const message = 'Hello VuePress!'
console.log(message)
return message
}
Using Vue.js Components
<CustomComponent :prop="value" @event="handler"> Slot content
Dynamic Content
Current time: {{ new Date().toLocaleString() }}
Counter: {{ counter }} <button @click="increment">Click
### Creating Custom Vue Components
```vue
<!-- docs/.vuepress/components/FeatureCard.vue -->
<template>
<div class="feature-card">
<div class="feature-icon">
<slot name="icon"></slot>
</div>
<h3 class="feature-title">{{ title }}</h3>
<p class="feature-description">{{ description }}</p>
<div class="feature-actions">
<slot name="actions"></slot>
</div>
</div>
</template>
<script>
export default {
name: 'FeatureCard',
props: {
title: {
type: String,
required: true
},
description: {
type: String,
required: true
}
}
}
</script>
<style scoped>
.feature-card {
border: 1px solid #e0e6ed;
border-radius: 8px;
padding: 24px;
margin: 16px 0;
background: #ffffff;
transition: box-shadow 0.3s ease;
}
.feature-card:hover {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
.feature-icon {
font-size: 2em;
margin-bottom: 16px;
color: #3eaf7c;
}
.feature-title {
margin: 0 0 12px 0;
font-size: 1.4em;
color: #2c3e50;
}
.feature-description {
margin: 0 0 16px 0;
color: #5e6d82;
line-height: 1.6;
}
.feature-actions {
display: flex;
gap: 12px;
}
</style>
Plugin Development Example
// plugins/custom-plugin.js
module.exports = (options = {}, context) => ({
name: 'custom-plugin',
// Plugin configuration
async ready() {
// Plugin initialization process
console.log('Custom plugin is ready!')
},
// Markdown extension
extendMarkdown(md) {
md.use(require('markdown-it-container'), 'custom', {
validate: function(params) {
return params.trim().match(/^custom\s+(.*)$/)
},
render: function(tokens, idx) {
const m = tokens[idx].info.trim().match(/^custom\s+(.*)$/)
if (tokens[idx].nesting === 1) {
return `<div class="custom-container">
<div class="custom-title">${m[1]}</div>
<div class="custom-content">`
} else {
return '</div></div>'
}
}
})
},
// Page extension
async additionalPages() {
return [
{
path: '/custom-page/',
frontmatter: {
title: 'Custom Page',
layout: 'CustomLayout'
}
}
]
},
// Client-side extension
enhanceAppFiles: [
path.resolve(__dirname, 'enhanceApp.js')
],
// Build-time processing
async generated(pagePaths) {
// Post-processing of generated pages
console.log('Generated pages:', pagePaths.length)
}
})
Theme Customization
// docs/.vuepress/theme/index.js
const path = require('path')
module.exports = {
// Inherit parent theme
extend: '@vuepress/theme-default',
// Layout overrides
layouts: {
Layout: path.resolve(__dirname, 'layouts/Layout.vue'),
404: path.resolve(__dirname, 'layouts/404.vue')
},
// Global components
globalLayout: path.resolve(__dirname, 'layouts/GlobalLayout.vue'),
// Plugin additions
plugins: [
'@vuepress/back-to-top',
'@vuepress/nprogress',
['@vuepress/search', {
searchMaxSuggestions: 10
}]
]
}
Custom Layout Component
<!-- docs/.vuepress/theme/layouts/Layout.vue -->
<template>
<div class="custom-layout">
<!-- Header -->
<header class="custom-header">
<nav class="custom-nav">
<router-link to="/" class="custom-logo">
<img src="/logo.png" alt="Logo">
</router-link>
<ul class="custom-nav-links">
<li v-for="item in $themeConfig.nav" :key="item.text">
<NavLink :item="item"/>
</li>
</ul>
</nav>
</header>
<!-- Main content -->
<main class="custom-main">
<aside class="custom-sidebar" v-if="shouldShowSidebar">
<Sidebar :items="sidebarItems"/>
</aside>
<div class="custom-content">
<div class="content-wrapper">
<!-- Page content -->
<Content/>
<!-- Page navigation -->
<PageNav v-bind="{ sidebarItems }"/>
<!-- Edit link -->
<PageEdit/>
</div>
</div>
</main>
<!-- Footer -->
<footer class="custom-footer">
<p>© {{ new Date().getFullYear() }} Project Name</p>
</footer>
</div>
</template>
<script>
import Home from '@theme/components/Home.vue'
import Navbar from '@theme/components/Navbar.vue'
import Page from '@theme/components/Page.vue'
import Sidebar from '@theme/components/Sidebar.vue'
import { resolveSidebarItems } from '@theme/util'
export default {
name: 'Layout',
components: {
Home,
Page,
Sidebar,
Navbar
},
computed: {
shouldShowSidebar() {
const { frontmatter } = this.$page
return !frontmatter.home &&
frontmatter.sidebar !== false &&
this.sidebarItems.length
},
sidebarItems() {
return resolveSidebarItems(
this.$page,
this.$page.regularPath,
this.$site,
this.$localePath
)
}
}
}
</script>
<style lang="stylus">
.custom-layout
min-height 100vh
display flex
flex-direction column
.custom-header
background #ffffff
border-bottom 1px solid #eaecef
position sticky
top 0
z-index 20
.custom-nav
max-width 1200px
margin 0 auto
padding 0 2rem
display flex
align-items center
justify-content space-between
height 3.5rem
.custom-logo img
height 2rem
.custom-nav-links
display flex
list-style none
margin 0
padding 0
gap 2rem
.custom-main
flex 1
display flex
max-width 1200px
margin 0 auto
width 100%
.custom-sidebar
width 20rem
flex-shrink 0
.custom-content
flex 1
min-width 0
.content-wrapper
padding 2rem
max-width 740px
.custom-footer
background #f8f9fa
text-align center
padding 2rem
border-top 1px solid #eaecef
</style>
Build and Auto-deploy Configuration
# .github/workflows/deploy.yml
name: Build and Deploy VuePress
on:
push:
branches: [ main ]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 18
cache: yarn
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Build VuePress
run: yarn docs:build
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: docs/.vuepress/dist
cname: docs.example.com
Advanced Features and Workflow
// docs/.vuepress/enhanceApp.js
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
export default ({
Vue, // Vue constructor used by VuePress app
options, // Root instance options
router, // Current app router instance
siteData // Site metadata
}) => {
// Register Element UI globally
Vue.use(ElementUI)
// Register global components
Vue.component('demo-component', {
template: '<div class="demo">{{ message }}</div>',
data() {
return {
message: 'Hello from global component!'
}
}
})
// Add global mixin
Vue.mixin({
computed: {
$title() {
return this.$page.title || this.$site.title
}
}
})
// Add router guards
router.beforeEach((to, from, next) => {
console.log('Navigating to:', to.path)
next()
})
// Hot reload settings for development environment
if (process.env.NODE_ENV === 'development' && module.hot) {
module.hot.accept()
}
}
Development and Build Commands
# Start development server
yarn docs:dev
# or
npm run docs:dev
# Production build
yarn docs:build
# or
npm run docs:build
# Start with specific port
vuepress dev docs --port 8080
# Start in debug mode
DEBUG=vuepress:* vuepress dev docs
# Check plugin details
vuepress info
# Clear cache
rm -rf docs/.vuepress/.cache docs/.vuepress/dist
# Custom theme ejection (not recommended)
vuepress eject docs