VuePress

GitHub概要

vuejs/vuepress

📝 Minimalistic Vue-powered static site generator

スター22,801
ウォッチ261
フォーク4,727
作成日:2018年4月5日
言語:JavaScript
ライセンス:MIT License

トピックス

blog-enginedocs-generatorseostatic-site-generatorvuevuepress

スター履歴

vuejs/vuepress Star History
データ取得日時: 2025/8/13 01:43

ドキュメント作成ツール

VuePress

概要

VuePressはVue.jsを基盤とした静的サイトジェネレータです。マークダウンベースのコンテンツ作成とVue.jsの表現力を組み合わせ、高速で美しいドキュメントサイトを構築できます。

詳細

VuePress(ビュープレス)は2018年にEvan You(Vue.jsの作者)によって開発され、Vue.jsエコシステムの公式ドキュメントツールとして誕生しました。マークダウンファイルを基盤としながら、Vue.jsコンポーネントの強力な機能を活用できます。静的サイト生成(SSG)により高速な表示速度を実現し、同時にSPAとしてのリッチなユーザー体験を提供します。プラグインシステムにより、検索機能、PWA対応、ブログ機能、多言語対応など多彩な機能を追加できます。テーマシステムにより、デフォルトテーマの美しいデザインを使用するか、完全カスタムテーマを作成できます。Vue.jsエコシステムと密接に統合されており、VueコンポーネントをMarkdown内で直接使用できます。2025年現在、Vue.js、Element Plus、Ant Design Vue等の多くのVue.jsプロジェクトで公式ドキュメントツールとして採用されています。VuePress 2ではVite統合により開発体験が大幅に向上し、より高速なビルドと開発サーバーを実現しています。バージョン管理、多言語サイト構築、SEO最適化など、現代的なドキュメントサイトに必要な機能を標準装備しています。

メリット・デメリット

メリット

  • Vue.js統合: MarkdownとVueコンポーネントのシームレスな組み合わせ
  • 高速表示: 静的サイト生成による優れたパフォーマンスとSEO
  • SPA体験: ページ遷移時のリッチなユーザー体験とナビゲーション
  • 豊富なプラグイン: 検索、PWA、ブログ、多言語対応の公式プラグイン
  • 美しいデフォルトテーマ: すぐに使える洗練されたデザイン
  • Vue.jsエコシステム: 既存のVueコンポーネントライブラリとの統合
  • 開発者体験: Vite統合による高速な開発サーバーとホットリロード

デメリット

  • Vue.js依存: Vue.jsの知識が必要、学習コストの存在
  • Node.js環境: 開発・ビルドにNode.js環境が必須
  • ビルド時間: 大規模サイトでのビルド時間増加
  • プラグイン制限: Vue.js生態系外のプラグイン選択肢の限定
  • カスタマイズ複雑性: 高度なカスタマイズにはVue.jsとWebpack/Viteの理解が必要
  • メモリ使用量: 大規模サイトでの開発時メモリ消費

主要リンク

書き方の例

プロジェクトの初期化

# VuePressプロジェクトの作成
yarn create vuepress-site my-docs
# または
npx create-vuepress-site my-docs

# プロジェクト構造
my-docs/
├── docs/                 # ドキュメントディレクトリ
│   ├── .vuepress/       # VuePress設定ディレクトリ
│   │   ├── config.js    # サイト設定ファイル
│   │   ├── components/  # カスタムVueコンポーネント
│   │   ├── theme/      # カスタムテーマ
│   │   └── public/     # 静的アセット
│   ├── guide/          # ガイドセクション
│   └── README.md       # ホームページ
└── package.json

基本的な設定ファイル(config.js)

// docs/.vuepress/config.js
module.exports = {
  // サイト基本情報
  title: 'プロジェクトドキュメント',
  description: 'Vue.jsベースのドキュメントサイト',
  base: '/',
  lang: 'ja-JP',

  // ヘッド設定
  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' }]
  ],

  // テーマ設定
  themeConfig: {
    // ナビゲーションバー
    nav: [
      { text: 'ホーム', link: '/' },
      { text: 'ガイド', link: '/guide/' },
      { text: 'API', link: '/api/' },
      { text: 'GitHub', link: 'https://github.com/username/project' }
    ],

    // サイドバー
    sidebar: {
      '/guide/': [
        '',
        'getting-started',
        'installation',
        'configuration',
        'deployment'
      ],
      '/api/': [
        '',
        'components',
        'directives',
        'utilities'
      ]
    },

    // Git リポジトリ設定
    repo: 'username/project',
    repoLabel: 'GitHub',
    docsDir: 'docs',
    docsBranch: 'main',
    editLinks: true,
    editLinkText: 'このページを編集',

    // 最終更新日時表示
    lastUpdated: '最終更新',

    // 検索設定
    search: true,
    searchMaxSuggestions: 10,

    // Algolia DocSearch設定
    algolia: {
      apiKey: 'your-api-key',
      indexName: 'your-index-name'
    }
  },

  // プラグイン設定
  plugins: [
    '@vuepress/back-to-top',
    '@vuepress/medium-zoom',
    ['@vuepress/pwa', {
      serviceWorker: true,
      updatePopup: {
        message: "新しいコンテンツが利用可能です。",
        buttonText: "更新"
      }
    }],
    ['@vuepress/google-analytics', {
      'ga': 'UA-XXXXXXXXX-X'
    }]
  ],

  // Markdown設定
  markdown: {
    lineNumbers: true,
    anchor: { permalink: true },
    toc: { includeLevel: [1, 2, 3] },
    plugins: [
      'markdown-it-container',
      'markdown-it-footnote',
      'markdown-it-deflist'
    ]
  },

  // ビルド設定
  evergreen: true,
  dest: 'dist',
  
  // 多言語設定
  locales: {
    '/': {
      lang: 'ja-JP',
      title: 'プロジェクトドキュメント',
      description: 'Vue.jsベースのドキュメントサイト'
    },
    '/en/': {
      lang: 'en-US',
      title: 'Project Documentation',
      description: 'Vue.js-powered documentation site'
    }
  }
}

