Hexo で markdown-it の renderer をカスタムする


前提と環境

  • markdown-it は、2019年現在最もよく利用されている Markdown パーサーである
    • renderer の設定を変えることでヘッダーやテーブルのレンダリング(どのような DOM を描くか)を変更できる
  • Hexo は、静的サイトジェネレーターである
    • hexo-renderer-markdown-it を使うことで、Markdown のレンダリングに markdown-it を利用することができる

問題

Hexo + markdown-it 環境で、ヘッダーやテーブルのレンダリングを変更する方法がわからない

設定ファイルの変更

  • 以下のように設定ファイルを変更することで、カスタムプラグインを markdown-it にセットできる
  • 仕組みとしては、plugins にリストした文字列が hexo-renderer-markdown-it によって require される
_config.yml
# markdown-it
markdown:
  plugins:
    - '../../../scripts/markdown-it/plugins/custom-header-renderer'   # relative path from 'node_modules/hexo-renderer-markdown-it/lib'
    - '../../../scripts/markdown-it/plugins/custom-table-renderer'    # relative path from 'node_modules/hexo-renderer-markdown-it/lib'

カスタムプラグインの Example

テーブルのレンダリングを変更するカスタムプラグイン

/scripts/markdown-it/plugins/custom-table-renderer.js
/**
 * Reference: https://github.com/medfreeman/markdown-it-toc-and-anchor/blob/708434d7965924e4bf79090b5fd758a2a1cec011/src/index.js#L285-L304
 */
module.exports = function plugin(md) {

  md.renderer.rules.table_open = function(tokens, idx) {
    return '<table class="table table-sm table-bordered">';
  };

}

ヘッダーのレンダリングを変更するカスタムプラグイン

Markdown 内の # ヘッダー を、<h1>ヘッダー</h1> から <h1><span>ヘッダー</span></h1> に変更する

/scripts/markdown-it/plugins/custom-header-renderer.js
/**
 * Reference: https://github.com/medfreeman/markdown-it-toc-and-anchor/blob/708434d7965924e4bf79090b5fd758a2a1cec011/src/index.js#L285-L304
 */
module.exports = function plugin(md) {

  // fetch original rules
  const originalHeadingOpen = md.renderer.rules.heading_open ||
    function(...args) {
      const [ tokens, idx, options, , self ] = args;
      return self.renderToken(tokens, idx, options);
    };
  const originalHeadingClose = md.renderer.rules.heading_close ||
    function(...args) {
      const [ tokens, idx, options, , self ] = args;
      return self.renderToken(tokens, idx, options);
    }

  // override rules
  md.renderer.rules.heading_open = function (...args) {
    const tag = originalHeadingOpen.apply(this, args);
    return `${tag}<span>`;
  }
  md.renderer.rules.heading_close = function (...args) {
    const tag = originalHeadingClose.apply(this, args);
    return `</span>${tag}`;
  }
}