Nu HTML Checkerをローカルで使う方法 2分でできるセットアップ
- #HTML
- #Web標準
- #WHATWG
- #Tips
最終的なHTMLの品質チェック、していますか?
開発中はmarkuplintなどのLinterでコードをチェックできますが、フレームワークや昔ながらのSSI[1]などを使っていると、最終的なHTMLではエラーが出ていることがあります。
そんなときに便利なのがThe Nu Html Checkerです。
Nu Html Checkerとは?
Nu Html Checkerは、WHATWGやW3Cでも使われているHTMLのバリデーションツールです。
Web上にURLを貼り付けたり、HTMLをコピペしたり、ファイルを添付することでHTMLのエラーや警告を検出できます[2]。
今回はそんなNuを、ローカル環境で起動する方法をご紹介したいと思います。
コピペだけでできるからやってみよう!
Dockerでも起動できますが、今回はより環境を選ばず使えるJava版を紹介します。Javaの準備ができていない場合は、先に実行環境をインストールしてください[3]。
なお、Windows向けはPowerShellでの実行を想定しています。
brew install temurin@21winget install EclipseAdoptium.Temurin.21.JDKnuのダウンロード
以下のコマンドで公式リポジトリのReleaseから最新版をダウンロードします[4]。
curl -L -o ~/vnu/vnu.jar https://github.com/validator/validator/releases/download/latest/vnu.jarInvoke-WebRequest -Uri "https://github.com/validator/validator/releases/download/latest/vnu.jar" -OutFile "$HOME\vnu\vnu.jar"nuの起動
java -cp ~/vnu/vnu.jar nu.validator.servlet.Main 8888Start-Process -NoNewWindow java -ArgumentList @("-cp", "$HOME\vnu\vnu.jar", "nu.validator.servlet.Main", 8888)ブラウザでhttp://localhost:8888/を開くだけ!
ついでにこのツールでブックマークレットも使えるようにしておきましょう!(よければどうぞ)
これでもうNuがローカルで使えるようになったはずです🎉
【全部入り】vnuをコマンド化する
インストールもアップデートも丸ごと1つのコマンドでやりたい!!!そんな私のためのメモ書き。
以下のコマンドを1回叩くだけで、vnuコマンドを生やせます[5]。むちゃ便利です。なおご利用は自己責任で🙏
コマンド | 処理 |
|---|---|
| Nuの起動 |
| Nuのインストール |
| Nuのアップデート |
| Nu(port 8888)の停止 |
cat >> ~/.zshrc << 'EOF'
vnu() {
# --install
if [ "$1" = "--install" ]; then
echo "installing..."
mkdir -p ~/vnu
curl -L -o ~/vnu/vnu.jar https://github.com/validator/validator/releases/download/latest/vnu.jar
echo "✅ vnu is installed!"
return
elif [ ! -f ~/vnu/vnu.jar ]; then
echo "❌ vnu is not installed."
echo "Run 'vnu --install' to install vnu."
return
# --update
elif [ "$1" = "--update" ]; then
echo "updating..."
curl -L -o ~/vnu/vnu.jar https://github.com/validator/validator/releases/download/latest/vnu.jar
echo "✅ vnu is updated!"
return
# --stop
elif [ "$1" = "--stop" ]; then
if lsof -i :8888 > /dev/null 2>&1; then
kill $(lsof -ti :8888)
echo "💤 vnu is stopped"
else
echo "⚠️ vnu is not running"
fi
return
fi
# 起動中かチェック
if lsof -i :8888 > /dev/null 2>&1; then
echo "⚠️ vnu is already running"
open http://localhost:8888/
return
fi
# 起動
echo "starting..."
java -cp ~/vnu/vnu.jar nu.validator.servlet.Main 8888 &
# 最大10秒待つ
for i in $(seq 1 20); do
if lsof -i :8888 > /dev/null 2>&1; then
open http://localhost:8888/
return
fi
sleep 0.5
done
echo "⚠️ vnu did not start within 10s"
}
EOF
source ~/.zshrcAdd-Content $PROFILE @'
function vnu {
$jar = "$HOME\vnu\vnu.jar"
$url = "https://github.com/validator/validator/releases/download/latest/vnu.jar"
$port = 8888
# --install
if ($args[0] -eq "--install") {
Write-Host "installing..."
New-Item -ItemType Directory -Force -Path "$HOME\vnu" | Out-Null
Invoke-WebRequest -Uri $url -OutFile $jar
Write-Host "✅ vnu is installed!"
return
}
# jarがない場合
if (-not (Test-Path $jar)) {
Write-Host "❌ vnu is not installed."
Write-Host "Run 'vnu --install' to install vnu."
return
}
# --update
if ($args[0] -eq "--update") {
Write-Host "updating..."
Invoke-WebRequest -Uri $url -OutFile $jar
Write-Host "✅ vnu is updated!"
return
}
# --stop
if ($args[0] -eq "--stop") {
$listeners = Get-NetTCPConnection -State Listen -LocalPort $port -ErrorAction SilentlyContinue
if ($listeners) {
$pids = $listeners |
Select-Object -ExpandProperty OwningProcess -Unique |
Where-Object { $_ -notin 0, 4 }
if ($pids) {
foreach ($targetPid in $pids) {
try {
Stop-Process -Id $targetPid -ErrorAction Stop
Write-Host "💤 stopped PID $targetPid"
} catch {
Write-Host "⚠️ failed to stop PID $targetPid ($($_.Exception.Message))"
}
}
Write-Host "💤 vnu is stopped"
} else {
Write-Host "⚠️ no stoppable process found"
}
} else {
Write-Host "⚠️ vnu is not running"
}
return
}
# 起動中かチェック
$running = Get-NetTCPConnection -State Listen -LocalPort $port -ErrorAction SilentlyContinue
if ($running) {
Write-Host "⚠️ vnu is already running"
Start-Process "http://localhost:$port/"
return
}
# 起動
Write-Host "starting..."
Start-Process -NoNewWindow java -ArgumentList @(
"-cp"
$jar
"nu.validator.servlet.Main"
$port
)
# 最大10秒待つ
$maxWait = 10
$elapsed = 0
while ($elapsed -lt $maxWait) {
$started = Get-NetTCPConnection -State Listen -LocalPort $port -ErrorAction SilentlyContinue
if ($started) {
Start-Process "http://localhost:$port/"
return
}
Start-Sleep -Milliseconds 500
$elapsed += 0.5
}
Write-Host "⚠️ vnu did not start within ${maxWait}s"
}
'@
. $PROFILEおわりに
新しい技術の話はすぐ盛り上がる一方で、HTMLの品質とかそういう基礎的な部分ってあんまり話題にならないのは、知るチャンスが少ないからだと思うんですよね。
ユーザが触る領域を担うエンジニアならばこそ、先人たちが築き上げてきた偉大なWeb標準を守ることを大切に、できる限り仕様に準拠したものだけを世の中にリリースしていって欲しいと思っています。
そうした小さな積み重ねが、一人一人のユーザの助けになり、ゆくゆくは将来の自分を助けることになるかもしれません。誰かの「使えなくて困った」は、HTMLを正しくするだけで大幅に削減できます。
Nu Validatorを知らなかったあなたも、忘れていたあなたも、日常使いしているあなたも、まだHTMLの品質チェックの仕方を知らない誰かへ伝えてあげてください。
余談1:ローカルでNuを動かすとなにがうれしいのか
余談2:社内のイントラでホスティングする場合に、社外のWebページが検査できてしまうと困るんだけど…
URLを入力してそのWebページのHTMLをチェックする機能がありますが、SSRFなどの懸念がありセキュリティ的に避けたい…。
実はそんなあなたのために--allowed-address-typeオプションが用意されています。
all- URL経由の検査をすべて許可します(デフォルト)same-origin- 同一オリジンURL経由の検査のみ許可しますnone- URL経由のHTML検査を禁止します
サーバで起動する際に設定することで、社内のNuから許可されていないWebページの検査を禁止できます。
関連情報
脚注
- [^1]:その昔、よく共通ヘッダーや共通フッターなどのガワはServer Side Includeで実装したものです😌
- [^2]:「check as CSS」にチェックをいれればCSSを検査することもできます。
- [^3]:Dockerが使える方は公式リポジトリから起動コマンドを参照してください。2026年3月現在は21がLTSですが、必要に応じてバージョンは修正してください。JDKはOracleが本家ですが、商用利用に制限があるためここではEclipse Temurinを用います。
- [^4]:ここでは、ユーザルートに
vnuフォルダを作ってその中にvnu.jarをダウンロードしていますが、どこにおいてもOK。vnuがNu html Checker本体。 - [^5]:Javaのインストールは必要です。Docker版でも似たような感じでコマンドはやしたほうが便利そう。
- [^6]:基本的にほとんどのケースでは、所属組織から認証されてない外部サーバに資材を送信することはNGになっていると思います。
- [^7]:Python環境が必要です。