MathJax v3.x メモ-1 MathJaxの導入

現在の最新版は8/25リリースの`v3.1`らしい[ぞ](https://www.mathjax.org/MathJax-v3-1-0-available/)！
##### MathJax公式ドキュメント
何かあったら[こ↑こ↓](https://docs.mathjax.org/en/latest/index.html)を読んでくれよな〜頼むよ〜
##### 注意
ちょっと頑張って和訳したり実験したりしているだけです，あんまり本気でアテにするなよ…？


### 前提
（特には）ないです．




# MathJaxの導入



## 最も基本の型
[こ↑こ↓](https://docs.mathjax.org/en/latest/web/start.html)にある通りだと

```html
<script type="text/javascript" id="MathJax-script" async
  src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js">
</script>
```

を`<head></head>`にぶち込めばおk．
ちなこの`cdn.jsdelivr`はこのままだと強制的に最新版を読み込ませてくるので，それが嫌なら

```html
<script id="MathJax-script" async
  src="https://cdn.jsdelivr.net/npm/mathjax@3.x.y/es5/tex-mml-chtml.js">
</script>
```
のように，指定したいバージョンを`@3.x.y`みたいにフル記述してやればおk．
これでもうバージョン管理は…完璧やな！


### 概念として
「html本文を読み取った内容を読める数式として出力する」という性質上，html本文に記述する入力とページに表示される出力のそれぞれに，方式が2つずつ存在する．
入力ならば

- TeX
  - みなさんお馴染みのまさしくアレ
- MML
  - XMLとしてXHTMLにぶち込まれる

，出力ならば

- chtml
    - どうやらこれはCSS+HTMLを意味するらしい，決してCompact HTMLではない
- svg
    - どんだけ拡大しても品質が劣化しないヤツ，これを生成して直に埋め込むらしい

，これをどう設定するかによって最初の話からがらりと変わってくる…のだが，俺はTeXとsvgが好きだからよ，折角だし**TeX入力・svg出力**を選ぶぜ！



## 用途ごとの使い分け
じゃあさっきの例だと`tex-mml-chtml.js`を呼び出すということだ，そしてこれは「tex型の入力もmml型の入力も受け入れてchtmlで出力する」ということ，他のパターンなら[こ↑こ↓](https://docs.mathjax.org/en/latest/web/components/combined.html)にある通り

+ tex-chtml
+ tex-chtml-full
+ tex-svg
+ tex-svg-full
+ tex-mml-chtml
+ tex-mml-svg
+ mml-chtml
+ mml-svg

なんか`-full`って付いてあるのが強そうだな！じゃあ俺は

```html
<script type="text/javascript" id="MathJax-script" async
  src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg-full.js">
</script>
```

を`<head></head>`にぶち込んでやればいいんだな！

#### ☝️`-full`ってなんだよ
[こ↑こ↓](https://docs.mathjax.org/en/latest/web/components/input.html#input-tex-full)によると，TeXの入力の処理に使うライブラリを事前に全てロードさせるオプションらしい．


## 更なるオプションについて
実は最初のロードの時点で使うライブラリやその動作の設定自由自在にできたりする，[TeXのオプション](https://docs.mathjax.org/en/latest/options/input/tex.html#tex-options)だったり[MathMLのオプション](https://docs.mathjax.org/en/latest/options/input/mathml.html#mathml-options)だったり[AsciiMathのオプション](https://docs.mathjax.org/en/latest/options/input/asciimath.html#asciimath-options)がある，その上でTeXには[これだけのライブラリ](https://docs.mathjax.org/en/latest/input/tex/extensions/index.html#extension-list)を個別に使い分けられる~~だからこれほどまでにTeXを勧めているという節もある~~．
じゃあ試しに書いてみるか，さっきの`input/tex-full`のとこには

> This is the most complete TeX input component. It includes the main TeX/LaTeX input parser, along with all the TeX extensions, and is configured to enable all of them other than physics and colorv2. You can add these two to the packages array in the tex section of your MathJax configuration, though you should remove the color extension if you add the colorv2 extension, and should remove the braket extension if you enable the physics package.
> これは最も完全なTeX入力コンポーネントです。 これには、メインのTeX / LaTeX入力パーサーとすべてのTeX拡張機能が含まれており、物理学とcolorv2以外のすべてを有効にするように構成されています。 これら2つをMathJax構成のtexセクションのpackages配列に追加できますが、colorv2拡張機能を追加する場合はcolor拡張機能を削除し、physicsパッケージを有効にする場合はbracket拡張機能を削除する必要があります。

って書いてある，つまり`-full`した上で更に`color`と`bracket`を減らして`colorv2`と`physics`を入れることができる（そしたらコマンドの重複がなく安全に動作する）らしいな？
[こ↑こ↓](https://docs.mathjax.org/en/latest/options/input/tex.html#the-configuration-block)の全体像と[こ↑こ↓](https://docs.mathjax.org/en/latest/options/input/tex.html#the-configuration-block)の説明

> This array lists the names of the packages that should be initialized by the TeX input processor. The input/tex and input/tex-full components automatically add to this list the packages that they load. If you explicitly load addition tex extensions, you should add them to this list. For example:
> この配列は、TeX入力プロセッサによって初期化される必要があるパッケージの名前をリストします。 input / texおよびinput / tex-fullコンポーネントは、ロードするパッケージをこのリストに自動的に追加します。 追加のtex拡張機能を明示的にロードする場合は、それらをこのリストに追加する必要があります。

そして[こ↑こ↓](http://docs.mathjax.org/en/latest/input/tex/extensions.html)の例文を見る限りだと，なんだか

```javascript
MathJax = {
  loader: {load: ['[tex]/colorv2', '[tex]/physics']},
  tex: {
    packages: {
      '[+]': ['colorv2', 'physics'],
      '[-]': ['color', 'bracket']
    }
  }
};
```

というような形が推奨されているように思うなぁ…

#### urlとライブラリの対応関係

+ `input/tex-base`
  + `base`のみ
      + `require`も`autoload`も入ってないので，本文中のTeX記法からの拡張が不可能になる
+ `input/tex`
  + `base`
  + `ams`
  + `newcommand`
  + `require`
  + `autoload`
  + `configmacros`
  + `noundefined`
  + 管轄外のコマンドを呼び出すと，`physics`・`colorv2`以外なら勝手に`require`する
      + ちなみに自分で`require`で明示的に呼び出した方が整理しやすいらしいよ
+ `input/tex-full`
  + `physics`・`colorv2`以外の[全て](https://docs.mathjax.org/en/latest/input/tex/extensions/index.html#extension-list)
      + その2つは`bracket`・`color`と差し替えできる

以上からわかる通り，別にTeX専用のライブラリに限らずとも，そもそも[Inputのコンポーネント](https://docs.mathjax.org/en/latest/web/components/input.html)も[Outputのコンポーネント](https://docs.mathjax.org/en/latest/web/components/output.html)も同じくライブラリの扱いであり，単に指定しなければsrcの先のurlに`-full`があるか否かでロードする中身を勝手に決めているだけである．

### `require`と`autoload`
`require`の出来る仕事は本家TeX並みに強く，[説明ページ](https://docs.mathjax.org/en/latest/input/tex/extensions/require.html)には

> The require extension defines the non-standard \require macro that allows you to load extensions from within a math expression in a web page. 
> require拡張機能は、Webページの数式内から拡張機能をロードできるようにする非標準の\ requireマクロを定義します。

とあり，つまりコイツさえ入れれば**各ページで`require`することで逐次にロード**できる．

他方で`autoload`は**TeXコマンドとロードするライブラリとの対応関係を事前に定義する**ものであり，そのTeXコマンドをWebページの本文に打っておくと最初にロードされる．
[説明ページ](https://docs.mathjax.org/en/latest/input/tex/extensions/autoload.html)を見ても`require`とは準備や挙動が全く異なることがわかるが，TeX本家にはなさげな見慣れない機能なので，試しに動作する例を示すと

```javascript
MathJax = {
  loader: {
    load: ['input/tex-base', 'output/svg', '[tex]/autoload']
  },
  tex: {
    packages: {
                    '[+]': ['base', 'autoload']
    },
    autoload: {
      boldsymbol: ['boldsymbol']
    }
  }
}
```

↓

![スクリーンショット 2020-11-30 0.13.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540440/9029e278-effb-8d95-f250-eb35b38a161f.png)

後述する`loader: {load: []}`や`tex: {packages: {}}`とは無関係にロードを行うことができる，という点は`require`と共通している


### 最小構成のやり方について
ん？先に挙げた[最小構成オプション](https://docs.mathjax.org/en/latest/web/components/input.html#input-tex-base)の選択肢に対応するようなURLが[こ↑こ↓](https://docs.mathjax.org/en/latest/web/components/combined.html#combined-components)のリストに載ってないやん！と思う方も中にはいるかもしれない．
だがしかし，そもそもこの`MathJax`オブジェクトの中の`loader: {}`（の中の`load: []`）こそが，ページがロードする中身を事前に決め打ちできるレシピのような存在なのである．早い話が例えば

```javascript
MathJax = {
  loader: {load: ['input/tex-base', 'output/svg']},
  tex: {
    packages: {
      '[+]': ['base']
    }
  }
};
```

とすれば，取り合えずは（使えるかどうかは置いといて）最小構成となる．
更に`require`と`autoload`を含めて柔軟性を高めた最小構成であれば

```javascript
MathJax = {
  loader: {load: ['input/tex-base', 'output/svg', '[tex]/require', '[tex]/autoload']},
  tex: {
    packages: {
      '[+]': ['base', 'require', 'autoload']
    }
  }
};
```

と設定してやるのが妥当であろう．

しかしそう設定したところで，srcの先のurlを

```html
<script type="text/javascript" id="MathJax-script" async
  src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js">
</script>
```

やら

```html
<script type="text/javascript" id="MathJax-script" async
  src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg-full.js">
</script>
```

やらとやってしまって良いのだろうか？いや，やっぱりそれはよくない（反語）．
後述する`startup`を[用いなければ](https://docs.mathjax.org/en/latest/web/components/misc.html#startup)MathJaxの指定通りのロードは完璧にはできない．
そしてドキュメントには仕様が載っていなかったので，自分でやって比較してみた…

![fullを選ぶ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540440/f9d10029-fec7-69b9-aa68-9ad2788e7345.png)

![startupを選ぶ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540440/052a3498-620d-e6e8-c0ae-897a7beb7da5.png)

下の方が指定通りのロードをしていそうなことがわかる．
よって突き詰めるのであれば

```html
<script type="text/javascript" id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/startup.js">
</script>
```

を選択することが正しいと考えられる．~~でもurlを打てば一括でロードできちゃうのは楽なんよ~~


### まだまだあるよ！ライブラリ
別にライブラリがあるのはTeXに限った話ではないし，面白い機能もあったりする．

#### [アクセシビリティ](https://docs.mathjax.org/en/latest/web/components/accessibility.html)
さっきの`load: []`に入れると使えるらしい．

+ `a11y/semantic-enrich`
  + 数式に読み仮名を振る，読み上げ機能がある端末に対応できる
+ `a11y/complexity`
  + 複雑すぎる式を折り畳んでくれる，クリックすれば元に戻る
+ `a11y/explorer`
  + Tab（↹）とかを押してWebページの中で数式を移動できる
      + `a11y/complexity`と組み合わせられる
+ `a11y/assistive-mml`
  + MathMLを利用する読み上げ機能がある端末に対応できる
      + `a11y/semantic-enrich`が必要

ここまでを全部載せすると…？

```html
<script type="text/javascript" id="MathJax-script" async
  src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg-full.js">
</script>
```

```javascript
MathJax = {
  loader: {load: ['[tex]/colorv2', '[tex]/physics', 'a11y/semantic-enrich', 'a11y/complexity', 'a11y/explorer', 'a11y/assistive-mml']},
  tex: {
    packages: {
      '[+]': ['colorv2', 'physics'],
      '[-]': ['color', 'bracket']
    }
  }
};
```

`tex: {packages: {}}`が設定するのは**TeXのタイプセット処理にどのライブラリを用いるか**のみであり，アクセシビリティのライブラリはそれとは無関係なので，`loader: {load: []}`の中に記載するだけでおk．

#### [その他](https://docs.mathjax.org/en/latest/web/components/misc.html)

+ `startup`
  + 先にある通り，srcの先のurlの末尾を`startup`にすると，`loader: {load: []}`で指定したライブラリを決め打ちでロードできる
  + 同時にライブラリとしても存在し，`loader`を動かしてロードさせた後にタイプセットまでを行う
  + オプションでロードやタイプセットに関する挙動を制御できる
+ `ui/safe`
  + ユーザーがWebページ上に入力する際に，変なコードが紛れて走らないように防御できる
  + 基本的にhtmlコードに関してであり，オプションで制限する内容をカスタマイズできる
+ `ui/menu`
  + 数式を右クリックすると出現するメニューを追加する
  + 先の[アクセシビリティの注意書き](https://docs.mathjax.org/en/latest/web/components/accessibility.html#accessibility-components)には「機能が被っているので別々に読み込まなくても良い」って書いてる
      + つまりアクセシビリティを突っ込んだからコレと同じものが勝手に読み込まれるらしい
      + ただしコレ単体でもソースコードを表示したり拡大縮小したりchtmlとsvgを切り替えたりはできる
  + あと「自動で折り畳まれる機能は`v3.x.y`にはまだない」って書いてある
  + オプションで表示や機能の設定をカスタマイズできる
+ `adaptors/liteDOM`
  + ブラウザのDOMに対して直接のアクセスができないもの（nodeのアプリとか）でMathJaxのタイプセット等を実行するために，ブラウザのDOMの代替品を実装させる
  + …というものらしいが使ったことがない
+ `core`
  + その他の機能の全てを含む，基本的には勝手に操作されるので弄らなくてもいい
+ `loader`
  + `startup`が自動で持ってくるライブラリで，追加のライブラリをロードする
  + オプションでロードするライブラリの中身やロードの設定をカスタマイズできる
      + `loader: {load: []}`は[その内の1つ](https://docs.mathjax.org/en/latest/options/startup/loader.html#option-descriptions)



## `loader`のオプション
オプション自体は[こ↑こ↓](https://docs.mathjax.org/en/latest/options/startup/loader.html)が公式ドキュメント，機能の一覧を見ると割と使いそうなものも…？

```javascript

MathJax = {
  loader: {
    paths: {mathjax: Loader.getRoot()},          // the path prefixes for use in specifying components
    source: {},                                  // the URLs for components, when defaults aren't right
    dependencies: {},                            // arrays of dependencies for each component
    provides: {},                                // components provided by each component
    load: [],                                    // array of components to load
    ready: Loader.defaultReady.bind(Loader),     // function to call when everything is loaded
    failed: function (error) {                   // function to call if a component fails to load
      console.log(`MathJax(${error.package || '?'}): ${error.message}`);
    },
    require: null                                // function to use for loading components
  }
};
```


### `loader: {load: []}`

今まで何度も出たしもういいよね…


### `loader: {paths: {}}`

#### `[xxx]/yyy`ってなんだ？
`loader: {paths: {}}`が関係する，例えば`xxx`のソースのurlが

```javascript
MathJax = {
  loader: {
    paths: {xxx: 'https://example.com/xxx'},
  }
};
```

と定義されれば，その下の`yyy`を

```javascript
MathJax = {
  loader: {
    load: ['[xxx]/yyy']
  }
};
```

でロードできる，更に数珠つなぎにしてしまえば

```javascript
MathJax = {
  loader: {
    paths: {
      xxx: 'https://example.com/xxx',
      yyy: '[xxx]/yyy'
    },
    load: ['[yyy]/zzz']
  }
};
```

となる，すなわちTeX系のライブラリにおいては

```javascript
MathJax = {
  loader: {
    paths: {
      tex: '何かしらのurl',
    },
    load: ['[tex]/何かしらのライブラリ']
  }
};
```

みたいな構造になっていると推測される．

ちなみにさっきの最小構成において`loader: {load: []}`を以下のように改変すると…

```javascript
MathJax = {
  loader: {load: ['input/tex-base', 'output/svg', 'tex']},
  tex: {
    packages: {
      '[+]': ['base']
    }
  }
};
```

↓

![スクリーンショット 2020-11-29 20.34.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540440/c763d7c4-69fe-41b0-a309-c3e1558449e0.png)

```javascript
MathJax = {
  loader: {load: ['input/tex-base', 'output/svg', '[tex]']},
  tex: {
    packages: {
      '[+]': ['base']
    }
  }
};
```

↓

![スクリーンショット 2020-11-29 20.34.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540440/75401474-8ff5-2dba-4440-de2d971c442e.png)

要するに最終的に末端で確実にファイルが手に入るようなurlにならないとCDNに突き返される，**こんな横着みたいな一括ロードはできない**~~そりゃそうじゃ~~

更に，

```javascript
MathJax = {
  loader: {load: ['input/tex-base', 'output/svg', '[tex]/boldsymbol.js']},
  tex: {
    packages: {
      '[+]': ['base', 'boldsymbol']
    }
  }
};
```

↓

![スクリーンショット 2020-11-29 20.56.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540440/28ef05b9-a1cd-c336-8292-720b5d77dc27.png)

```javascript
MathJax = {
  loader: {load: ['input/tex-base', 'output/svg', '[tex]/boldsymbol.js']},
  tex: {
    packages: {
      '[+]': ['base', 'boldsymbol.js']
    }
  }
};
```

↓

![スクリーンショット 2020-11-29 20.57.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540440/d136e836-fbde-5995-4549-832a3e461464.png)

`tex: {packages: {}}`にはちゃんとライブラリの名前を表記しなきゃいけない割には`loader: {load: []}`はurlの体を成してさえいればおkらしい…


### `loader: {source: {}}`

#### `xxx/yyy`ってなんだ？
絶対urlを設置できる`loader: {source: {}}`が関係する，例えば

```javascript
MathJax = {
  loader: {
    source: {
      'xxx/yyy': 'https://example.com/xxx/yyy.js'
    },
    load: ['xxx/yyy']
  }
};
```

となる，すなわちアクセシビリティ系のライブラリにおいては

```javascript
MathJax = {
  loader: {
    source: {
      '何かしらのライブラリ': '何かしらのurl',
    },
    load: ['何かしらのライブラリ']
  }
};
```

みたいな構造になっていると推測される．
見ての通りで1対1構造の決め打ち方式であり，`loader: {paths: {}}`のような拡張性はない．


### `dependencies: {}`と`provides: {}`
`dependencies: {}`はライブラリ間の依存関係を記憶するリストであり，`startup`は`load: []'`の依頼に基づき`dependencies: {}`を使って必要な（ロードするべき）ライブラリを考え`provides: {}`に列挙していく．
すなわち最終的にロードされるライブラリの実態は`provides: {}`に現れる，先に述べた**urlとライブラリの対応関係はこれで実現されている**とも言える，ドキュメントにも

```javascript
loader: {
  provides: {
    'input/tex': [
      'input/tex-base',
      '[tex]/ams',
      '[tex]/newcommand',
      '[tex]/noundefined',
      '[tex]/require',
      '[tex]/autoload',
      '[tex]/configmacros'
    ]
  }
}
```
みたいな例が載っているし多分そう．
また基本的なライブラリであれば`dependencies: {}`は既に完全に整備されている．

そもそも普通にMathJaxを使うだけなら（コピー品や独自品を自前のサーバーから配信したいとか出ない限り），`loader`にわざわざ手を加える場所は何もなさそうだけど…


### その他のオプション
投げられる関数だったりエラーの処理だったり色々とあるけど，もういいよね…



## `startup`のオプション
オプション自体は[こ↑こ↓](https://docs.mathjax.org/en/latest/options/startup/startup.html)が公式ドキュメント，ロードとタイプセットの挙動を弄るのはもう完全に動的なサービスを作りたい人くらいだと思うので，パスさせていただきますね…

それにタイプセット自体のお話はまた後述…