[{"data":1,"prerenderedAt":36},["ShallowReactive",2],{"post-beautiful-code-blocks-with-shiki":3},{"id":4,"createdAt":5,"updatedAt":6,"publishedAt":6,"revisedAt":6,"title":7,"body":8,"categories":9,"author":11,"thumbnail":24,"ogpImage":28},"beautiful-code-blocks-with-shiki","2024-04-04T01:51:08.098Z","2024-07-16T00:00:05.630Z","シンタックスハイライター「Shiki」で、美しいコードブロックを手に入れよう","\u003Cp>ソースコードのシンタックスハイライトはどのように対応していますか？　普段コードを書いていると、\u003Ca href=\"https:\u002F\u002Fqiita.com\u002F\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">Qiita\u003C\u002Fa>や\u003Ca href=\"https:\u002F\u002Fzenn.dev\u002F\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">Zenn\u003C\u002Fa>などの技術記事プラットフォームや技術系のブログなどで、ハイライトされたコードを見ることは多いのではないでしょうか？\u003C\u002Fp>\u003Cp>\u003Ca href=\"https:\u002F\u002Fshiki.style\u002F\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">Shiki\u003C\u002Fa>は、シンタックスハイライトのためのJavaScriptライブラリです。多くの主要プログラミング言語に対して、非常に正確で高速なシンタックスハイライトを提供します。名前の由来は日本語の「式」で、「スタイル」を意味しています。\u003C\u002Fp>\u003Cp>Webフレームワークの\u003Ca href=\"https:\u002F\u002Fastro.build\u002F\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">Astro\u003C\u002Fa>や\u003Ca href=\"https:\u002F\u002Fnuxt.com\u002F\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">Nuxt\u003C\u002Fa>のコンテンツ管理モジュールである\u003Ca href=\"https:\u002F\u002Fcontent.nuxt.com\u002F\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">Nuxt Content\u003C\u002Fa>、スライド作成ツールの \u003Ca href=\"https:\u002F\u002Fja.sli.dev\u002F\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">Slidev\u003C\u002Fa>などでもシンタックスハイライトに利用されています。\u003C\u002Fp>\u003Cp>本サイトのコードブロックも、すべてShikiを利用してハイライトしています！\u003C\u002Fp>\u003Ch2 id=\"h8e30e50696\">Shikiの特徴\u003C\u002Fh2>\u003Cp>シンタックスハイライトのためのJavaScriptライブラリというと、代表的なものに\u003Ca href=\"https:\u002F\u002Fprismjs.com\u002F\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">Prism\u003C\u002Fa>や\u003Ca href=\"https:\u002F\u002Fhighlightjs.org\u002F\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">highlight.js\u003C\u002Fa>があります。Prismは、軽量で拡張性が高く、プラグインを利用して機能を追加できるといった特徴があります（現在は、v2への移行に向けて2022年頃から開発がストップしている状態のようです \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Forgs\u002FPrismJS\u002Fdiscussions\u002F3531\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">Roadmap for Prism v2\u003C\u002Fa>）。highlight.jsは、200以上のプログラミング言語をサポートし、プログラムコードの言語を自動で検出してハイライトするといった機能があります。直近1年間のnpmダウンロード数を見ると、どちらも多くのサイトで利用されていることが伺えます。\u003C\u002Fp>\u003Cfigure>\u003Ca href=\"https:\u002F\u002Fnpmtrends.com\u002Fhighlight.js-vs-prismjs-vs-shiki\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">\u003Cimg src=\"https:\u002F\u002Fimages.microcms-assets.io\u002Fassets\u002F2e326e11eb0942a5ad843f163281c5af\u002F1b20f0050d704f6ab75464ab823c2fe1\u002Fimage.png?w=1280&amp;h=777\" alt=\"Prism、highlight.js、Shikiの1年間のnpmダウンロード数を表したグラフ。\" width=\"1280\" height=\"777\">\u003C\u002Fa>\u003Cfigcaption>highlight.js vs prismjs vs shiki | npm trends\u003C\u002Ffigcaption>\u003C\u002Ffigure>\u003Cp>では、今回紹介するShikiはどのような特徴があるのでしょうか？\u003C\u002Fp>\u003Ch3 id=\"hdd017d27a1\">VSCodeと同じTextMate文法エンジン\u003C\u002Fh3>\u003Cp>ShikiはVSCodeのシンタックスハイライトと同じ、TextMateの文法とテーマをベースにしています。そのため、VSCodeの更新に伴ってShikiの文法とテーマも更新されます。執筆時点（2024\u002F07\u002F10）では、デフォルトで46のテーマと208の言語をサポートしており、カスタマイズしたテーマや言語を使用することもできます。\u003C\u002Fp>\u003Cul>\u003Cli>\u003Ca href=\"https:\u002F\u002Fshiki.style\u002Fthemes\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">Themes | Shiki\u003C\u002Fa>\u003C\u002Fli>\u003Cli>\u003Ca href=\"https:\u002F\u002Fshiki.style\u002Flanguages\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">Languages | Shiki\u003C\u002Fa> \u003C\u002Fli>\u003C\u002Ful>\u003Cp>公式サイトでは、これらのテーマと言語をプレビューできるPlaygroundも用意されており、使用したいテーマを事前にプレビューすることができます。\u003C\u002Fp>\u003Cul>\u003Cli>\u003Ca href=\"https:\u002F\u002Fshiki.style\u002Fguide\u002F#playground\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">Playground | Shiki\u003C\u002Fa>\u003C\u002Fli>\u003C\u002Ful>\u003Ch3 id=\"h95bf28c01a\">あらゆるJavaScriptランタイム上で動作\u003C\u002Fh3>\u003Cp>Node.jsのAPIやファイルシステムに依存せず、ブラウザ、Node.js、Cloudflare Workersなど、最新のJavaScriptランタイムで動作します。例えば、Shikiの\u003Ca href=\"https:\u002F\u002Fshiki.style\u002F\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">ドキュメントサイト\u003C\u002Fa>ではコードブロックはビルド時にレンダリングし静的に配信され、前述のPlaygroundのみ、クライアントサイドでレンダリングされているようです。\u003C\u002Fp>\u003Ch3 id=\"hbfef88b703\">高度なカスタマイズが可能\u003C\u002Fh3>\u003Cp>ハイライトするコードの指定範囲に、独自のクラスや属性を適用できる装飾用のAPIが提供されています。これにより、コードの特定箇所に枠をつけるなどの処理が簡単に行えるようになっています。\u003C\u002Fp>\u003Cp>また、Shikiは\u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fsyntax-tree\u002Fhast\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">hast\u003C\u002Fa>（HTMLのASTフォーマット）を使用してHTMLを生成します。このhastを操作する処理（トランスフォーマー）を独自に書くことで、生成されるHTMLを柔軟にカスタマイズすることができます。\u003C\u002Fp>\u003Ch3 id=\"h6e3c5c73d2\">柔軟なバンドル\u003C\u002Fh3>\u003Cp>メインの\u003Ccode>Shiki\u003C\u002Fcode>エントリーには、サポートされているすべてのテーマと言語がバンドルされています。文法が使用されるときにのみインポート・ダウンロードされるため、パフォーマンスに優れています。また、ブラウザのランタイムで使用する場合などに細かくコントロールしたい場合は、独自にバンドルを構成することも可能です。あらかじめ構成された以下の2つのバンドルも提供されています。\u003C\u002Fp>\u003Cul>\u003Cli>\u003Cstrong>shiki\u002Fbundle\u002Ffull\u003C\u002Fstrong>【バンドルサイズ：6.4 MB（最小化）、1.2 MB（gzip）】\u003Cp>メインのshikiエントリーと同じように、すべてのテーマと言語が含まれています。\u003C\u002Fp>\u003Cp>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cstrong>shiki\u002Fbundle\u002Fweb\u003C\u002Fstrong>【バンドルサイズ：3.8 MB（最小化）、695 KB（gzip）】\u003Cp>すべてのテーマと一般的なウェブ言語（HTML、CSS、JS、TS、JSON、Markdownなど）、いくつかのWebフレームワーク（Vue、JSX、Svelteなど）が含まれています。\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Ch2 id=\"h10463d71f9\">基本の使い方\u003C\u002Fh2>\u003Cp>Shikiの特徴がなんとなく分かってきたと思いますので、ここから基本的な使用方法について紹介します。\u003C\u002Fp>\u003Ch3 id=\"h038d6117c5\">導入\u003C\u002Fh3>\u003Cp>Shikiを利用するには、npm経由でインストールするか、CDNで利用することができます。今回はnpm経由での利用方法を紹介します。CDNでの利用については\u003Ca href=\"https:\u002F\u002Fshiki.style\u002Fguide\u002Finstall#cdn-usage\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">公式ドキュメント\u003C\u002Fa>を参照してください。\u003C\u002Fp>\u003Cpre>\u003Ccode class=\"language-shell\">npm install -D shiki\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch3 id=\"h9cd0426676\">簡単な使用例\u003C\u002Fh3>\u003Cp>まずは、Shikiが提供する\u003Ccode>codeToHtml\u003C\u002Fcode>関数を用いることで、簡単に使い始めることができます。言語とテーマを指定し、対象のコードを\u003Ccode>codeToHtml\u003C\u002Fcode>関数に渡すと、ハイライトされたHTML文字列が返されます。\u003C\u002Fp>\u003Cdiv data-filename=\"TypeScript\">\u003Cpre>\u003Ccode class=\"language-typescript\">import { codeToHtml } from &quot;shiki&quot;\n\nconst code = &quot;const a = 1&quot; \u002F\u002F 表示するコード\nconst html = await codeToHtml(code, {\n  lang: &quot;javascript&quot;, \u002F\u002F 言語を指定\n  theme: &quot;github-light&quot; \u002F\u002F テーマを指定\n})\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\u003Cp>HTML文字列には、各トークンのインラインスタイルが含まれているので、スタイルを設定するための追加のCSSは必要ありません。\u003C\u002Fp>\u003Cdiv data-filename=\"戻り値のHTML文字列\">\u003Cpre>\u003Ccode class=\"language-html\">&lt;pre\n  class=&quot;shiki github-light&quot;\n  style=&quot;background-color: #fff; color: #24292e&quot;\n  tabindex=&quot;0&quot;\n&gt;\n  &lt;code&gt;\n    &lt;span class=&quot;line&quot;&gt;\n      &lt;span style=&quot;color:#D73A49&quot;&gt;const&lt;\u002Fspan&gt;\n      &lt;span style=&quot;color:#005CC5&quot;&gt; a&lt;\u002Fspan&gt;\n      &lt;span style=&quot;color:#D73A49&quot;&gt; =&lt;\u002Fspan&gt;\n      &lt;span style=&quot;color:#005CC5&quot;&gt; 1&lt;\u002Fspan&gt;\n    &lt;\u002Fspan&gt;\n  &lt;\u002Fcode&gt;\n&lt;\u002Fpre&gt;\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\u003Cp>これを表示すると、以下のようになります。\u003C\u002Fp>\u003Cfigure>\u003Cimg src=\"https:\u002F\u002Fimages.microcms-assets.io\u002Fassets\u002F2e326e11eb0942a5ad843f163281c5af\u002F88f308c40f314183895db080d101bd4d\u002Fimage.png\" alt=\"装飾されたコードのキャプション：const a = 1\" width=\"493\" height=\"81\">\u003C\u002Ffigure>\u003Cp>\u003Ccode>codeToHtml\u003C\u002Fcode>関数の他にも、\u003Ccode>codeToTokens\u003C\u002Fcode>や\u003Ccode>codeToHast\u003C\u002Fcode>を使用して中間データ構造を取得し利用することもできます。\u003C\u002Fp>\u003Cp>参照：\u003Ca href=\"https:\u002F\u002Fshiki.style\u002Fguide\u002Finstall#usage\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">https:\u002F\u002Fshiki.style\u002Fguide\u002Finstall#usage\u003C\u002Fa>\u003C\u002Fp>\u003Ch2 id=\"h5d10f6d404\">同期的にハイライトする\u003C\u002Fh2>\u003Cp>先ほど使用した\u003Ccode>codeToHtml\u003C\u002Fcode>は、テーマと言語をロードするために非同期に実行されます。コードを同期的にハイライトする場合は、\u003Ccode>getHighlighter\u003C\u002Fcode>関数を使用して事前にインスタンスを作成します。\u003C\u002Fp>\u003Cdiv data-filename=\"TypeScript\">\u003Cpre>\u003Ccode class=\"language-typescript\">import { getHighlighter } from &quot;shiki&quot;\n\nconst code = &quot;const a = 1&quot;\n\n\u002F\u002F 事前にインスタンスを作成\nconst highlighter = await getHighlighter({\n  langs: [&quot;javascript&quot;],\n  themes: [&quot;github-light&quot;],\n})\n\n\u002F\u002F 作成したインスタンスを使用して同期的にハイライト\nconst html = highlighter.codeToHtml(code, {\n  lang: &quot;javascript&quot;,\n  theme: &quot;github-light&quot;\n})\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\u003Cp>また、ハイライト作成後にテーマや言語をロードしたい場合は、\u003Ccode>loadTheme\u003C\u002Fcode>や\u003Ccode>loadLanguage\u003C\u002Fcode>メソッドを使うことができます。\u003C\u002Fp>\u003Cdiv data-filename=\"TypeScript\">\u003Cpre>\u003Ccode class=\"language-typescript\">\u002F\u002F テーマを追加\nawait highlighter.loadTheme(&quot;github-dark&quot;)\n\n\u002F\u002F 言語を追加\nawait highlighter.loadLanguage(&quot;css&quot;)\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\u003Cp>すべてのテーマと言語を読み込みたい場合は、\u003Ccode>bundledLanguages\u003C\u002Fcode>と\u003Ccode>bundledThemes\u003C\u002Fcode>からすべてのキーを読み込むことができますが、こちらは推奨されていません。\u003C\u002Fp>\u003Cp>参照：\u003Ca href=\"https:\u002F\u002Fshiki.style\u002Fguide\u002Finstall#highlighter-usage\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">https:\u002F\u002Fshiki.style\u002Fguide\u002Finstall#highlighter-usage\u003C\u002Fa>\u003C\u002Fp>\u003Ch2 id=\"hfdd695d88d\">発展的な機能\u003C\u002Fh2>\u003Ch3 id=\"he046c65b52\">ライトモード・ダークモード（デュアルテーマ）\u003C\u002Fh3>\u003Cp>Shikiはライトモード・ダークモードのデュアルテーマ出力をサポートしています。\u003C\u002Fp>\u003Cp>設定方法は、まず\u003Ccode>themes\u003C\u002Fcode>オプションの\u003Ccode>light\u003C\u002Fcode>と\u003Ccode>dark\u003C\u002Fcode>キーにそれぞれ利用したいテーマを指定します。\u003C\u002Fp>\u003Cdiv data-filename=\"TypeScript\">\u003Cpre>\u003Ccode class=\"language-typescript\">import { codeToHtml } from &quot;shiki&quot;\n\nconst code = &quot;const a = 1&quot;\n\nconst html = await codeToHtml(code, {\n  lang: &quot;javascript&quot;,\n  themes: { \n    light: &quot;github-light&quot;, \u002F\u002F ライトモードのテーマを指定\n    dark: &quot;github-dark&quot;, \u002F\u002F ダークモードのテーマを指定\n  }\n})\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\u003Cp>Shikiは各トークンの色を保存するためにCSS変数を使用しているため、以下のどちらかの方法でCSSスニペットを追加する必要があります。プレフィックスはオプションで変更することも可能です（デフォルトは\u003Ccode>--shiki-\u003C\u002Fcode>）。\u003C\u002Fp>\u003Cdiv data-filename=\"CSSスニペット：クエリーベース\">\u003Cpre>\u003Ccode class=\"language-css\">@media (prefers-color-scheme: dark) {\n  .shiki,\n  .shiki span {\n    color: var(--shiki-dark) !important;\n    background-color: var(--shiki-dark-bg) !important;\n    \u002F* フォントスタイルにも対応する場合は以下のオプションも追加 *\u002F\n    font-style: var(--shiki-dark-font-style) !important;\n    font-weight: var(--shiki-dark-font-weight) !important;\n    text-decoration: var(--shiki-dark-text-decoration) !important;\n  }\n}\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\u003Cdiv data-filename=\"CSSスニペット：クラスベース\">\u003Cpre>\u003Ccode class=\"language-css\">html.dark .shiki,\nhtml.dark .shiki span {\n  color: var(--shiki-dark) !important;\n  background-color: var(--shiki-dark-bg) !important;\n  \u002F* フォントスタイルにも対応する場合は以下のオプションも追加 *\u002F\n  font-style: var(--shiki-dark-font-style) !important;\n  font-weight: var(--shiki-dark-font-weight) !important;\n  text-decoration: var(--shiki-dark-text-decoration) !important;\n}\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\u003Cp>これで、ライトモード・ダークモードによってテーマを変更することができるようになりました。\u003C\u002Fp>\u003Cfigure>\u003Cimg src=\"https:\u002F\u002Fimages.microcms-assets.io\u002Fassets\u002F2e326e11eb0942a5ad843f163281c5af\u002F378dd8866eae42fcb9461d5ce70e8a64\u002Fimage.png\" alt=\"装飾されたコードのキャプション（ライトモード）：const a = 1\" width=\"498\" height=\"85\">\u003C\u002Ffigure>\u003Cfigure>\u003Cimg src=\"https:\u002F\u002Fimages.microcms-assets.io\u002Fassets\u002F2e326e11eb0942a5ad843f163281c5af\u002F04224d884b2a42bd99d57c4ca842a4d1\u002Fimage.png\" alt=\"装飾されたコードのキャプション（ダークモード）：const a = 1\" width=\"494\" height=\"82\">\u003C\u002Ffigure>\u003Ch3 id=\"hd8f0ee35bb\">複数のテーマ\u003C\u002Fh3>\u003Cp>ライトモード・ダークモードのみではなく、2つ以上のテーマをサポートすることも可能です。\u003Ccode>themes\u003C\u002Fcode>オプションは、任意の数のテーマを指定することができます。\u003Ccode>defaultColor\u003C\u002Fcode>オプションでデフォルトのテーマを指定することもできます。\u003C\u002Fp>\u003Cdiv data-filename=\"TypeScript\">\u003Cpre>\u003Ccode class=\"language-typescript\">import { codeToHtml } from &quot;shiki&quot;\n\nconst code = &quot;const a = 1&quot;\n\nconst html = await codeToHtml(code, {\n  lang: &quot;javascript&quot;,\n  themes: {\n    light: &quot;github-light&quot;,\n    dark: &quot;github-dark&quot;,\n    dim: &quot;github-dimmed&quot;,\n    \u002F\u002F ... 任意の数を追加可能\n  },\n\n  \u002F\u002F オプションでデフォルトのテーマを指定\n  defaultColor: &quot;light&quot;,\n})\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\u003Ch2 id=\"h8314264fbd\">コードの装飾\u003C\u002Fh2>\u003Cp>Shikiにはコードをハイライトするだけではなく、コードの特定箇所に独自のクラスを適用するなど、装飾を細かくコントロールするいくつかの機能があります。\u003C\u002Fp>\u003Ch3 id=\"h1f621309ac\">Decorations \u003C\u002Fh3>\u003Cp>decorations  APIを使用することで、独自のクラスや属性を指定の範囲に適用することができます。使用方法は、\u003Ccode>decorations\u003C\u002Fcode>オプション内に\u003Ccode>start\u003C\u002Fcode>と\u003Ccode>end\u003C\u002Fcode>で適用範囲を指定し、\u003Ccode>properties\u003C\u002Fcode>に任意のプロパティを指定します。例として、\u003Ccode>highlighted-word\u003C\u002Fcode>クラスを用意し、コード内の指定箇所に適用してみます。\u003C\u002Fp>\u003Cdiv data-filename=\"TypeScript\">\u003Cpre>\u003Ccode class=\"language-typescript\">import { codeToHtml } from &quot;shiki&quot;\n\nconst code = `\nconst greeting = &quot;Hello World!&quot;\nconsole.log(greeting)\n`.trim();\n\nconst html = await codeToHtml(code, {\n  lang: &quot;javascript&quot;,\n  theme: &quot;github-light&quot;,\n  decorations: [\n    {\n      start: { line: 1, character: 12 }, \u002F\u002F 開始位置を指定\n      end: { line: 1, character: 20 }, \u002F\u002F 終了位置を指定\n      properties: { class: &quot;highlighted-word&quot; }, \u002F\u002F 適用するプロパティを指定\n    },\n  ],\n});\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\u003Cdiv data-filename=\"CSS\">\u003Cpre>\u003Ccode class=\"language-css\">.highlighted-word {\n  border: solid 1px #555555;\n  padding: 0 2px;\n}\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\u003Cp>表示結果は以下のようになります。2行目の13文字目から20文字目まで、「greeting」の箇所に\u003Ccode>highlighted-word\u003C\u002Fcode>のスタイルが適用されていることがわかります。\u003C\u002Fp>\u003Cfigure>\u003Cimg src=\"https:\u002F\u002Fimages.microcms-assets.io\u002Fassets\u002F2e326e11eb0942a5ad843f163281c5af\u002F3ce84396e7684538bd69aa0d2c0bd091\u002Fimage.png\" alt=\"装飾されたコードのキャプチャ画像：const greeting = &apos;Hello World!&apos; console.log(greeting)\" width=\"495\" height=\"114\">\u003C\u002Ffigure>\u003Ch3 id=\"h4f5ce78c05\">Transformers\u003C\u002Fh3>\u003Cp>Shikiは\u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fsyntax-tree\u002Fhast\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">hast\u003C\u002Fa>（HTMLのASTフォーマット）を使用してHTMLを生成しています。Transformers機能を利用すると、このhastを操作する処理を独自に書くことができます。コードの特定の行にアンダーラインを引いたり、diffを表示するといったことが可能です。\u003C\u002Fp>\u003Cp>使用方法は、\u003Ccode>transformers\u003C\u002Fcode>オプション内で変換用のHookを利用した処理を記述します。以下のようなHookが用意されており、任意のタイミングで処理を挟みむことができます。\u003C\u002Fp>\u003Cfigure>\u003Ca href=\"https:\u002F\u002Fshiki.style\u002Fguide\u002Ftransformers#transformer-hooks\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">\u003Cimg src=\"https:\u002F\u002Fimages.microcms-assets.io\u002Fassets\u002F2e326e11eb0942a5ad843f163281c5af\u002Fa01c9131f118406fb75a778941e5e7b3\u002Fimage.png\" alt=\"\" width=\"869\" height=\"104\">\u003C\u002Fa>\u003Cfigcaption>出典：https:\u002F\u002Fshiki.style\u002Fguide\u002Ftransformers#transformer-hooks\u003C\u002Ffigcaption>\u003C\u002Ffigure>\u003Cp>例えば、特定の行に装飾を加えたい場合は、\u003Ccode>line\u003C\u002Fcode>を使用します。\u003C\u002Fp>\u003Cdiv data-filename=\"TypeScript\">\u003Cpre>\u003Ccode class=\"language-typescript\">import { codeToHtml } from &quot;shiki&quot;;\n\nconst code = `\nconst greeting = &quot;Hello World!&quot;\nconsole.log(greeting)\n`.trim();\n\nconst html = await codeToHtml(code, {\n  lang: &quot;javascript&quot;,\n  theme: &quot;github-light&quot;,\n  transformers: [\n    {\n      \u002F\u002F 2行目にアンダーラインを追加\n      line(node, line) {\n        if (line === 2) this.addClassToHast(node, &quot;underline&quot;); \n      },\n    },\n  ],\n});\n\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\u003Cp>これで、以下のように2行目にアンダーラインを引くことができました。\u003C\u002Fp>\u003Cfigure>\u003Cimg src=\"https:\u002F\u002Fimages.microcms-assets.io\u002Fassets\u002F2e326e11eb0942a5ad843f163281c5af\u002Ff725322b4e9c439499920bc8bad50a1e\u002Fimage.png\" alt=\"装飾されたコードのキャプチャ画像：const greeting = &apos;Hello World!&apos; console.log(greeting)\" width=\"491\" height=\"110\">\u003C\u002Ffigure>\u003Cp>また、別パッケージとして提供される\u003Ca href=\"https:\u002F\u002Fshiki.style\u002Fpackages\u002Ftransformers\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">@shikijs\u002Ftransformers\u003C\u002Fa>には、いくつかの便利なTransformersが用意されています。こちらをインストールして利用することで、\u003Cstrong>コードのdiff表示\u003C\u002Fstrong>や\u003Cstrong>特定の行をハイライト\u003C\u002Fstrong>するといったことが簡単に行えます。\u003C\u002Fp>\u003Cpre>\u003Ccode class=\"language-shell\">npm i -D @shikijs\u002Ftransformers\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>コードのdiff表示を追加したい場合は、\u003Ccode>transformerNotationDiff\u003C\u002Fcode>を使用します。\u003Ccode>transformers\u003C\u002Fcode>オプションにインポートした\u003Ccode>transformerNotationDiff()\u003C\u002Fcode>を追加し、コードの差分表示したい行の末尾に\u003Ccode>\u002F\u002F [!code --]\u003C\u002Fcode>と\u003Ccode>\u002F\u002F [!code ++]\u003C\u002Fcode>をそれぞれ追加します。\u003C\u002Fp>\u003Cdiv data-filename=\"TypeScript\">\u003Cpre>\u003Ccode class=\"language-typescript\">import { codeToHtml } from &quot;shiki&quot;;\nimport { transformerNotationDiff } from &quot;@shikijs\u002Ftransformers&quot;;\n\nconst code = `\nconst greeting = &quot;Hello World!&quot; \u002F\u002F [!code --]\nconst greeting = &quot;Hello Japan!&quot; \u002F\u002F [!code ++]\nconsole.log(greeting)\n`.trim();\n\nconst html = await codeToHtml(code, {\n  lang: &quot;javascript&quot;,\n  theme: &quot;github-light&quot;,\n  transformers: [transformerNotationDiff()],\n});\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\u003Cp>これで、\u003Ccode>\u002F\u002F [!code ++]\u003C\u002Fcode>を加えた箇所は\u003Ccode>&lt;span class=&quot;line diff add&quot;&gt;\u003C\u002Fcode>、\u003Ccode>\u002F\u002F [!code --]\u003C\u002Fcode>を加えた箇所は\u003Ccode>&lt;span class=&quot;line diff remove&quot;&gt;\u003C\u002Fcode>とそれぞれclassが付与されたアウトプットが得られます。スタイル自体は生成されないため、好みのスタイルを追加します。\u003C\u002Fp>\u003Cdiv data-filename=\"CSS\">\u003Cpre>\u003Ccode class=\"language-css\">.line.diff.remove {\n  background-color: #fef2f2;\n}\n.line.diff.remove::before {\n  margin-right: 4px;\n  content: &quot;−&quot;;\n  color: #dc2626;\n}\n.line.diff.add {\n  background-color: #f0fdf4;\n}\n.line.diff.add::before {\n  margin-right: 4px;\n  content: &quot;+&quot;;\n  color: #16a34a;\n}\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\u003Cp>表示結果は以下のようになりました。\u003C\u002Fp>\u003Cfigure>\u003Cimg src=\"https:\u002F\u002Fimages.microcms-assets.io\u002Fassets\u002F2e326e11eb0942a5ad843f163281c5af\u002Fdb715d2a720d45c89c9915b26bdda811\u002Fimage.png\" alt=\"装飾されたコードのキャプチャ画像：const greeting = &apos;Hello World!&apos; \u002F\u002F [!code --] const greeting = &apos;Hello Japan!&apos; \u002F\u002F [!code ++] console.log(greeting)\" width=\"493\" height=\"142\">\u003C\u002Ffigure>\u003Ch2 id=\"h87bc7f9479\">まだまだ進化するShiki\u003C\u002Fh2>\u003Cp>今回は、シンタックスハイライター「Shiki」の特徴と基本機能について簡単に紹介しました。\u003C\u002Fp>\u003Cp>Shikiには今回紹介した機能以外にも、まだまだ便利なものが備わっています。いくつか用意されている\u003Ca href=\"https:\u002F\u002Fshiki.style\u002Fguide\u002Finstall#integrations\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">インテグレーション\u003C\u002Fa>を利用し、\u003Ca href=\"https:\u002F\u002Fgithub.com\u002Ftwoslashes\u002Ftwoslash\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">Towslash\u003C\u002Fa>や\u003Ca href=\"https:\u002F\u002Fmicrosoft.github.io\u002Fmonaco-editor\u002F\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">Monaco Editor\u003C\u002Fa>などを、機能統合して使用することもできます。また、最新の\u003Ccode>v1.10\u003C\u002Fcode>ではコード・スニペットの一部をハイライトしたい場合などに便利な\u003Ccode>GrammarState\u003C\u002Fcode>の機能が追加されました。（参考：\u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fshikijs\u002Fshiki\u002Fpull\u002F712\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">https:\u002F\u002Fgithub.com\u002Fshikijs\u002Fshiki\u002Fpull\u002F712\u003C\u002Fa>）\u003C\u002Fp>\u003Cp>まだまだ進化するShikiを利用して、コードブロックに美しいハイライトを施してみてください！\u003C\u002Fp>\u003Ch2 id=\"h44e51f96ce\">参考資料\u003C\u002Fh2>\u003Cul>\u003Cli>\u003Ca href=\"https:\u002F\u002Fshiki.style\u002F\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">https:\u002F\u002Fshiki.style\u002F\u003C\u002Fa>\u003C\u002Fli>\u003Cli>\u003Ca href=\"https:\u002F\u002Fprismjs.com\u002F\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">https:\u002F\u002Fprismjs.com\u002F\u003C\u002Fa>\u003C\u002Fli>\u003Cli>\u003Ca href=\"https:\u002F\u002Fhighlightjs.org\u002F\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">https:\u002F\u002Fhighlightjs.org\u002F\u003C\u002Fa>\u003C\u002Fli>\u003C\u002Ful>",[10],"フロントエンド",[12],{"id":13,"createdAt":14,"updatedAt":15,"publishedAt":14,"revisedAt":16,"name":17,"job":18,"avatar":19,"profile":22,"xId":23,"githubId":23},"koyama","2024-02-14T00:43:53.323Z","2024-03-20T13:41:39.499Z","2024-03-15T13:16:51.910Z","小山 樹人","フロントエンドエンジニア",{"url":20,"height":21,"width":21},"https:\u002F\u002Fimages.microcms-assets.io\u002Fassets\u002F2e326e11eb0942a5ad843f163281c5af\u002F74ad15c43b6042fe899472eb640b7db8\u002Fkoyama_202310.jpg",512,"静岡県出身。大学卒業後、桑沢デザイン研究所の夜間部でグラフィックデザインを学ぶ。専門誌や教育系の出版物を中心に、約10年間DTP制作の仕事に携わる。Webのフロントエンド開発の分野に興味を持ち、2023年に世路庵に入社。\nデザインと開発の両面からものづくりに携わっていきたい。","yamageji",{"url":25,"height":26,"width":27},"https:\u002F\u002Fimages.microcms-assets.io\u002Fassets\u002F2e326e11eb0942a5ad843f163281c5af\u002Fafe9172276d94aca97f534441b35e7bd\u002Fshiki.png",720,1280,{"fieldId":29,"type":30,"image":32},"ogpImage",[31],"タイプ2（タイトル＋画像）",{"url":33,"height":34,"width":35},"https:\u002F\u002Fimages.microcms-assets.io\u002Fassets\u002F2e326e11eb0942a5ad843f163281c5af\u002Fdacce6d618b84eeaa69ced431772ccad\u002Fshiki-ogp.png",630,1200,1776401660706]