VuePressでプラグインを作ってみた

当サイトではVuePressのサブディレクトリ以下をブログとして扱っている。少し前まではブログ構築に@vuepress/plugin-blogを使っていたが、もっと簡単な機能でいいことと、VuePressの勉強もしたいと思っていたので自分で作ってみた。

VuePress公式サイトのPluginを参考にした。

作りたいもの

ブログといっても、以下のように必要な機能は少ない。

  • ページのURLに日付を入れる
  • サイドバーに年ごとにグルーピングした記事一覧を表示

VuePress内の全ての記事をブログ化するのではなく、特定のディレクトリ内だけに適用させたい。

Pluginの基本

.vuepress内にscript/MyBlogPlugin.jsを作る。

module.exports = (options, ctx) => {
  return {
    name: 'myblog-plugin', //プラグインの名前

    //TODO: ここにいろいろAPIを追加していく
  }
}

プラグインを読み込ませるためにconfig.jsのpluginsに読み込み処理を追加



 



module.exports = {
  plugins: [
      require('./script/MyBlogPlugin.js'), //この行を追加。作成するプラグインを読み込む
  ]
}

ページのURLに日付を入れる

ページのURLを変えるには、通常はマークダウンのfrontmatterにpermalinkを指定する。これをプラグインでできればうまくいくはず。つまり、プラグイン側で各ページのfrontmatterにアクセスする方法が分かればよい。

ページのデータを拡張するにはextendPageDataを使用する。

この関数をMyBlogPluginに追加する。


 




 
 
 
 
 
 
 
 
 
 
 
 
 



module.exports = (options, ctx) => {
  const blogHome = '/_blog/'

  return {
    name: 'myblog-plugin', //プラグインの名前

    //ページオブジェクト拡張用API
    extendPageData ($page) {
      //_blogディレクトリ以下をブログとする
      if($page.regularPath.startsWith(blogHome)){
        if($page.regularPath === 'blogHome'){
          //ブログトップページのURLには日付は入れない
          $page.frontmatter.permalink = '/blog/'
        }else{
          //各記事のURLは/blog/2019/07/14/xxxxのようになる
          $page.frontmatter.permalink = '/blog/:year/:month/:day/:slug'
        }
      }
    },
  }
}

extendPageDataは全ての記事分呼ばれるのでブログ化処理は特定のディレクトリ内の記事のみに適用させている。$pageオブジェクトを使って各ページのデータを変更することができる。今回の場合は、frontmatterのpermalinkを変更している。

サイドバーに年ごとにグルーピングした記事一覧を表示

サイドバーは通常はconfig.jsのthemeConfigから設定できる。そこにスクリプトを書いてもいいのだが、ブログ関連の処理がちらばるのが嫌なのでプラグイン内でサイドバーをいじりたい。extendPageDataは各ページ毎に呼ばれるので、その後に一度呼ばれるようなAPIがほしい。そこでreadyを使う



 













 
 
 
 



 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 



module.exports = (options, ctx) => {
  const blogHome = '/_blog/'
  const sidebarPages = [] //サイドバーに表示するページ

  return {
    name: 'myblog-plugin', //プラグインの名前

    //ページオブジェクト拡張用API
    extendPageData ($page) {
      if($page.regularPath.startsWith(blogHome)){
        if($page.regularPath === 'blogHome'){
          $page.frontmatter.permalink = '/blog/'
        }else{
          $page.frontmatter.permalink = '/blog/:year/:month/:day/:slug'
        }

        //サイドバーをありに設定
        $page.frontmatter.sidebar = true
        //ブログ対象記事のpageオブジェクトを持っておく
        sidebarPages.push($page)
      }
    },

    //初期化後に呼ばれる。(extendPageDataより後に呼ばれる。)
    async ready() {
      const sidebar = []

      //ホーム以外の記事を日付の降順に取得し、サイドバーに年毎にグループ分けして表示
      sidebarPages
        .filter($page => $page.regularPath !== blogHome)
        .sort(($pageA, $pageB) => $pageB.frontmatter.date - $pageA.frontmatter.date)
        .forEach($page => {
          const yyyy = $page.frontmatter.date.getFullYear()
          let group = sidebar.find(v => v.title === `${yyyy}`);
          if(!group){
            group = {
              title: `${yyyy}`,
              collapsable: true,
              sidebarDepth: 0,
              children: [],
            }
            sidebar.push(group)
          }
          group.children.push($page.regularPath)
        })

      //ctx.siteConfigでconfig.jsの設定へアクセスできる
      ctx.siteConfig.themeConfig.sidebar[blogHome] = sidebar
    },
  }
}

ready内では、config.jsのthemeConfig.sidebarに以下のような設定を作るのと同じことをやっている。

sidebar: {
  '/_blog/': [
    {
      title: '2019年',
      collapsable: true, //開閉可能
      sidebarDepth: 0, //通常は各ページ内のヘッダー要素へのリンクも作られるが、不要なので消す
      children: [
        '2019年の記事1のパス',
        '2019年の記事2のパス',
      ]
    },
    {
      title: '2018年',
      collapsable: true,
      sidebarDepth: 0,
      children: [
        '2018年の記事1のパス',
        '2018年の記事2のパス',
      ]
    },
    //以下省略
  ]
}

これでこのページのようなブログっぽいものが出来上がり。プラグインを作ればいろいろできそうなのでもっと試したい。

Last Updated: 2019-8-4 19:39:10