03 / ガイド
Markdown から HTML へ:クリーンな公開ワークフロー
Markdown が長持ちするソース形式である理由、制限されたコンバーターが実際に対応する範囲、サニタイズとリンクルールが出力を安全に保つ仕組み、HTML 往復で失われるもの、そしてドキュメントやブログのパイプラインにおける変換の位置づけ。
Markdown はエクスポートではなくソースである
公開パイプラインには、ツールやホスト、リニューアルを生き延びるマスター形式が必要です。プレーンテキストの Markdown がそのマスターです。どのエディターでも読め、バージョン管理で差分が取れ、今年たまたまレンダリングしている HTML テンプレートから独立しています。
これを機能させる規律は一方向の流れです。Markdown は人が編集し、HTML はコンバーターが生成し、誰も出力を手で修正しません。エクスポートされた HTML に手が入った瞬間、マスターが二つになり、いずれ乖離します。
- 可搬性可搬性:Markdown ファイルはどのエディターでも開け、移行プロジェクトなしで HTML、PDF、スライド、ドキュメントシステムへ変換できます。
- 差分が取れるレビュー性:文章の変更はきれいな行差分として現れます。HTML をマスターにすると、一語の修正がタグと属性の中に埋もれます。
- スタイルではなく構造関心の分離:ソースは構造——見出し、リスト、引用——だけを持ち、タイポグラフィはテーマが決めるので、リニューアルがアーカイブに触れることはありません。
対応サブセットが変換するもの——平坦化されるもの
意図的なコンバーターがサブセットに限定するのには理由があります。対応構造が一つ増えるごとに、誰もレビューしていないマークアップの持ち込み口が一つ増えるからです。変換に頼る前に、自分のコンテンツがその線に対してどこにいるかを把握しましょう。
Markdown・HTML 作業領域が変換するのはまさにこのサブセットです。Markdown 構文で書かれた画像は代替テキストとリンクに退化し、生の HTML で書かれた表はグリッドを失いセルの文字だけが残ります。サブセットの内側で書けば、公開時に驚くことはありません。
- きれいな変換きれいに変換される:6 段階までの見出し、段落、太字、斜体、取り消し線、インラインコード、フェンス付きコードブロック、番号付き・箇条書きリスト、ブロック引用、水平線、インラインリンク。
- 既知の損失平坦化または消失:埋め込み画像、表、脚注、タスクリスト、生の HTML ブロックはサブセットに対応する表現がないため、消えるかプレーンテキストに退化します。
- 実際の記事で試すテストは簡単です。代表的な記事を変換して出力を読む。結果にないものは、最初から契約になかったのです。
サニタイズは公開の一部であり、追加工程ではない
変換された HTML はページに注入される運命にあり、注入されるマークアップは攻撃面です。クリーンなパイプラインはデフォルトでサニタイズします。スクリプト、スタイル、iframe、フォーム、埋め込み、画像は問答無用で除去され、未知のタグはテキストに展開され、属性は剥がされます。
プレビューペインはサニタイズ済みの出力を描画し、外部リソースを一切読み込まないため、悪意あるマークアップを貼り付けてもツール自体が外部に送信することはありません。
- 能動コンテンツを除去能動的な振る舞いを持つ要素——script、style、iframe、object、embed、svg、form、video、audio、img——は無力化されるのではなく、内容ごと除去されます。
- 属性を剥がす属性は一括で消えます。インラインスタイルもイベントハンドラーも、ソースから持ち込まれたクラスもありません。アンカーが href を保持するのはスキーム検査を通過した場合だけです。
- 静黙ではなく報告作業領域は除去したもの——削除されたノードと剥がされた属性の数——を報告するので、サニタイズは静かな改変ではなく目に見えるイベントです。
リンクは安全なスキームだけを残す
レンダリングされた文書の大半はリンクであり、リンクこそサニタイズが最も具体化される場所です。コンバーターが受け入れるのは http、https、mailto の URL とページ内の #フラグメントだけ。それ以外——javascript:、data:、プロトコル相対の小細工——は href を失い、プレーンテキストとして描画されます。
コンバーターを標準化する前に、許可リストを自分のコンテンツと照合しましょう。FTP ミラーやカスタムアプリスキームへの正当なリンクを含むドキュメント群では、それらのリンクを手で維持する必要があります。まともなサニタイザーが自動で通すことはないからです。
- スキーム許可リスト生き残ったリンクには rel="noreferrer noopener" が付き、開いた先のリンクが元のページを見たりスクリプトで操作したりできません。
- noopener noreferrer同じルールが双方向に適用されます。Markdown に書かれたリンクは変換時に検査され、貼り付けた HTML 内の href はサニタイズ後に再検査されます。
- ラベルは残るリンクがスキームを失ってもラベルのテキストは残ります。壊れたナビゲーションは即座に可視化され、静かな javascript: ペイロードを出荷することにはなりません。
戻りの往復で失われる現実
HTML から Markdown への変換は往復ではなく救出です。サブセットが理解する構造——見出し、段落、強調、リスト、引用、コード——は無事に戻りますが、それ以外は変換が始まる前にサニタイザーが捨てています。
HTML から Markdown への変換は、もう自分でコントロールできないページ——古い CMS のエクスポート、レンダリング済み HTML しか残っていない文書——から本文を引き上げる手段と捉えましょう。そして往復では直せない部分を直します。画像を足し、表を組み直し、それ以降は Markdown を原本にするのです。
- 表は崩壊表は崩壊します。サブセットに表構文がないため、セルのグリッドはセル文字の連なりになり、表形式データは書き直すか CSV エクスポートに切り替える必要があります。
- メディアは除去画像、動画、インタラクティブな埋め込みは設計上消えます。Markdown が組み立てられる前に、サニタイザーが能動コンテンツとして除去するからです。
- テキストは装飾より長生きサブセット外の書式——span、div、クラス、アンカー先——は痕跡を残しません。テキストは生き残り、プレゼンテーションは生き残りません。
ドキュメントやブログのワークフローにおける変換の位置
変換ステップは公開時に記事ごとに一度だけ実行します。Markdown で起草・レビューし、サニタイズ済み HTML に変換し、レンダリング結果を検証してから出荷します。すべてはブラウザータブ内で起こり、下書きがアップロードされることはありません。内容が未発表のリリースである場合に特に重要です。
- 公開時のステップ作業領域は最大 256 KiB のソースを受け付け、最大 512 KiB の出力を生成します。本の一章なら十分な規模です。制限を超えた場合は静かに切り詰めるのではなく、明示的なエラーを報告します。
- 明示的な上限出力は CMS のフィールドにコピーするか、ファイルとしてダウンロードします。どちらの経路でも、プレビューに表示されたのと同じサニタイズ済み文書が渡されます。
- パッチではなく再変換Markdown はそれが記述するコードの隣でバージョン管理し、編集のたびに再変換しましょう。古い HTML にパッチを当てるのはやめます。
構造化テキストにはルーティンが値します。
Markdown の下書きと JSON ペイロードは同じ規律を共有します。まずパースし、構造を検査し、レビュー全体を自分のデバイス上に留めることです。