【フロントエンド学習記録】マークダウン形式でブログを投稿できるようにする

前回はブログに複数枚の画像を添付する実装を見ていきました。

今回は画像をブログ本文の任意の場所に挿入できるようにする前準備としてマークダウンで記事を書けるようにしていく実装を見ていきます。

マークダウン形式で記事を書けるようにするには、現段階では投稿フォーム側で特に実装を変更する箇所はありません。対応が必要なのはブログ本文を描画する側の実装です。

maimux2x.hatenablog.com

実装にあたり Marked というライブラリを使いました。

github.com

Marked を利用することでマークダウン形式のテキストを HTML に変換することができます。 利用する上では README にも記載がある通り、Marked のみでは HTML をサニタイズすることができないため、別のライブラリと併用する必要があります。

github.com

今回はMarked の README に記載されていた sanitize-html を使ってみました。

これらを利用して本文を引数に取り HTML への変換とサニタイズ、HTML としてレンダリングするためのアクションを用意します。

// web/app/components/post.js

import Component from '@glimmer/component';
import { action } from '@ember/object';
import { marked } from 'marked';
import { htmlSafe } from '@ember/template';
import sanitizeHtml from 'sanitize-html';

export default class PostComponent extends Component {
  @action
  renderMarkdown(body) {
    return htmlSafe(sanitizeHtml(marked.parse(body)));
  }
}

Marked と sanitize-html を使ってブログ本文をマークダウンから HTML へ変換し、サニタイズしている部分が sanitizeHtml(marked.parse(body) です。そして、変換された HTML を Ember.js へ HTML としてレンダリングすることを伝えるための関数が htmlSafe() の部分です。

このアクションを以下のように使用することで、マークダウン形式で保存されているブログ本文が適切に変換された結果として描画することができます。

<!-- web/app/components/post.hbs -->

<div class="card mb-3">
  <div class="card-body">
    <h2 class="card-title">
      {{#if @link}}
        <LinkTo @route="posts.show" @model={{@post.id}}>{{@post.title}}</LinkTo>
      {{else}}
        {{@post.title}}
      {{/if}}
    </h2>
    <div class="card-text">{{this.renderMarkdown @post.body}}</div> <!-- @post.body をアクションに渡す -->
    {{#each @post.image_urls as |url|}}
      <img src={{url}} alt="" class="img-fluid">
    {{/each}}
  </div>
</div>

これで実装完了です!

まとめ

最低限のマークダウンでブログ本文を書くようなユースケースであれば、ライブラリのおかげでスムーズに対応できることが分かりました。

投稿フォーム側でできることを増やしていこうとすると、実装上色々考えないといけない部分が出てきそうです。次はその事例の一つとして画像をマークダウン本文内の任意の位置に挿入できるようにする部分の実装を見ていきたいと思います!