zz log

zaininnari Blog

Blink HTMLTokenizer を PHP に移植して、HTML Minifyをできるようにした「html-minifier」

概要

Webkit からフォークされたレンダリングエンジン Blink で使用されている HTMLTokenizer をPHPに移植して、 HTML の Minify(圧縮) を行う「html-minifier」を作りました。

zaininnari/html-minifier

※アルファ版にも満たないため、名称の変更、APIの変更、歴史改変のための push -f がありえます。

できること・できないこと

  • 条件付きコメントを残す
  • textarea や pre 要素内のテキストのHTMLの意味を変えない
  • 開始タグ内のホワイトスペースの最適化
  • タグ間の文字列のホワイトスペースの最適化

但し、未実装の部分があります。

  • DOCTYPE memo SYSTEM の Tokenizer が未実装(PUBLICはOK)。ここを通る処理は未実装のメソッドがあります。
  • invalid なHTMLを処理する際のエラー処理に未実装が多い。
  • 実体参照(©等)が最低限
  • 最適化が甘い(type="checkbox" → type=checkbox や disabled="disabled" → disabled はまだ未実装)

動機

css の最適化なら LESS や Sass があり、JavaScript ならば、Closure Compiler, YUICompressor, UglifyJS 等のライブラリが存在していますが、 それらを活用する HTML には代表的なものをあまり聞きません。

必要な要件は以下の通りです。

  • MUST HTMLの意味を変えない
    • 条件付きコメントは除外されると、挙動が変わってしまうので、条件付きコメント(ダウンレベルから見えない/見える)を除去しない
    • textarea や pre タグ内の要素の空白は意味があるので、最適化を行わない
  • MUST アプリケーションレベルで最適化の実行が可能
    • 素のPHP 、Twig や Smartyのコンパイル後テンプレートキャッシュに対して、最適化を実行したい
  • better 最適化のレベルが選択できる
    • ドキュメントタイプによる最適化の違い(<br>, <br/>, <br />)
    • 属性の最適化( type="checkbox" → type=checkbox 一定の条件で「"」は省略できます。また、disabled="disabled" → disabled という最適化もあります。 )
    • コメントを除去を On/Off 可能(ライブラリによっては、コメントタグに情報を持たせるものが存在するので、問答無用に削除してもらっては困ります。)

今回はブラウザの処理を理解したいのと、PHPでデバック情報も取得したいので、Blink(現時点では、フォーク前のWebkitWebcoreとほとんど変わりありません)の処理を移植することにしました。

最適化の分類

HTMLに独自タグを埋め込む方式

Twig (Symfony 等で採用されているテンプレート言語です。)では、spacelessブロックによって、そのブロック内のタグ間のホワイトスペースを除外できます。 処理方法は正規表現により、「'/>\s+</', '><'」という形式になっており、タグ間のホワイトスペースを一律削除します。

欠点は、テンプレートの導入とコンテンツの移植が必要なことと、属性の最適化・複雑なホワイトスペース・条件付コメントに対応していないことです。

別のマークアップ言語からHTMLへ変換する方式

最高のパフォーマンスを発揮できる形式だと思われますが、有名どころが haml や slim等で Ruby なのが残念。

欠点は、テンプレートの導入とコンテンツの移植が必要なことです。

HTMLの文字列に対して最適化を実行する方式

今回採用した方式、汎用性がある代わり、ブラウザが解釈するレベルの実装でないと、適切な最適化ができません。

PageSpeed Module

最適化のタイミングは、PHP等の処理が行われた後のHTMLに対して処理されます。

ブラウザ → Webサーバー → PHP等 → Webサーバー(ここ) → ブラウザ

実装は、C言語で、Tokenization の簡略化された処理でトークンを作成後、各種フィルタによって圧縮が行われています。 処理の精度も高く、条件付きコメントを残し、インラインの cssJavaScript まで処理してくれます。

欠点は、Webサーバーにインストールを行うので、アプリケーションレベルで最適化を行うとすると、HTTPリクエストが必要になってしまう点です。

minify

PHP で動作するHTML最適化ライブラリです。 方式は正規表現による置換で最適化を行います。 HTMLの構造は正規表現で表現しきれないので、過剰な最適化が発生してしまいます。

欠点は、最適化が甘いこと、過剰な最適化を行う場合がある、更新が止まっていることです。

kangax/html-minifier

JavaScript で動作するHTML最適化ライブラリです。 方式は、正規表現によるトークンの検出後に最適化を実施する方式です。

開発が止まっておらず、ほしい要件も満たしていました。 Node.js からも利用できるので、PHP内で最適化された結果を取得することも可能ですし、そのままPHPへ移植することも可能です。

使い方

composer からインストールできます。

composer.json

{
    "require": {
        "zaininnari/html-minifier": "0.1.*"
    }
}
<?php

require 'vendor/autoload.php';

$html = 'HTML文字列';
$out = zz\Html\HTMLMinify::minify($html);

example.com のTOPページの最適化の様子です。左が最適化前、右が最適化後です。

f:id:zainin:20130716000305p:plain