Menu

Mobile navigation

v1.6.0 リリースノート: MDX コンポーネントの強化

今回のアップデートではなくても良いけど、あったら嬉しい機能を追加した。

このブログは MDX を使って書かれており、いくらでも JavaScript のコードを埋め込める。 便利な機能ではあるのだが、GitHub でコンテンツを保存しているという背景もあり、できるだけ素のマークダウンファイルか GFM の形式を崩さない程度に実装してきた。 そうすればいつの日かホスティングを止めても GitHub から自然言語に近い形で記事を閲覧できる。

GitHub で見ると このような感じ で表示される。

ただ、それらの形式で表現するには限界があるので JSX コンポーネントを意味的に理解しやすい形で実装することにした。 意味的に理解しやすいの定義はコンポーネント名と属性を見るだけで何をしているのかがレンダリングされる前の状態でも推測できるということ。

Google Maps

Google Maps の下にはキャプションを付けられる

これから旅行関係の記事も記録として書いていきたいので一目で場所を理解できる Google Maps は取り入れたかった。

幸いにも Next.js が Google Maps の埋め込みをサポートする ライブラリ を作成していたためそれをラップする形で利用した。

GCP の API キーが必要とのことで、もしかして API の呼び出し制限がある?と思ったが、Maps Embed API は無料かつ無制限で呼び出せた(ソース)。 他の API はリクエスト数に応じた従量課金制であるため、もし API キーが流出した場合を考えて他の API は使えないように設定した。

地図のマーカーを一意に設定するために placeId という Google Maps 固有の ID を使用している。 旧オスカー・シンドラーのホーロー工場 のように名称を入れてもマーカーを設定できるが、それがユニークである保証はないため、少し面倒だが placeId を入れるようにしてある。

placeId の取得は下記のページから行える。

また、caption プロパティに文字列を入れるとコンポーネントの下に説明文を挿入できる。 もちろん設定しなくてもよし。

YouTube

YouTube を記事に埋め込むことで、文章だけでは伝えきれない内容を視覚的に訴えられるので好きだ。 また、読者が動画を再生したら必然的に滞在時間が長くなり検索エンジンからの評価も上がる。 基本的にメリットしかないので実装するしかない。

これも Google Maps と同様に Next.js の 便利なライブラリ があったためラップして使用している。 本来 YouTube の埋め込みは大量のデータを読み込むため、かなり LCP スコアを悪化させてしまう。

Next.js のライブラリでは内部的に lite-youtube-embed を使うことで通常の画像読み込みと遜色ないパフォーマンスを実現している。

lite-youtube-embed がやっていることは非常にシンプルで、動画の代わりにサムネイル画像を最初に読み込む。 動画の再生はユーザがサムネイル画像をクリックしたときのみ開始されるため余計なリクエストが行われないという訳だ。

ただ、デメリットとしてはサムネイル画像が角丸だったりすると UI と合わずに違和感が出てしまう。 これは避けようがない問題なので、そういった動画に当たらないことを願うしかない。

MDX 内では YouTube の URL を入力するだけでビルド時に videoId を抜き出してコンポーネントに属性として渡している。 便利な方法なのだが、キャプションを追加できないのが少し引っかかっているため Google Maps と同じように <YouTube /> のようなコンポーネントに変えるかもしれない。

あと、動画再生時は必ずミュートでスタートするようにしてある(大事なポイント)。

https://github.com/kkhys/me/issues/685

X (Twitter)

X(前 Twitter)ではよく IT 技術関係のポストを見ており、稀に興味深くて記事で言及したいものがあったりする。 そのときに引用する形で埋め込めたら便利だなと思ったため実装してみた。

内部的には react-tweet という Vercel 製のライブラリを使用している。 Vercel が作っているだけあって非常に使い勝手が良く、ポストを埋め込みたい場合はおすすめだ。

特にライトモードとダークモードのスタイリングの切り替えを勝手にしてくれたのは驚いた。

脚注

Here is a simple footnote1.

A footnote can also have multiple lines2.

技術記事ではソースが非常に重要になってくる。 そのときに本文内で言及すると冗長な印象を与えてしまうため脚注を追加できるようにした。

この書き方自体は GitHub のマークダウンファイルでサポートされている3remark-gfm で脚注の HTML は生成されているため、今回はそのスタイリングのみ行った。

