【Angular】Marked + Highlight.js + KaTeX + Mermaid を同時に使用する

 前回までの3記事の総まとめです。

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

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-katex-extension:5.1.2
  • Mermaid:11.3.0

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

$ npm install marked highlight.js marked-katex-extension mermaid

 今回は Mermaid との兼ね合いで自分で Highlight.js を使用するための設定を自分で設定する必要があるため、 marked-highlight は使いません。

/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
  "compileOnSave": false,
  "compilerOptions": {
    "outDir": "./dist/out-tsc",
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "noImplicitOverride": true,
    "noPropertyAccessFromIndexSignature": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "esModuleInterop": true,
    "sourceMap": true,
    "declaration": false,
    "downlevelIteration": true,
    "experimentalDecorators": true,
    "moduleResolution": "node",
    "importHelpers": true,
    "target": "ES2022",
    "module": "ES2022",
    "useDefineForClassFields": false,
    "skipLibCheck": true,
    "lib": [
      "ES2022",
      "dom"
    ]
  },
  "angularCompilerOptions": {
    "enableI18nLegacyMessageIdFormat": false,
    "strictInjectionParameters": true,
    "strictInputAccessModifiers": true,
    "strictTemplates": true
  }
}

 "skipLibCheck": true を設定します。

コンポーネントの生成

$ ng generate component component/page/markdown
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, Renderer, Tokens } from 'marked';
import hljs from 'highlight.js';
import markedKatex from "marked-katex-extension";
import mermaid from 'mermaid';

@Component({
  selector: 'app-markdown',
  standalone: true,
  imports: [InputComponent, OutputComponent],
  templateUrl: './markdown.component.html',
  styleUrl: './markdown.component.css'
})
export class MarkdownComponent {
  public safeHTML!: SafeHtml;
  private readonly KATEX_OPTIONS = {
    throwOnError: false
  };

  constructor(
    private sanitizer: DomSanitizer
  ) {
    mermaid.initialize({ startOnLoad: false });
    this.setupMarked();
  }

  private setupMarked() {
    const renderer: Renderer = new marked.Renderer();

    renderer.code = function ({ text, lang, escaped }: Tokens.Code): string {
      if (lang === 'mermaid') {
        return `<div class="mermaid">${text}</div>`;
      }

      const language = lang || 'plaintext';
      if (language == 'plaintext') {
        return `<pre><code class="hljs">${marked.parseInline(text)}</code></pre>`;
      } else {
        return `<pre><code class="hljs language-${language}">${hljs.highlight(text, { language }).value}</code></pre>`;
      }
    };
    marked.use({ renderer });
    marked.use(markedKatex(this.KATEX_OPTIONS))
  }

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

    setTimeout(async () => {
      await mermaid.run({
        querySelector: '.mermaid',
      });
    }, 0);
  }
}

33~50行目

 Mermaid と Highlight.js を同時に使うための Render を設定しています。コードブロックで mermaid が指定されていたら図式できるように <div class="mermaid></div> 要素を返し、それ以外が指定された場合は Highlight.js の機能を使ってシンタックスハイライトで色分けされるように <pre><code class="hljs"></code></pre> 要素を返すようにします。

確認

 上記で設定したように、Mermaid もコードブロックで入力します。

# Python
``` python
print('Hello world')
```

# KaTeX
This is inline katex: $c = \pm\sqrt{a^2 + b^2}$

# Mermaid
``` mermaid
graph LR
      A["$$x^2$$"] -->|"$$\sqrt{x+3}$$"| B("$$\frac{1}{2}$$")
```

コメント

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