2018-09-05

tobijibu

preタグの中でもPugテンプレートを使って表示する2

前回preタグの中でPug記法を使う方法を紹介しました。

実際に使っていたのですが、少々具合が悪いことに気が付きました。 :pug(pretty=true)フィルタを指定した場合、 ブロック要素は改行されるのですが、インライン要素では改行されません。 また、Pugのpretty=trueのオプションも廃止予定のようです。(すっかり忘れてました。) ですので、今回は別の方法を探してみたいと思います。単に使うfilterを変更するだけです。

モジュールを探して追加

prettyがうまく処理できるようなフィルタを探しました。 :pugでPug→HTMLに変換したあとに、HTMLを整理するフィルタを使えば良さそうです。

探してみたところ、 jstransformer-html-beautifyというモジュールが見つかりました。 早速インストールします。

$ npm install --save-dev jstransformer-html-beautify

試す

以下のPugテンプレートで試します。文章はWikipediaから拝借しました。

div パグについて
  p
    | #[b パグ](Pug)は、犬の種類(犬種)の一つ。短鼻の小型犬。#[br]
    | 短毛でダブルコート、垂れ耳、巻き尾。
    | 毛色はフォーン(サンプル画像の毛色)、#[span.black 黒]、#[span.white 白]、#[span.slver シルバー]など。
    //
      シルバーの毛色は見たことない!
    | 
    | なお、黒以外の毛色の場合は鼻から口の周辺及び耳は黒い。
    | フォーンのパグは背中に沿って黒のトレースがある
    sup [1]
    | 。

まずは前回の方法です。filterには:escape-html:pug(pretty=true)を指定しています。

pre
  code
    :escape-html:pug(pretty=true)
      ...
結果

<div>パグについて</div>
<p><b>パグ</b>(Pug)は、犬の種類(犬種)の一つ。短鼻の小型犬。<br/>
  短毛でダブルコート、垂れ耳、巻き尾。
  毛色はフォーン(サンプル画像の毛色)、<span class="black">黒</span>、<span class="white">白</span>、<span class="slver">シルバー</span>など。
  <!--シルバーの毛色は見たことない!
  --> 
  なお、黒以外の毛色の場合は鼻から口の周辺及び耳は黒い。
  フォーンのパグは背中に沿って黒のトレースがある<sup>[1]</sup>。
</p>

ブロックタグが1行目の場合、不自然な改行が出てしまいます。 また、Pugフィルタにdoctypeを指定していないので、XMLと認識されbrタグに閉じスラッシュが入ってしまいます。


続いて新しい方法です。fitlerには:escape-html:html-beautify(indent-size=2 inline=''):pug(doctype='html')を指定します。

:pugにはdoctype='html'を指定し、:html-beautifyにはindent-size=2inline=''を指定しました。

pre
  code
    :escape-html:html-beautify(indent-size=2 inline=''):pug(doctype='html')
      ...
indent-sizeはその名の通りインデントの幅を指定することができます。今回は2にしました。

inlineは、インライン要素のタグ名を指定します。指定したタグ名がインライン要素のタグとして認識され、それ以外の要素はブロックタグとして認識されます。 今回は何も指定していないので、全てのタグがブロック要素のタグとして認識されるようになります。

ブロック要素タグは、開始タグの直後に別のブロック要素がある場合、改行を入れます。つまり、ブロック要素の開始直後にインライン要素タグがある場合も改行されて表示されます。

結果
<div>パグについて</div>
<p>
  <b>パグ</b>(Pug)は、犬の種類(犬種)の一つ。短鼻の小型犬。
  <br>
  短毛でダブルコート、垂れ耳、巻き尾。
  毛色はフォーン(サンプル画像の毛色)、<span class="black">黒</span>、<span class="white">白</span>、<span class="slver">シルバー</span>など。
  <!--シルバーの毛色は見たことない!-->
  なお、黒以外の毛色の場合は鼻から口の周辺及び耳は黒い。
  フォーンのパグは背中に沿って黒のトレースがある<sup>[1]</sup>。
</p>
<p>
  <sup>a</sup>
</p>

これで前回よりも少し見やすい状態になりました。

mixinを指定したくても...

今回のfilterは少し複雑です。 HTMLを表示するpreタグを使うたびに指定するのは面倒です。 そう思ってmixinを指定しようとしたのですが、どうやらそれは出来ないようです。

mixinにはMixin Blocksという機能があります。 Mixin Blocksはmixinを呼び出す際に、その中に内包するように要素を指定すると、 mixinの中でblockを指定すると、内包した要素を出力することができます。

しかし以下のように指定しても、blockという文字が出力されてしまい、本来出力してほしい内容(block)は出力されません。

mixin html_code
  pre
    code
      :escape-html:html-beautify(indent-size=2 inline=''):pug(doctype='html')
         block
  
+html_code
  ...

上記以外にもいろいろと試行錯誤したのですが、mixinblockにフィルタを適用することはできませんでした。 仕方ないので都度フィルタを指定する方法を取ることにしています。

おまけ

pre > codeで表示するならhighlight.jsおすすめですが、 filterとしてhighlightjsと同じように動作するjstransformer-highlightもあります。

highlightフィルタを使うと、ソースコードをあらかじめハイライトした状態のHTMLを生成します。 キーワードが色付きのspanタグで囲われて、エスケープ済みの状態で生成されます。

つまり、ブラウザでhighlight.jsを実行する必要が無くなるので、コンテンツの軽量化も見込めます。

導入も簡単で、npmjstransformer-highlightをインストールして、 :escape-htmlの代わりに:highlightを指定するだけです。

$ npm install --save-dev jstransformer-highlight
pre
  code
    :highlight(lang='html'):html-beautify(indent-size=2 inline=''):pug(doctype='html')
      ...