Misskey & Webテクノロジー最前線

VuePressを用いた静的サイト生成入門

本連載は分散型マイクロブログ用ソフトウェアMisskeyの開発に関する紹介と、関連するWeb技術について解説を行うものです。今回はMisskeyオフィシャルサイトであるMisskey Hubでも使用している、静的サイトジェネレーターVuePressについて紹介します。

図1 VuePressで構築されている「Misskey Hub」
図1

静的サイトとは

静的なサイトを理解するにはまず動的なサイトを理解するのが早いと思います。

動的(dynamic)なサイトとは、簡単に言うと閲覧者のアクセスごとに内容をサーバーで生成するWebサイトのことです。例えばTwitterのようなサービスを考えると、表示されるタイムラインは閲覧者がフォローしているユーザーによって異なるため、同じtwitter.comへのアクセスでも異なる内容になります。

静的(static)なサイトとは、動的なサイトの逆で、そのWebサイトのすべてのコンテンツがあらかじめ用意されていて、それらを配信するだけのサイトです。例えばブログやWikiなどのWebサイトを考えると、誰がアクセスしても内容は同じですので静的だと言えます。

Webサイトの内容が静的だと、Webサーバーはコンテンツを生成したりする役割を持たず、あらかじめ用意されたコンテンツを送り返せば良いだけになり、非常に運営のコストが減ります。また、どのアクセスに対しても返す内容が同じでコンテンツをキャッシュできることから、そういった「コンテンツを配信する」用途に特化したサービスであるCDNとの相性が良いです。さらに、サイト内容をGitHubで管理すれば、GitHub Pagesを用いてそのままサイト公開が行えるので、自分でサーバーを用意・管理する必要さえありません。

VuePressとは

VuePressはそういった静的サイトの作成を行うソフトウェア(Static Site Generator, SSG)のひとつです。Webサイトが簡単な内容であればHTMLやCSSを手書きで作ることも可能ですが、規模が大きい場合は手動での管理は困難です。VuePressを使うことで、Markdownの使用、自動目次生成、全文検索、多言語対応、Vueコンポーネントの埋め込みなど複雑なことが簡単に行えるようになります。また、テーマが標準で用意されているのでデザインの手間が省けますし、プラグイン機能もあるため自由に拡張することもできます。

使ってみる

実際にVuePressを使ったサンプルを動かしてみます。前提として、Node.js、npmがインストールされている必要があります。

ディレクトリを作成します。

mkdir my-site
cd my-site

nodeプロジェクトを初期化します。このコマンドを実行した際に出るプロンプトはすべて空欄のままで構いません。

npm init

VuePressをプロジェクトに追加します。

npm install -D vuepress@next

package.jsonのscripts内を以下のように書き換えます。

"dev": "vuepress dev docs",
"build": "vuepress build docs"

ページを作成します。文字化けした場合はファイルの文字エンコードがUTF-8になっているか確認してください。

mkdir docs
echo '# Hello VuePress' > docs/README.md

開発サーバーを起動します。

npm run dev

以上で準備は完了です。開発サーバーが起動したら、ブラウザでhttp://localhost:8080にアクセスすることでサイトの内容が表示されます。問題なく設定できていれば、⁠Hello VuePress」が表示されているはずです。

図2 「Hello VuePress」
図2

この開発サーバーにはHMR(Hot Module Replacement)の機能が備わっているため、ページの内容を変更すると自動でブラウザに反映されます。実際にdocs/README.mdを編集して動作を確かめてみてください。デフォルトでMarkdownが使えます。

なお、サイト全体を静的サイトとしてビルドするには以下を実行します。

npm run build

これにより、docs/.vuepress/dist内にサイトが生成されます。よって、サイトを公開する際はこのディレクトリをまるごとサーバーにアップロードすれば良いわけです。

カスタマイズ

ここまでで作成したサンプルは最小限のものです。実際にはサイト設定、テーマ、プラグインなどのカスタマイズが行えます。

まず設定ファイルを編集し、サイトの設定を変更してみます。docs/.vuepress内にconfig.jsというファイルを作成し、中身を以下のようにしてください。

