frontmatter 付きの markdown を渡したら、frontmatter 部分を json に、本文を html に変換する wasm を書いた。
GitHub はこちらで、npm で公開している。
この WASM は node.js で動かす用になっているが、やろうと思えば browser でも動作する。
このブログが next.js 製なんだけど、それの markdown パースに使ってる。
↓ の気になる点はあるものの、記事のパース自体はやっぱそこそこ高速。
記事の更新エディタに esa を使っているので、そっちもいずれ記事にしたい。
Rust の経験も薄いし WASM は初体験だったので勉強した。
Rust の公式ページ から辿れるところが基本。
まずは https://rustwasm.github.io/docs/book/ の Hello World までやると大体感触がつかめる。
大体わかってきたら wasm-bindgen の方を見て、Rust のどの型が JS のどれに変換されるのか確認しながら書いた。
pulldown-cmark は Rust 製の markdown パーサー。プル方式のパーサーで、AST に手を入れるのが簡単で、かつ速いという特徴がある。
このあたりのコード が Syntect でコードブロックを処理する AST を作っているところ。
大体こんな流れで処理している ↓
:innocent:
→ 😇 という絵文字変換もやりたかったので、コードブロック内でない絵文字を変換するという処理もやっている。
絵文字変換には gh-emoji という crate を使っている。
なお、このあたりで zola という SSG の実装を見つけて、上記の処理をだいたい似たような感じでやっているので、大いに参考にさせてもらった。
syntect の SyntaxSet, ThemeSet、絵文字の replacer など、一回初期化してあとはそれを再利用したいものがちょこちょこあった。
まず例として出てきたのは lazy_static だったのだけど、これは結構書き方が覚えにくいと感じたので、once_cell に移行した。
が、これはこれで Lazy::new(|| {
の ||
意味がまだわかっていない。。
追記: 単に引数が空の Closure だった 😂
serde_json, serde_yaml を入れて、下記のように書けば serde_json::Value が取得できるので、あとは to_string なり何なりで JSON 文字列にできる。
serde_yaml::from_str::<serde_json::Value>(text)
# 最初に入れたときは、WSL2 環境だと vendored-openssl オプションつけないとだめだった
cargo install cargo-generate --features vendored-openssl
# 今はオプションつけなくてもインストールできるので、もしかしたら、別件で下記のインストールをした結果直ったかも
sudo apt install libssl-dev
そういう Issue がある。詳しく追ってないけど Cargo.toml に下記を書けば動いた。
[package.metadata.wasm-pack.profile.release]
wasm-opt = ["-Oz", "--enable-mutable-globals"]
syntect とは Rust 製の Syntax Highlighter.
ビルドエラーは この Issue に詳細があり、ざっくりいうと内部で rust-onig という正規表現のライブラリを使っていて、それが WASM に対応してないという状況。oniguruma という C のライブラリに聞き覚えがある人も多そう。
代わりに pure rust な fancy-regex を有効にすることができるので、そっちを使えばビルドができる。
syntect = { version = "4.4.0", default-features = false, features = ["default-fancy"] }