VuePress をお試ししてみた

## VuePress とは

![image.png](https://qiita-image-store.s3.amazonaws.com/0/35603/ded6e8c6-2e1b-51ab-02ac-8e5368fcede7.png)

> この記事は 2018-04-15 に記載されたものです。

[VuePress](https://vuepress.vuejs.org/) は Vue の始祖こと [Evan You](http://evanyou.me/) 氏が新たに始めた Vue による静的サイトジェネレーターです。
Markdown によるページの作成が可能で、Vue の機能はもちろん、Webサイトを作っていてほしくなるシンタックスハイライトや、PWAのサポートがされています。
雑な解釈としては Vue 版の Gatsby という認識で良いのではないのかと思います。

### VuePress の機能

公式に記載されている内容を抜粋して雑に翻訳してみました。

ref: [VuePress | Introduction](https://vuepress.vuejs.org/guide/#features)

- 技術文書に最適化されたビルトインのMarkdown拡張
- Markdown 内部での Vue 活用
- Vue により強化されたカスタムテーマシステム
- Progressive Web Application (PWA) のサポート
- Google Analytics の統合
- デフォルトテーマの機能:
  - レスポンシブレイアウト
  - オプショナルなホームページ
  - シンプルで確信的なヘッダー検索
  - ナビバーとサイドバーのカスタマイズ
  - 自動での Github へのリンク、および編集リンクの設置

### Nuxt.js との違い

「Vue の静的サイトジェネレータなら Nuxt.js があるじゃん！」という感じの方もいると思うので言及しておきます。
自分自身なんでNuxt.js があるのにわざわざ？と思ったものですがそこについては VuePress の公式サイトの 「Why Not?」 のページに記載されていましたので抜粋します。

> Nuxt is capable of doing what VuePress does, but it is designed for building applications. VuePress is focused on content-centric static sites and provides features tailored for technical documentation out of the box.
>
> (Nuxt は VuePress の機能を満たしていますが、Nuxt はアプリケーションを作成することを主軸にデザインされているところが異なります。VuePressは、コンテンツを主軸に置いた静的サイトの作成にフォーカスし、技術文書の作成にぴったりの革新的な機能を提供します。)

Nuxt.js 自体は Vue を使ったアプリケーションの作成に特化しており、VueRouterとの統合やモジュールを併用しての PWAの 対応など VuePress の実現しようとしている世界を一部含んでいますが、そこに加えて VuePress は Markdown のサポートやデフォルトのテーマリングなどが統合されており、文書を提供する基盤として特化しているということなのではないかと言う理解です。

逆に、汎用的なアプリケーションの開発には現時点では向かないと思うのでやはり使い所の話になってきそうです。例えばアプリ本体は Nuxt.js で作って、内部やAPIドキュメントは VuePress で生成するなどかなというように思いました。


### というわけで...

先日まで Gatsby を使用していたのですが、さっくり移行してみました。
Markdown で記事を書いているとこういうふうにエンジンをパカパカ切り替えれて便利ですね。

デフォルトでは Vueの公式サイトみたいなデザインが割り当てられます。
2018-04-15 現在、ブログ用途の機能はまだ実装されていませんが、予定にははいっているそうです。

なお予定されている機能についてはこちら。

ref: [VuePress | Introduction](https://vuepress.vuejs.org/guide/#todo-features)

- ナビバー内部のドロップダウンメニュー
- 多言語サポート
- Algolia DocSearch の組み込み
- ブログ機能のサポート

まだ公式にはブログ機能はサポートされていないのですが、とりあえず行けるところまで行って見ようと思います。

## 実施した設定

VuePress の設定は `.vuepress/config.js` に記載します。下記のページに書いてあることが基本的に全てです。
- [VuePress | Configuration](https://vuepress.vuejs.org/guide/basic-config.html) 

### ディレクトリ構成

ざっくりとこんな感じになります。

```bash
- /
  - .vuepress/     #-> VuePress関連のファイルを格納するディレクトリ
    - public/      #-> 静的ファイルを格納するディレクトリ
    - components/  #-> 使用するコンポーネントを格納するディレクトリ
    - dist/        #-> ビルド済みコンテンツを格納するディレクトリ
    - config.js    #-> 設定ファイル 
  - README.md      #-> ページとなる Markdown ファイル
  - ...
```

特筆としては `.vuepress/public` ディレクトリに配置したファイルはビルド時にそのままコピーされるということと、VuePress でビルドしたコンテンツは `.vuepress/dist` に出力されることです。  
ビルド済みのコンテンツの出力先については、設定ファイルから変更することができます。

### favicon の設定

favicon を始めとした head タグへの差し込みが必要なものについては基本的に `.vuepress/config.js` に記載するようです。`nuxt.config.js` と同じですね。
VuePressから静的に配信して欲しいファイルは `.vuepress/public` に配置すれば良いようです。ビルド時に出力用のディレクトリにそのままコピーされます。

```js
{
  head: [
    ['link', { rel: 'icon', type: 'image/png', href: '/favicon.png' }],
  ],
}
```

### Service Worker

Service Worker についてはデフォルトでは無効にされています。
なので、有効にするには下記を参考に同じく `.vuepress/config.js` に記載する必要があります。

ref: [VuePress | Config Reference](https://vuepress.vuejs.org/config/#serviceworker)

```js
{
  base: '/',
  serviceWorker: true,
}
```

なおこの機能を有効化した場合は PWA のアプリアイコンとなる画像ファイルを `.vuepress/public` に配置しておく必要があります。
またこれもマニュアルに書いていますが production環境でないと Service Worker は有効になりません。
ビルドするときには `NODE_ENV=production` をあわせて設定してあげましょう。

ちなみに ServiceWorker こそ有効になりますが、manifest.json が生成されませんでした。まだ実装中なのかな？
なので最低限の定義を書いて meta タグを差し込んで対応しました。

定義はこんな感じ。

```json
{
  "short_name": "untitled",
  "name": "untitled",
  "icons": [
    {
      "src": "favicon.png",
      "type": "image/png",
      "sizes": "256x256"
    }
  ],
  "theme_color": "#263238",
  "background_color": "#ffffff",
  "display": "standalone",
  "start_url": "/?pwa=true"
}
```

`.vuepress/config.js` にはこんな感じで記載してあげましょう。

```js
module.exports = {
  head: [
    ['link', { rel: 'manifest', href: '/manifest.json' }],
  ],
}
```

これでアプリケーションとしてインストールできるようになります。
(ただの雑記なんだからインストールするメリットはまったくないのですが)

### 色変更 (テーマリング)

デフォルトだと Vue風なカラーリングになりますが、Stylus でのテーマリングに対応しています。 `.vuepress/override.styl` を用意して変更したい値を定義するだけで読み込んでくれる仕組みです。ひとまず `accentColor` だけデフォルトから変えて適用しています。

ref: [VuePress | Default Theme Config](https://vuepress.vuejs.org/default-theme-config/#simple-css-override)

```stylus
$accentColor = #1976D2
$textColor = #2c3e50
$borderColor = #eaecef
$codeBgColor = #282c34
```

### 自動リンクの設定

後述しますが VuePress は markdown-it が統合されています。そのため markdown-it でできることは大抵できるように設計されているようです。
デフォルトではURLが自動でリンクにならないよう markdown-it の linkify が false にされているのですが、自動でリンクしてほしかったので下記のように設定を追加しました。

```js
{
  markdown: {
    config: (md) => {
      md.options.linkify = true
    },
  },
}
```

## Vue コンポーネントの設置

VuePressではMarkdownの文中で Vue のコンポーネントを試用することができます。使うには `.vuepress/components/` 配下に `*.vue` ファイルを配置して、置きたいところに同名のタグを設定すれば良いようです。

ブログパーツをサクッと Vue でつくって画面に配置したりできるとかっこいいですね。
というわけで置いてみました。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/35603/e795e8c7-263b-4508-5e90-3f644e4d76d5.png)

スクリプト本体はこんな感じで書いています。
何も考えずに cssModules 使ってみたのですが普通に行けましたね。すごい。

```vue
<template>
  <button @click.prevent="onClick" :class="$style.button"><slot /></button>
</template>

<script>
module.exports = {
  methods: {
    onClick() {
      alert('Hello World!')
    },
  },
}
</script>

<style module>
.btn {
  background-color: #1976D2;
  border-radius: 5px;
  border: none;
  color: #ffffff;
  font-size: 2rem;
  font-weight: bold;
  padding: 1rem;
  transition: opacity .1s linear;
}
.btn:hover {
  opacity: .8;
}
</style>
```

## そのほか便利な機能

ref: [VuePress | Markdown Extensions](https://vuepress.vuejs.org/guide/markdown.html)

markdown-it の拡張が組み込まれているので Github みたいな書き方をするといい感じに絵文字をパースしてくれたり表を作ってくれるのはもちろん、それに加えていくつか便利な機能があるのでご紹介しておきます。


### 見出し一覧 (TOC)

```md
[[toc]]
```

と記載するとその場所に見出し一覧が展開されます。しかしながら、現時点ではアルファベットのみ対応のようでした。残念。Github で Issue が上がっていました。

ref: https://github.com/vuejs/vuepress/issues/45

ちなみに現在のバージョン 0.3.1 では `##` で見出しをつけると `vuepress build` がうまく動かない不具合があるようですが、次のリリースで修正されるそうです。

ref: https://github.com/vuejs/vuepress/issues/42

### 行のハイライト付きシンタックスハイライト

<pre><code>```typescript{6}
import Vue from 'vue'
import Component from 'vue-class-component'

@Component({})
export default class extends Vue {
  private highlight: booelan = true
}
```</code></pre>

と記載すると該当行がハイライトされます

![image.png](https://qiita-image-store.s3.amazonaws.com/0/35603/b6fa69f7-39b8-8b7e-f408-1b90e41ce5de.png)


### カスタムコンテナ

```md
::: tip
これはチップです。
:::

::: warning
これは警告です。
:::

::: danger 注意するべき点
これは危険な警告です。
:::
```

と記載すると

![image.png](https://qiita-image-store.s3.amazonaws.com/0/35603/92a9e743-8ce3-7eb8-d29f-0eddac83acc2.png)

こうなります。文書中で注釈を入れたいシーンで活躍しそうですね。
色の指定のあとにスペースで注釈の見出しを入れることができるようです。

### Markdown のさらなる拡張

VuePress は markdown-it を使用しているので markdown-it のプラグインを追加して使うことができます。
これも `.vuepress/config.js` に記載することで設定可能です。

ref: [VuePress | Markdown Extensions](https://vuepress.vuejs.org/guide/markdown.html#advanced-configuration)

## 現時点で足りない機能はどうする？

### Feed

ブログ機能が無いので Feed も当然ありません。ブログという形ならばせめて Feed はほしいとおもったので、
本文となるMarkdown を別途 processmd に掛けたあと成果物を利用した雑スクリプトでひとまず生成することにしました。

### Sitemap

ひとまずトップページに全ページのリンクを貼って、クローラに頑張ってもらうこととしました。
手が空いたら Feed と同じく対応がさなれるまで雑に generate しようかなと言う気持ちでいます。

## まとめ

今回は VuePress をお試ししてみました。いまはブログ機能がまだ用意されていないのですが、割と素直に動いてくれてなかなか便利に使えています。VueJS公式のプロジェクトの1つでもあるので継続的なプロジェクトになりそうだという点も期待できるのではないでしょうか。
直近ではなにかのライブラリを作った時にマニュアルを Markdown で用意しておいて、ブラウザから見るとき向けに VuePress でビルドして公開しておくとかなどの用途においてはすぐに使えて便利なのではないかなと思いました。ブログ機能など今後のリリースが楽しみですね。

> from: [Scrapbox](https://scrapbox.io/dojineko/VuePress_%E3%82%92%E3%81%8A%E8%A9%A6%E3%81%97%E3%81%97%E3%81%A6%E3%81%BF%E3%81%9F)