import { defineUserConfig } from 'vuepress'

export default defineUserConfig({
  lang: 'ja-JP',
  title: 'VuePressのテスト',
})

ファイルが作成できたら開発サーバーを再起動して再度ブラウザで表示してみてください。サイトのタイトルが「VuePressのテスト」に変わっているはずです。このように、サイトの設定はconfig.jsに記述します。設定の詳細については公式ドキュメントを参照してください。

Vueコンポーネントの利用

VuePressの強みは、名前にもあるようにVueのコンポーネントを使った静的サイトを作成できることです。Vueコンポーネントを使用することで、静的サイトでありながらインタラクティブなページが実現できます。実際に試してみましょう。

まず、docs/.vuepress内にcomponentsディレクトリを作り、その中にMyCounter.vueファイルを作成します。ファイルの中身は以下のようにします。

<template>
<div>
	<p class="label">{{ count }}回クリックしました</p>
	<button @click="count++">ここをクリック!</button>
</div>
</template>

<script setup>
import { ref } from 'vue';

const count = ref(0)
</script>

<style lang="scss" scoped>
.label {
	color: red;
}
</style>

Vueコンポーネントの書き方など詳細についてはVue公式ドキュメントを参照してください。

次に、追加の依存関係をプロジェクトにインストールします。

npm i -D @vuepress/plugin-register-components@next

設定ファイルを以下のように変更します。

import { defineUserConfig } from 'vuepress'
import { path } from '@vuepress/utils'
import { registerComponentsPlugin } from '@vuepress/plugin-register-components'

export default defineUserConfig({
  lang: 'ja-JP',
  title: 'VuePressのテスト',
  plugins: [
    registerComponentsPlugin({ componentsDir: path.resolve(__dirname, './components/') }),
  ],
})

最後に、README.mdを以下のように変更します。

# Hello VuePress

<MyCounter/>

これで完了です。開発サーバーを再起動し、ブラウザでアクセスしてみてください。上手くいけば、Vueのコンポーネントがページに埋め込まれているでしょう。

図3 カウンターが設置された
図3

自動デプロイ

冒頭触れましたが、このVuePressプロジェクトをGitHubのリポジトリとして管理を行えばGitHub Pagesを利用してサイトをゼロコストで公開できます。GitHub Pagesの詳細についてはこの記事では省略しますが、GitHub Actionsを使うとコミットを行った際に自動でVuePressのビルドを行い、GitHub Pagesに反映させることが可能です。

以下にActionの例を示します。

name: GitHub Pages

on:
  # trigger deployment on every push to main branch
  push:
    branches:
      - main
  # trigger deployment manually
  workflow_dispatch:

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v2
        with:
          # fetch all commits to get last updated time or other git log info
          fetch-depth: 0

      - name: Setup Node.js
        uses: actions/setup-node@v1
        with:
          node-version: 16

      - name: Cache dependencies
        uses: actions/cache@v2
        with:
          path: ~/.npm
          key: npm-${{ hashFiles('package-lock.json') }}
          restore-keys: npm-

      - name: Install dependencies
        run: npm ci

      - name: Build
        run: npm run build

      - name: Deploy
        uses: peaceiris/actions-gh-pages@v3
        if: ${{ github.ref == 'refs/heads/main' }}
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: ./src/.vuepress/dist
          cname: my-site.example.com

GitHub Pagesでは独自ドメインも使用できます。

Misskey Hubでもこの技術スタック(VuePress + GitHub Pages + GitHub Actions)で管理されています。

まとめ

VuePressを使うことで、簡単にリッチな静的サイトを生成できることを紹介しました。また、リポジトリをGitHubで管理することでゼロコストでサイトを公開できることを紹介しました。

VuePressなどのSSGとGitHub Pagesの組み合わせは、ライブラリの公式ドキュメントやブログなど、幅広い用途で活用できます。ぜひSSGを使ったサイト生成を試してみてください。

おすすめ記事

記事・ニュース一覧