知らない子も生まれたようですが、いつもの奴に行き着きました。
構文強調
構文強調とは、以下のようにプログラミング言語のキーワードを装飾することです。
<p>HTML</p>
css { color:red; }
console.log('Hello JavaScript !!');
カラフルで見やすいですね。これは複雑なHTMLとCSSで実装されています。でも、それを手作業で書くのは大変です。そこで自動化するライブラリが欲しくなります。
構文強調ライブラリとは、構文強調に必要なHTMLとCSSのコードを自動生成してくれるJavaScriptライブラリです。
既存ライブラリ
| ライブラリ | 概要 |
|---|---|
| highlight.js | 昔からある使いやすいライブラリ。テーマも豊富。 |
| shiki | 新しいライブラリで高機能。でも私の要件に合わず。 |
| CSS Custom Highlight API | 新しい標準API。でも私の環境に未実装。 |
他にも色々なライブラリがありますが、有名なものは上記です。今も更新されており、高機能で使いやすい等の理由でしょう。
CSS Custom Highlight API
CSS Custom Highlight APIは標準APIです。外部ライブラリをインストールする必要がありません。ぜひとも使いたかったのですが、私の環境では未実装でした。
Chrome 105以降で使えるそうですが、私の環境は92と古すぎました。残念。
更新作業が大変すぎるので避けています。私のマシンはラズパイです。ブラウザの更新にはOSの更新が必要です。ダウンロード、SDカード焼き、ブート設定ファイル作成、クリーンインストール、データコピー、アプリのインストール等の工程が必要で、数日がかりの大作業となり、憂鬱すぎて避けること早数年。だれか代わりにやってください。以下にそのあたりの膨大な情報を記録してあります。
本題から遠ざかること山の如し。やってられません。
shiki
shikiは現状で最高の構文強調ライブラリです。
- 高パフォーマンス
- 分割インポートできる
- wasmで実装されている
- 高機能
- ダークモードに対応している
- TypeScriptの型情報からコード注釈をポップアップできる
ただ、私の要件には合いませんでした。
- オフラインでも実行できる
- Node.js, TypeScriptが不要である
Node.js, TypeScriptをインストールしてビルドすれば、オフラインでも実行できるコードを生成できるでしょう。ただし、私はその環境を使いたくありません。
ブラウザだけで開発したかったのです。shikiのJSとCSSを全部ダウンロードし、<script>と<link>タグをローカルのHTMLに書くだけで動作するように実装したかったのです。これができませんでした。
CDNなら動作しました。しかしオフラインでは使えません。リンク先を辿りコードを追いましたが、内部で大量のimport文があり、それらをすべて手動でダウンロードしてローカルに再配置するのは無謀だと諦めました。
highlight.js
highlight.jsは昔からある構文強調ライブラリです。業界で最も有名かつ情報も多く、今尚、更新が続けられていたので安心して利用できそうです。
APIは旧版から多少変化しているようですが、API Referenceを見れば判るでしょう。あるいは古いですが日本語情報も豊富です。
ただ、私の要件的に、次のような問題があります。
- 分割インポートできない
- ダークモードに対応していない
- 行数表示がない
- コピーボタンがない
- ダウンロードボタンがない
- JsDocによるコード注釈ポップアップ表示できない
実際には1さえ解決できれば、あとはプラグインを実装することで実現可能だと思われます。尤も、1〜6はすべて自分で実装することになるでしょうが。(shikiであれば2までは裸の状態で使えるのになぁ)
他者が開発したプラグインもあるようです。しかし細かい所で不満が出そうなので、自分でイチから作ることになりそうな気がします。
1. 分割インポートできない
これを説明すると少々長くなります。
構文強調は多数のプログラミング言語に対応していますが、それぞれの言語用に異なるライブラリをインポートする必要があります。そのせいで読込に時間がかかり応答速度が遅くなってユーザ体験が悪くなってしまいます。
応答速度の低下を回避するには、分割インポートが有効です。つまり構文強調したい言語のライブラリだけをインポートすれば、応答速度の低下を最小限に抑えられます。
構文強調したい言語のライブラリだけをインポートする。それは当たり前のことです。でも、事前にどの言語を強調したいか判らない場合もあります。たとえばブログを書くツール等です。ユーザに自由な入力を許すため、事前にどの言語を強調したいか判りません。
事前にどの言語を強調したいか判らない場合、それが判明した時点で、判明した言語のライブラリだけを動的インポートしたいのです。たとえば言語名を文字列の変数で渡せば動的インポートしてくれるようなAPIが欲しいです。
実際には存在しませんが、以下hljs.loadLanguage(...langNames)のようなAPIが欲しかったのです。
hljs.loadLanguage('html', 'css', 'js'); // 任意の言語名 hljs.highlightAll(); // 構文強調する
1-1. EMS版コードならimportできる
highlight.jsをダウンロードして展開した中に、esディレクトリがあります。その中にあるコード一式を使います。これはES Moduleと呼ばれる比較的新しい標準APIを用いて実装されたコードです。
次のようにすると、js,json,yaml,markdownの言語ライブラリを動的インポートします。
import hljs from 'highlight.js/lib/core'; import js from 'highlight.js/lib/languages/javascript'; import json from 'highlight.js/lib/languages/json'; import yml from 'highlight.js/lib/languages/yaml'; import md from 'highlight.js/lib/languages/markdown'; hljs.registerLanguage('javascript', js); hljs.registerLanguage('json', json); hljs.registerLanguage('yaml', yml); hljs.registerLanguage('markdown', md);
ただ、この場合、次のような問題があります。
- EMS版コードはES6(ES2015)以前の環境では動作しない
hljs.registerLanguage()だけでなくimport文も必要だが、それを文字列変数で渡せない(文書の先頭に書く必要有)- 動的import APIがあるが、ES6(ES2015)以前の環境では動作しない
GitHubのIssueにも私が挙げた問題の一部がやり玉に挙がっていますが、モチベーションは低いようです。それは理解できます。費用対効果は薄いでしょうから。新しい環境なら動的import APIを使えばいいだけですし、わざわざ古い環境に対応するのも面倒な上に、ファイルサイズが無駄に肥大化します。未来を見据えると全員が不幸になるでしょう。
1-2. EMSを使いたくない(ES5以前でも使用できるよう実装したい)
昔から使える<script>や<link>でJSとCSSを参照する方法です。これなら環境を選ばず、どこでも動作します。ビルド環境を用意する必要もありません。ブラウザとテキストエディタだけで開発できます。
さしずめNo-Module版とでも仮名しておきます。
index.htmlファイルに以下を追記することで外部にあるJSやCSSのファイルを参照します。
<link rel="stylesheet" href="参照したいCSSファイルのURLやパス"> <script src="参照したいJSファイルのURLやパス">
ここで本題です。参照するファイルを動的に決定したいです。構文強調したい言語毎に参照したいJSファイルが違います。また、使用したいテーマ毎に参照したいCSSファイルが違います。これをユーザが自由に選んで、必要なファイルだけを動的に参照したいのです。
残念ながら、それを実行する直接的なAPIはありませんでした。先述の通り、ESMを使用したインポートは対応していますが、それだと後方互換に問題があります。
後方互換の問題を解決するには、古いコードで動作する動的インポートを実装する方法があります。さしずめscriptタグ挿入式動的インポートとでも仮名しましょう。これを自分で実装すれば、私の求める古い環境における動的インポートが実現できるでしょう。
とりあえず技術的に可能であるかを軽く調べると、以下のような記事がありました。
たぶん実現可能でしょう。今更欲しがる人は居ないかもしれません。ES6(ES2015)以降なら動的import APIが使えますからね。でも私は欲しいのです。誰もやらないだろうから、私が作るしかないでしょう。時代に取り残されたガラパゴス化石人間の末路……。
所感
調査だけで大変だった。
使用ライブラリはhighlight.jsに決まるも、不足が6つもあり、そのうちの1つ目の調査だけでもう大変。
やりたいことを実現するまでが遠すぎる。コツコツやるしかないが、途中で挫折するのが目に浮かぶようだ。
とりあえず最初はscriptタグ挿入式動的インポートの汎用ライブラリだけでも仮作成してみるか。
対象環境
- Raspbierry pi 4 Model B
- Raspberry Pi OS buster 10.0 2020-08-20 ※
- bash 5.0.3(1)-release
$ uname -a Linux raspberrypi 5.10.103-v8+ #1529 SMP PREEMPT Tue Mar 8 12:26:46 GMT 2022 aarch64 GNU/Linux