マークダウンと Vue.js コンポーネントの統合

# VuePressの活用ガイド

## 基本的なマークダウン

VuePressはマークダウンを拡張し、様々な機能を提供します。

### カスタムコンテナ
::: tip ヒント
これは便利なヒントです。
:::

::: warning 注意
注意が必要な内容です。
:::

::: danger 危険
危険な操作に関する警告です。
:::

::: details クリックして詳細を表示
詳細な説明がここに表示されます。
:::

### コードブロック
```javascript{2-4}
function example() {
  // この部分がハイライトされます
  const message = 'Hello VuePress!'
  console.log(message)
  return message
}

Vue.jsコンポーネントの使用

<CustomComponent :prop="value" @event="handler">

動的コンテンツ

現在の時刻: {{ new Date().toLocaleString() }}

カウンター: {{ counter }} <button @click="increment">クリック


### カスタムVueコンポーネントの作成
```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>

プラグイン開発の例

// plugins/custom-plugin.js
module.exports = (options = {}, context) => ({
  name: 'custom-plugin',
  
  // プラグイン設定
  async ready() {
    // プラグイン初期化処理
    console.log('Custom plugin is ready!')
  },

  // Markdown拡張
  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>'
        }
      }
    })
  },

  // ページ拡張
  async additionalPages() {
    return [
      {
        path: '/custom-page/',
        frontmatter: {
          title: 'カスタムページ',
          layout: 'CustomLayout'
        }
      }
    ]
  },

  // クライアント側拡張
  enhanceAppFiles: [
    path.resolve(__dirname, 'enhanceApp.js')
  ],

  // ビルド時処理
  async generated(pagePaths) {
    // 生成されたページの後処理
    console.log('Generated pages:', pagePaths.length)
  }
})

テーマカスタマイズ

// docs/.vuepress/theme/index.js
const path = require('path')

module.exports = {
  // 親テーマを継承
  extend: '@vuepress/theme-default',
  
  // レイアウトのオーバーライド
  layouts: {
    Layout: path.resolve(__dirname, 'layouts/Layout.vue'),
    404: path.resolve(__dirname, 'layouts/404.vue')
  },

  // グローバルコンポーネント
  globalLayout: path.resolve(__dirname, 'layouts/GlobalLayout.vue'),

  // プラグインの追加
  plugins: [
    '@vuepress/back-to-top',
    '@vuepress/nprogress',
    ['@vuepress/search', {
      searchMaxSuggestions: 10
    }]
  ]
}

カスタムレイアウトコンポーネント

<!-- docs/.vuepress/theme/layouts/Layout.vue -->
<template>
  <div class="custom-layout">
    <!-- ヘッダー -->
    <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 class="custom-main">
      <aside class="custom-sidebar" v-if="shouldShowSidebar">
        <Sidebar :items="sidebarItems"/>
      </aside>
      
      <div class="custom-content">
        <div class="content-wrapper">
          <!-- ページコンテンツ -->
          <Content/>
          
          <!-- ページナビゲーション -->
          <PageNav v-bind="{ sidebarItems }"/>
          
          <!-- 編集リンク -->
          <PageEdit/>
        </div>
      </div>
    </main>

    <!-- フッター -->
    <footer class="custom-footer">
      <p>&copy; {{ new Date().getFullYear() }} プロジェクト名</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>

ビルドと自動デプロイ設定

# .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

高度な機能とワークフロー

// docs/.vuepress/enhanceApp.js
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'

export default ({
  Vue, // VuePressが使用しているVueコンストラクタ
  options, // ルートインスタンスのオプション
  router, // 現在のアプリのルーターインスタンス
  siteData // サイトメタデータ
}) => {
  // Element UIをグローバルに登録
  Vue.use(ElementUI)
  
  // グローバルコンポーネントの登録
  Vue.component('demo-component', {
    template: '<div class="demo">{{ message }}</div>',
    data() {
      return {
        message: 'Hello from global component!'
      }
    }
  })

  // グローバルミックスインの追加
  Vue.mixin({
    computed: {
      $title() {
        return this.$page.title || this.$site.title
      }
    }
  })

  // ルーターガードの追加
  router.beforeEach((to, from, next) => {
    console.log('Navigating to:', to.path)
    next()
  })

  // 開発環境でのホットリロード設定
  if (process.env.NODE_ENV === 'development' && module.hot) {
    module.hot.accept()
  }
}

開発・ビルドコマンド

# 開発サーバー起動
yarn docs:dev
# または
npm run docs:dev

# 本番ビルド
yarn docs:build
# または
npm run docs:build

# 特定ポートでの起動
vuepress dev docs --port 8080

# デバッグモードでの起動
DEBUG=vuepress:* vuepress dev docs

# プラグインの詳細確認
vuepress info

# キャッシュクリア
rm -rf docs/.vuepress/.cache docs/.vuepress/dist

# カスタムテーマのejection(非推奨)
vuepress eject docs