Prettier 3.0 と DOCTYPE と HTML の XML 配信(いわゆる XHTML 5)

7月5日に Prettier 3.0(prettier.io)がリリースされました。メジャーバージョンアップということでいくつかの Breaking Changes があります。

当ブログでも HTML, CSS, JavaScript のフォーマッターとして Prettier を使っていますが、とくに影響があった(GitHub)のは以下の3点です。

API
Change public APIs to asynchronous(prettier.io)
JavaScript
Change the default value for trailingComma to all(prettier.io)
HTML
Print HTML5 doctype in lowercase(prettier.io)

API: Change public APIs to asynchronous

§

API の非同期化は単に await を付けて対応完了。特筆するようなことはありません。

JavaScript: Change the default value for trailingComma to all

§

JavaScript の trailingComma の変更は、リリースノートにあるように IE への考慮が必要なくなったことによるものです。これまで当ブログでは ESLint の comma-dangle(eslint.org)を Prettier 側に合わせて functions 構文のみ never にしていたのですが、すべて always-multiline に変更しました。

'comma-dangle': [
	'error',
	{
		arrays: 'always-multiline',
		objects: 'always-multiline',
		imports: 'always-multiline',
		exports: 'always-multiline',
		functions: 'never',
	},
],

'comma-dangle': ['error', 'always-multiline'],

HTML: Print HTML5 doctype in lowercase

§

本記事でもっとも触れたいのは HTML の DOCTYPE についてです。Prettier 2 以前は <!DOCTYPE html> のように DOCTYPE 部分が大文字になっていたものが、今回のバージョン 3 では <!doctype html> と小文字に変換するよう変更されました。

DOCTYPE は HTML 仕様(WHATWG)にあるように、DOCTYPEhtml 部分の大文字・小文字が区別されませんから、これは完全にプロジェクトルールや個人の好みで決めて良い話となります。極端な話、<DoCtYpE hTmL> と書いても(見た目の気持ち悪さを除けば)問題はありません。

一方で歴史的経緯や XML との互換性も踏まえて、私は <!DOCTYPE html> 形式を好んで書いていました。いまや DOCTYPE はその文字列自身には意味のない、単なるレンダリングモード指定のための存在となっていますが、HTML4 以前は文書型宣言としての意味があり、とくに XHTML 文書においては大文字・小文字の区別が重要でした。

文書型宣言の html は HTML 文書におけるルート要素すなわち <html> 要素の要素名を指します。なので要素名を大文字で書く習慣のあった時代は

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<HTML lang="ja">

のように、文書型宣言内の HTML も大文字で書くのが自然なことでした。

XHTML 文書においては要素名は小文字で書かなければなりませんし、HTML と異なり文書型宣言の html 部分もルート要素と大文字・小文字を含めて一致していなければなりませんでしたから、結果として文書型宣言の html も小文字にする必要がありました(must)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja">

また、XHTML では DOCTYPE を大文字で記述しなければならず、HTML を XML としても提供するための Polyglot Markup(W3C)でもやはり DOCTYPE を大文字で書くように推奨(W3C)されていました。

  • Polyglot Markup の W3C Note は2015年9月を最後に更新されておらず、現在はメンテナンスされていない文書となります。あくまで歴史的経緯の説明としてリンクを張っている次第です。

そういった経緯もあり、DOCTYPE は大文字、html は小文字とするのが個人的な肌感覚に合っていたのですが、一方で近年になり複数のプロジェクトで doctype の小文字化が行われた(GitHub)という報告もあります。

Prettier 3.0 でも強制的に小文字に変換されることとなり、この挙動は無効にすることはできません。Pull Request のコメントでオプションを用意する要望があったものの明確に否定(GitHub)されているので、今後のアップデートで追加される望みも薄いでしょう。Prettier を使い続けるならば DOCTYPE の小文字化を受け入れ、もしプロジェクトルールで言及があるならそこもアップデートする必要があるということになります。

ところで、現代の HTML Living Standard でも XML 構文を使用し、application/xhtml+xml などの XML MIME タイプで配信することは可能です。

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="ja" xml:lang="ja">

XML MIME タイプで配信すればユーザーは XML として処理ができるため、例えば <table> 要素を多用したデーターベース的なコンテンツにおいては text/html と比べてメリットになり得るケースもあるでしょう。レアケースだとは思いますが、こういう場合に Prettier 3.0 を導入すると doctype が小文字に変換され、これは XML としての整形式になりませんから、コンテンツがまったく閲覧できなくなってしまうことになります。

ただし、XHTML 1.0 や XHTML 1.1 時代に作られた (X)HTML を壊さないようにするためか、Prettier 3.0 による doctype の強制変換は <!DOCTYPE html> のような短い DOCTYPE の場合にのみ行われるようです。

HTML LS (HTML5) では通常はその短い DOCTYPE を使用するべきとされているものの、DOCTYPEレガシー文字列(WHATWG)として <!DOCTYPE html SYSTEM "about:legacy-compat"> のような長い DOCTYPE も認められているので、Prettier による強制変換の回避方法の一つとして検討に値するでしょう。

2024年11月26日追記本日リリースされた Prettier 3.4 にて、拡張子が .html または .htm 以外の場合は DOCTYPE の変換処理を行わないように挙動が変更されました(Prettier 3.4: A lot of bug fixes(prettier.io))。今年に入って HTML 仕様で XML 構文の使用は推奨されないことが明記されるようになるなど、もはや XML MIME タイプは時代遅れの感が否めないものの、HTML は決して Web でのみ使われるものではなく、EPUB など現役の分野もあるので、この変更は歓迎したいところです。一方で拡張子 .html で XML MIME タイプ配信を行っているケースは引き続き注意が必要ですね。