アコーディオン

マルチプル

記事内のレイアウトを整理するのに便利そうなアコーディオンコンポーネントを実装した。 複数か単数かで UI を分けている。

シングル

どちらかというとシングルの方が使う頻度は高そう。

HTML には details 4というタグがあり、JavaScript を使わずともブラウザ側で折りたたみウィジェットを作成できる。 以下のように使用する。

<details>
  <summary>バルトークの曲の特徴は?</summary>
 
  バルトークは管弦楽曲、ピアノ曲、歌曲などに多くの作品を残しているが、最も有名なのは 43 年作の「管弦楽のための協奏曲」と、6 曲から成る「弦楽四重奏曲」である。
  作風は異国旋法、原始主義、民族主義、新古典主義を豊かな情感でまとめ、不協和音の中にマジャール(ハンガリー)民族の民謡とリズムが感じとれる革新的な音楽になっている。
</details>

ただ、デフォルトだといまいち見た目が好きではないため独自のコンポーネントを実装した。 コンポーネント名と属性名は <details> タグに基づいている。

アラート

とりあえず 4 種類のアラートを実装した。 これから増える可能性もある。

GitHub がドキュメントでアラートの Markdown 拡張を最近追加した5が、最初はその構文に基づいた書き方にしようとしていた。 しかし、ブロッククォートを解析してコンポーネントに変換するのはけっこう面倒なのでシンプルに JSX で書けるようにした。

それに転載・引用元を示す構文でアラートを表示するのは意味論的に微妙な実装だと思う。

タブ

コンテンツ 1

この記事でも多用しているが、要素を 1 画面で表示してしまいたいときにタブは便利だ。

ステップ

野菜を炒める

  1. 玉ねぎはみじん切り、じゃがいもは大きめの一口大、人参は乱切りにする
  2. 鍋にサラダ油を熱し、玉ねぎを炒める
  3. 玉ねぎがしんなりしたら、豚肉を加えて炒める
  4. 豚肉に火が通ったら、じゃがいも、人参を加えて炒める

煮込む

  1. 水を加えて、沸騰したらアクを取り除く
  2. 弱火で 20 分ほど煮込み、野菜が柔らかくなったら火を止める

ルーを入れる

  1. カレールーを割り入れて溶かし、弱火で5分ほど煮込む
  2. 塩こしょうで味を調えて完成

何かを作るときは必ずステップが存在する。 そのプロセスを説明するときに便利なコンポーネントを追加した。

<Step> タグで囲んだ文字列は <h3> タグとしてレンダリングされる点に注意が必要。

カルーセル

干潮時の厳島神社
久住高原
桜島からの風景
0 / 0

最後にカルーセルコンポーネントを追加した。 今のところ以下の制約がある。

  • 画像のみ対応している
  • 全ての画像を同じ比率に揃える必要がある

コードでこれらの制約を表現できていないため、まだ WIP の機能となる。 とはいえ、カルーセルにこれ以上の機能を求めるべきかというのは疑問だし、ビルド時にバリデーションを追加して違反していれば例外を投げる対応が現実的かもしれない。

表示されている画像以外の不透明度を 15% にしているのと現在のページ数を表示しているのがポイント。 通常の画像に比べてカルーセルだと画像サイズが小さくなるのはデメリットだが、画像の拡大表示をこれから実装すれば問題なさそう。

https://github.com/kkhys/me/issues/624

さいごに

独自コンポーネント満載のこのページを見返してみたら雑多な感じがしてちょっと微妙に感じてしまった。 1 つ 1 つのコンポーネントのレイアウトやデザインを修正することで対応できれば一番良いが、研究が必要なのでしばらく時間がかかる。

そのため、記事を書く際はこれらのコンポーネントにできるだけ頼ることなくシンプルに書いていきたい。

Footnotes

  1. My reference.

  2. To add line breaks within a footnote, add <br />.
    This is a second line.

  3. 基本的な書き方とフォーマットの構文: 脚注 に記載。 ただし、GitHub では半角スペースを 2 つ入れることで改行できたが remark-gfm では対応していないため <br /> タグの追加が必要になる。

  4. MDN ドキュメント: 詳細折りたたみ要素

  5. New Markdown extension: Alerts provide distinctive styling for significant content