VitePress の概要とソースコードの概観
VitePress の概要とソースコードの外観を見て行きます。
長い前置き
VitePress と言うのが出ました。
◯ VuePress ってなんだ?
VitePress は、平たくいうと VuePress の高速版です。用途は VuePress と代わりないので、そもそも VuePress がなんぞや?という方は以下の記事で概要を掴んでおくと良いかもしれません。
◯ 静的サイトジェネレータってなんだ?
あとは個人ブログ的な用途については WordPress が独占的な地位であり続けると個人的には思ってるのですが、こちらの動画も、たいへん勉強になりました。VitePress は静的サイトジェネレータというアプリケーションに分類されますが、この動画は、その静的サイトジェネレータとはなんぞや、みたいなことを説明してくれています。
以下は、Vue.js に限定されない静的サイトジェネレータの比較サイトです。GitHub のスター順に並べてくれています。一覧になっているので、雰囲気が掴みやすいかなと思いました。
Vue.js に限定していうと VuePress 以外に Nuxt の @nuxt/content, Gridsome といった静的サイトジェネレータがあります。以下の動画は、その3つを比較してくれています。
◯ なんで VitePress なんて作ったんだ?
- webpack による bundle が重たい。
- webpack を Vite で置きかえよう。
VuePress は大好きなのですが、webpack 上に構築されているため、数ページのシンプルなドキュメントサイトの開発サーバを立ち上げるのにかかる時間に耐えられなくなってきています。HMRのアップデートを使ってさえ、ブラウザに反映されるまでに数秒かかることがあります。 I love VuePress, but being built on top of webpack, the time it takes to spin up the dev server for a simple doc site with a few pages is just becoming unbearable. Even HMR updates can take up to seconds to reflect in the browser! Motivation - vuejs/vitepress
以下の動画では、Evan You 氏による VitePress の説明がなされています。
◯ Vite ってなんだ?
高速な webpack のようなものらしいです。
◯ HeadlessCMS と Jamstack
直接、静的サイトジェネレータ SSG と関係があるわけではないのですが、HeadlessCMS と Jamstack の2単語は押さえておいても良いのかなと思いました。以下は、HeadlessCMS について説明していただいている動画になります。
以下は、JAMstack について説明していただいている記事になります。
以下の記事は WordPress に比して、なかなかクリティカルなメリットが見出しにくい、ということが書かれていてたいへん参考になりました。
そんで、僕らSPAエンジニアとしてはもちろんJAMstackを普及させていきたいわけですが、そんなのエンジニアの都合だけであってメディア管理者のメリットがあんまりないからはっきり言って微妙という話はしました。
僕もHeadless CMSってものを初めて聞いた時、 その嬉しさが当時はピンとこなかったんだよな https://twitter.com/Keisuke69/status/1272168063127810048
JAMstackの話。そこに向かうモチベーションとか一般的な話も含めてTinaCMSの人がゲストで。 WordPressのことをMonolithicCMSと言っててなるほど。 CMS部分とフロントエンドを切り離せるのが最大の売りだと思うので ただのブログ作るにはやはりオーバーエンジニアリングなんだろな https://twitter.com/Keisuke69/status/1272166570156949511
VitePress のシステム構成概観
普通の Vue のインスタンスにマークダウンファイルを埋め込むようなことをしています。router.go
で取得されたマークダウンファイルは Single File Compoent に変換されて <Content />
というタグに割り当てられ、内部で使用されます。
上記の図の関係は /src/client/app/index.ts
を見ると雰囲気が伝わります。
export function createApp() {
// ... 中略
// 1. テーマは、Single File Component で createApp によって埋め込まれます。
const app =
process.env.NODE_ENV === 'production'
? createSSRApp(Theme.Layout)
: createClientApp(Theme.Layout)
// 2. ルータは、リアクティブなデータ provide によって埋め込まれます。
app.provide(RouterSymbol, router)
app.provide(pageDataSymbol, pageDataRef)
// 3. Markdown ファイルは、component によって埋め込まれます。
app.component('Content', Content)
// ... 中略
return { app, router }
}
◯ VitePress は何をしているの?
主に以下2つのことをしています。
- /index.md, /hello.md, /nihao.md のパスを解決しています。
- マークダウンファイルを Vue.js の Single File Compoent に変換しています。
補足すると、docs ディレクトリ配下にマークダウンファイルがあった場合、VitePress は /index.md へのリクエストを /docs/index.md に、/hello.md へのリクエストを /docs/hello.md に変換してくれます。そして、次にアクセスされた /docs/hello.md を Single File Component に変換して、返しているという訳です。
◯ アクセスなんかしないけど?
/index.md, /hello.md なんかにアクセスなんかしないけど、どういうことでしょうか?
dev の場合、例えば /docs/hello.md にファイルを置いた場合、ブラウザでは /hello にアクセスすると思います。/hello.md にはアクセスしていないように見えます。しかし、内部では dev サーバから各コンポーネントを個別に HTTP リクエストして取得しています。これはデベロッパツールの network タブを開いて見るとわかりやすいかもしれません。デモの動画を作りました。
build の場合は、確認中です。
VitePress のディレクトリ構成概観
GitHub のリポジトリ配下にあるファイルは、エントリーポイント、サーバ、クライアントの3つに大きく分類できます。番号は、次節の目次に対応しています。
2 2.1, 2.2 5
bin/vitepress.js --> src/node --> src/client/app --> src/client/theme-default
エントリーポイント | サーバ | クライアント
◯ 目次
どことどこが繋がっているか、つなぎこまれているかを中心に見て行きます。
- VitePress のディレクトリ構成
- src/client/app と src/client/theme-default のつなぎ込み
- Markdown ファイルと src/client/app, Vue インスタンス本体のつなぎ込み
- Vite と VitePress のつなぎ込み
- dev 編
- build 編(未着手)
◯ 補足
また WIP, Work In Progress で頻繁に変更されているため、引用しているコードごとにバージョンが、異なります。同一記事内では、なるべく同じバージョンになるようにしています。
4 がメインで結論部分なので読める方は 4 から読んでいただいた方が速いと思います。しかし 4 が一番重たいです。1, 2, 3, 4 で周りから崩した方が、理解しやすいかなと思いました。
項番 3 の記事のタイトルは、「VitePress のルータの実装」になります。Markdown ファイルと app, Vue インスタンス本体のつなぎ込みも、どうやってやっているんだろう?と思ったのですが、router.go
でつなぎ込んでいます。詳細は、項番 3 のリンク先をご確認ください。
項番 4 では、Markdown ファイルから Vue コンポーネントへの変換を確認しています。
node ディレクトリの中の内容と client の中の内容、サーバとクライアントのつなぎ込みって、どうやっているんだろう?と思ったのですが、冷静に考えて HTTP 通信をさせているだけでした。
参考
console.dir, console.log で変数などを表示してみたい時は、CONTRIBUTING.md に記載された方法で起動するとやりやすいです。