【Angular】Marked + Highlight.js でMarkdownをHTMLに変換して表示する

 今回はMarkdownをHTMLに変換して表示する方法を紹介します。

 完成しているコードは下記になります。

Angular-sample/markdown at main · tsuneken5/Angular-sample
Contribute to tsuneken5/Angular-sample development by creating an account on GitHub.

環境

  • node: 18.20.0
  • Angular CLI:17.0.0
  • Marked:14.1.3
  • Highlight.js:11.10.0
  • marked-highlight:2.2.0

プロジェクトの作成

$ ng new markdown

パッケージのインストール

$ npm install marked

 MarkdownからHTMLの変換には Marked を使用します。

GitHub - markedjs/marked: A markdown parser and compiler. Built for speed.
A markdown parser and compiler. Built for speed. Contribute to markedjs/marked development by creating an account on Git...

 あとは必要に応じて Angular Material などをインストールしてください。

コンポーネントの作成

$ ng generate component component/page/marked
import { Component } from '@angular/core';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';

import { InputComponent } from '../../share/input/input.component';
import { OutputComponent } from '../../share/output/output.component';

import { marked } from 'marked';

@Component({
  selector: 'app-marked',
  standalone: true,
  imports: [InputComponent, OutputComponent],
  templateUrl: './marked.component.html',
  styleUrl: './marked.component.css'
})
export class MarkedComponent {
  public safeHTML!: SafeHtml;

  constructor(
    private sanitizer: DomSanitizer
  ) { }

  public async onParse(message: any) {
    const content = await marked.parse(message);
    this.safeHTML = this.sanitizer.bypassSecurityTrustHtml(content);
  }
}

 入力用のコンポーネントや出力用のコンポーネントのインポートなどをしていますが、 Markdown の出力で重要なのは下記だけです。

7行目

 Marked をインポートします。

24行目

 marked.parse() を使用して Markdown を HTML に変換します。 

25行目

 ここはMarkdonwの変換には関係ないですが、 <mat-card-content [innerHTML]="safeHtml"> で出力しているので、 XSS 対策で SafeHTML に変換しています。

確認

$ ng serve

 ブラウザで「http://localhost:4200/」にアクセスすると確認できます。下記のように Markdown 形式で入力するとHTMLに変換されて表示されます。

# Ruby
``` ruby
puts 'Hello world'
```
# Python
``` python
print('Hello world')
```
# empty
```
print('Hello world')
```

シンタックスハイライト

 このままだとコード部分が味気ないのでシンタックスハイライト(コードを色分け表示)していきます。シンタックスハイライトには Highlight.js と marked-highlight を使用します。

 Highlight.js がコードにシンタックスハイライトをしてくれるライブラリで、marked-highlight が Highlight.js を Marked で簡単に使えるようにするライブラリとなります。

GitHub - highlightjs/highlight.js: JavaScript syntax highlighter with language auto-detection and zero dependencies.
JavaScript syntax highlighter with language auto-detection and zero dependencies. - highlightjs/highlight.js
GitHub - markedjs/marked-highlight: Add code highlighting to marked
Add code highlighting to marked. Contribute to markedjs/marked-highlight development by creating an account on GitHub.

パッケージのインストール

$ npm install highlight.js marked-highlight

スタイルシートのインポート

@import 'highlight.js/styles/atom-one-dark.min.css';

html,
body {
  height: 100%;
}

body {
  margin: 0;
  font-family: Roboto, "Helvetica Neue", sans-serif;
}

 style.css に Highlight.js の css をインポートします。css が読み込めればどこで読み込んでも大丈夫です。スタイルは色々な種類があるので自分の好みのものを設定しましょう。

コンポーネントの作成

$ ng generate component component/page/highlight
import { Component } from '@angular/core';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';

import { InputComponent } from '../../share/input/input.component';
import { OutputComponent } from '../../share/output/output.component';

import { Marked } from 'marked';
import { markedHighlight } from 'marked-highlight';
import hljs from 'highlight.js';

@Component({
  selector: 'app-highlight',
  standalone: true,
  imports: [InputComponent, OutputComponent],
  templateUrl: './highlight.component.html',
  styleUrl: './highlight.component.css'
})
export class HighlightComponent {
  public safeHTML!: SafeHtml;
  private marked: Marked;

  constructor(
    private sanitizer: DomSanitizer
  ) {
    this.marked = new Marked(
      markedHighlight({
        emptyLangClass: 'hljs',
        langPrefix: 'hljs language-',
        highlight(code, lang, info) {
          const language = hljs.getLanguage(lang) ? lang : 'plaintext';
          return hljs.highlight(code, { language }).value;
        }
      })
    );
  }

  public async onParse(message: any) {
    const content = await this.marked.parse(message);
    this.safeHTML = this.sanitizer.bypassSecurityTrustHtml(content);
  }
}

 Marked を使用したコンポーネントを使いまわしてもいいんですが、今回は比較用に別コンポーネントを作成します。

 TypeScriptではコンストラクターで Marked と Highlight.js を使えるように定義しています。

確認

$ ng serve

 ブラウザで「http://localhost:4200/」にアクセスすると確認できます。下記のように Markdown 形式で入力するとHTMLに変換され、コードが色分けされて表示されます。

# Ruby
``` ruby
puts 'Hello world'
```
# Python
``` python
print('Hello world')
```
# empty
```
print('Hello world')
```

コメント

タイトルとURLをコピーしました