Web サイトの診断ツール Sonar を使ってみる | Monotalk に続いて、sonar, a linting tool for the web の Cli ツールを使ってみます。
目次
CLI ツールを実行する
User guide | sonar documentation を参考にインストール、ツールを実行します。
インストール、作業ディレクトリの作成
- インストール
% npm install -g --engine-strict @sonarwhal/sonar
-
OUTPUT
/usr/local/bin/sonar -> /usr/local/lib/node_modules/@sonarwhal/sonar/dist/src/bin/sonar.js > canvas-prebuilt@1.6.0 install /usr/local/lib/node_modules/@sonarwhal/sonar/node_modules/canvas-prebuilt > node-pre-gyp install [canvas-prebuilt] Success: "/usr/local/lib/node_modules/@sonarwhal/sonar/node_modules/canvas-prebuilt/canvas/build/Release/canvas-prebuilt.node" is installed via remote > amphtml-validator@1.0.20 postinstall /usr/local/lib/node_modules/@sonarwhal/sonar/node_modules/amphtml-validator > /bin/sh -c "exit 0" 2> postinstall.DELETEME && rm postinstall.DELETEME || node postinstall-windows.js > axe-core@2.4.2 postinstall /usr/local/lib/node_modules/@sonarwhal/sonar/node_modules/axe-core > node build/utils/postinstall.js + @sonarwhal/sonar@0.13.0 added 438 packages in 81.745s
-
作業ディレクトリを作成
init
コマンドを打つため、作業ディレクトリを作成します。
mkdir sonar
init コマンド実行
- ディレクトリ移動、initコマンドを実行
cd sonar sonar --init
以下、console 上で幾つか質問を聞かれるので、答えていきます。
-
ブラウザを選択
chrome
を選択しました。
Welcome to sonar configuration generator ? What connector do you want to use? (Use arrow keys) ❯ chrome jsdom
-
formatter を選択
json
を選択しました。? What formatter do you want to use? ❯ codeframe json stylish summary
-
推奨ルールを使うか否かを選択
Y
を選択しました。
? Do you want to use the recommended rules configuration?
-
対象ブラウザを選択
Default
を選択しました。
? What browsers are you targeting? (Use arrow keys) ❯ Default (last 2 versions of each browser, and browsers with globaly usage over 1%, plus Firefox ESR) Custom (use browserslist format: https://github.com/ai/browserslist#queries)
-
.sonarrc の内容を確認
選択した設定に従い、.sonarrc
が作成されます。
上記の選択だと、以下の内容で作成されました。
% cat .sonarrc { "browserslist": [], "connector": { "name": "chrome", "options": { "waitFor": 1000 } }, "formatters": [ "json" ], "ignoredUrls": [], "rules": { "amp-validator": "off", "apple-touch-icons": "error", "axe": "error", "content-type": "error", "disown-opener": "error", "highest-available-document-mode": "error", "html-checker": "error", "image-optimization-cloudinary": "off", "manifest-app-name": "error", "manifest-exists": "error", "manifest-file-extension": "error", "manifest-is-valid": "error", "meta-charset-utf-8": "error", "meta-viewport": "error", "no-disallowed-headers": "error", "no-friendly-error-pages": "error", "no-html-only-headers": "error", "no-protocol-relative-urls": "error", "no-vulnerable-javascript-libraries": "error", "ssllabs": "off", "strict-transport-security": "error", "validate-set-cookie-header": "error", "x-content-type-options": "error" }, "rulesTimeout": 120000 }
チェック実行
このサイトに対して、チェックを実行します。
-
チェック実行
sonar https://www.monotalk.xyz
-
警告の抜粋
json
フォーマットを選択したので、json形式で出力されます。
https://www.monotalk.xyz/static/fonts/Open-Sans-800italic/Open-Sans-800italic.woff2?5ddec16961e4: 5 issues [ { "location": { "column": -1, "line": -1 }, "message": "'content-type' header should have media type 'application/font-woff2' (not 'application/x-font-woff')", "resource": "https://www.monotalk.xyz/static/fonts/Open-Sans-800italic/Open-Sans-800italic.woff2?5ddec16961e4", "ruleId": "content-type", "severity": 2, "sourceCode": null }, { "location": { "column": -1, "line": -1 }, "message": "'server' header is disallowed", "resource": "https://www.monotalk.xyz/static/fonts/Open-Sans-800italic/Open-Sans-800italic.woff2?5ddec16961e4", "ruleId": "no-disallowed-headers", "severity": 2, "sourceCode": null }, { "location": { "column": -1, "line": -1 }, "message": "'x-ua-compatible' header is not needed", "resource": "https://www.monotalk.xyz/static/fonts/Open-Sans-800italic/Open-Sans-800italic.woff2?5ddec16961e4", "ruleId": "no-html-only-headers", "severity": 2, "sourceCode": null }, { "location": { "column": -1, "line": -1 }, "message": "'strict-transport-security' header was not specified", "resource": "https://www.monotalk.xyz/static/fonts/Open-Sans-800italic/Open-Sans-800italic.woff2?5ddec16961e4", "ruleId": "strict-transport-security", "severity": 2, "sourceCode": null }, { "location": { "column": -1, "line": -1 }, "message": "'x-content-type-options' header was not specified", "resource": "https://www.monotalk.xyz/static/fonts/Open-Sans-800italic/Open-Sans-800italic.woff2?5ddec16961e4", "ruleId": "x-content-type-options", "severity": 2, "sourceCode": null } ]
設定変更して、再度チェックを実行
コンソールで内容を確認するには、json 形式だと見づらいので別の形式に変更、3rd party の リソースで出力される警告を OFF にします。
また、Web UI から チェック実施した際に無視したルールを除外します。
出力フォーマットを変更
.sonarrc
を編集
.sonarrc
を編集して formatter を"stylish"
に変更します。
"formatters": [ "stylish" ],
-
チェックを再実行
sonar https://www.monotalk.xyz
-
チェック結果の抜粋
コンソール出力に見やすい形式で出力されます。
✖ Finishing... https://www.monotalk.xyz/ Error Invalid date format in 'expires' value of the 'set-cookie' header to set 'csrftoken'. The recommended format is: Mon, 29 Oct 2018 11:58:05 GMT validate-set-cookie-header Error Manifest not specified manifest-exists Error jQuery@2.2.4 has 2 known vulnerabilities (1 medium, 1 low). See https://snyk.io/vuln/npm:jquery for more information. no-vulnerable-javascript-libraries line 4 col 21516 Error Protocol relative URL found: //monotalkxyz.disqus.com/count-data.js?1=BlogPost-323&1=BlogPost-324&1=BlogPost-325&1=BlogPost-326&1=BlogPost-327&1=BlogPost-328&1=BlogPost-329&1=BlogPost-330&1=BlogPost-331&1=BlogPost-332 no-protocol-relative-urls line 4 col 21764 Error Protocol relative URL found: //monotalkxyz.disqus.com/count-data.js?1=BlogPost-333&1=BlogPost-334&1=BlogPost-335&1=BlogPost-337&1=BlogPost-338&1=BlogPost-339&1=BlogPost-340&1=BlogPost-341&1=BlogPost-342&1=BlogPost-343 no-protocol-relative-urls line 4 col 22012 Error Protocol relative URL found: //monotalkxyz.disqus.com/count-data.js?1=BlogPost-344&1=BlogPost-345&1=BlogPost-346&1=BlogPost-347&1=BlogPost-348 no-protocol-relative-urls line 5 col 20046 Error Protocol relative URL found: //uh.nakanohito.jp/uhj2/uh.js no-protocol-relative-urls line 5 col 21384 Error Protocol relative URL found: //monotalkxyz.disqus.com/count.js no-protocol-relative-urls line 5 col 22996 Error <ul> and <ol> must only directly contain <li>, <script> or <template> elements axe line 16 col 205 Error Form elements must have labels axe line 16 col 310 Error Form elements must have labels axe line 16 col 1002 Error Protocol relative URL found: //pagead2.googlesyndication.com/pagead/js/adsbygoogle.js no-protocol-relative-urls line 16 col 1598 Error Frames must have title attribute axe line 20 col 7460 Error Elements must have sufficient color contrast axe line 31 col 88 Error Protocol relative URL found: //pagead2.googlesyndication.com/pagead/js/adsbygoogle.js no-protocol-relative-urls line 31 col 684 Error Frames must have title attribute axe line 33 col 10696 Error Links must have discernible text axe line 33 col 10909 Error Links must have discernible text axe line 33 col 11119 Error Elements must have sufficient color contrast axe ✖ Found 19 errors and 0 warnings 中略..................... https://fcmatch.youtube.com/pixel?goog … cql_Xe3xhq4cSK1pDUlBdIUqmjVJtWBTQ51wpzw Error 'x-frame-options', 'x-xss-protection' headers are not needed no-html-only-headers Error 'strict-transport-security' header was not specified strict-transport-security Error 'x-content-type-options' header was not specified x-content-type-options ✖ Found 3 errors and 0 warnings https://pagead2.googlesyndication.com/ … UiZYl3_X2rV4FTV0sl2De43qVlh58jk7tgEaozB Error 'strict-transport-security' header was not specified strict-transport-security ✖ Found 1 error and 0 warnings ✖ Found a total of 181 errors and 0 warnings
ignore URL を追加
3rd party のリソースで警告が出力されますが、対処ができないため一律 OFF にします。
- ignore URL に、エラーを無視したいドメインを追加
ignoredUrls
に、エラーを無視したいドメインを追加します。
全てのルールを無視したいので、rules
には["*"]
を設定しています。
"ignoredUrls": [
{
"domain": "pagead2.googlesyndication.com",
"rules": ["*"]
},
{
"domain": "www.gstatic.com",
"rules": ["*"]
},
{
"domain": "tpc.googlesyndication.com",
"rules": ["*"]
},
{
"domain": "fonts.gstatic.com",
"rules": ["*"]
},
{
"domain": "googleads.g.doubleclick.net",
"rules": ["*"]
},
{
"domain": "monotalkxyz.disqus.com",
"rules": ["*"]
},
{
"domain": "fonts.googleapis.com",
"rules": ["*"]
},
{
"domain": "www.google-analytics.com",
"rules": ["*"]
},
{
"domain": "securepubads.g.doubleclick.net",
"rules": ["*"]
},
{
"domain": "uh.nakanohito.jp",
"rules": ["*"]
},
{
"domain": "adservice.google.com",
"rules": ["*"]
},
{
"domain": "adservice.google.co.jp",
"rules": ["*"]
},
{
"domain": "www.googletagmanager.com",
"rules": ["*"]
}
],
-
チェックを再実行
sonar https://www.monotalk.xyz
-
チェック結果
3rd party のドメインのエラーは出力されなくなりました。
✖ Finishing... https://www.monotalk.xyz/ Error Invalid date format in 'expires' value of the 'set-cookie' header to set 'csrftoken'. The recommended format is: Mon, 29 Oct 2018 12:05:14 GMT validate-set-cookie-header Error Manifest not specified manifest-exists Error jQuery@2.2.4 has 2 known vulnerabilities (1 medium, 1 low). See https://snyk.io/vuln/npm:jquery for more information. no-vulnerable-javascript-libraries line 4 col 21516 Error Protocol relative URL found: //monotalkxyz.disqus.com/count-data.js?1=BlogPost-323&1=BlogPost-324&1=BlogPost-325&1=BlogPost-326&1=BlogPost-327&1=BlogPost-328&1=BlogPost-329&1=BlogPost-330&1=BlogPost-331&1=BlogPost-332 no-protocol-relative-urls line 4 col 21764 Error Protocol relative URL found: //monotalkxyz.disqus.com/count-data.js?1=BlogPost-333&1=BlogPost-334&1=BlogPost-335&1=BlogPost-337&1=BlogPost-338&1=BlogPost-339&1=BlogPost-340&1=BlogPost-341&1=BlogPost-342&1=BlogPost-343 no-protocol-relative-urls line 4 col 22012 Error Protocol relative URL found: //monotalkxyz.disqus.com/count-data.js?1=BlogPost-344&1=BlogPost-345&1=BlogPost-346&1=BlogPost-347&1=BlogPost-348 no-protocol-relative-urls line 5 col 20046 Error Protocol relative URL found: //uh.nakanohito.jp/uhj2/uh.js no-protocol-relative-urls line 5 col 21331 Error Element “ul” not allowed as child of element “ul” in this context. (Suppressing further errors from this subtree.) html-checker line 5 col 21384 Error Protocol relative URL found: //monotalkxyz.disqus.com/count.js no-protocol-relative-urls line 5 col 22996 Error <ul> and <ol> must only directly contain <li>, <script> or <template> elements axe line 16 col 97 Error Element “form” not allowed as child of element “ul” in this context. (Suppressing further errors from this subtree.) html-checker line 16 col 205 Error Form elements must have labels axe line 16 col 310 Error Form elements must have labels axe line 16 col 743 Error Element “p” not allowed as child of element “h1” in this context. (Suppressing further errors from this subtree.) html-checker line 16 col 1002 Error Protocol relative URL found: //pagead2.googlesyndication.com/pagead/js/adsbygoogle.js no-protocol-relative-urls line 16 col 1598 Error Frames must have title attribute axe line 19 col 2149 Warning Text run is not in Unicode Normalization Form C. html-checker line 20 col 7460 Error Elements must have sufficient color contrast axe line 31 col 88 Error Protocol relative URL found: //pagead2.googlesyndication.com/pagead/js/adsbygoogle.js no-protocol-relative-urls line 31 col 684 Error Frames must have title attribute axe line 33 col 10696 Error Links must have discernible text axe line 33 col 10909 Error Links must have discernible text axe line 33 col 11119 Error Elements must have sufficient color contrast axe ✖ Found 22 errors and 1 warning ✖ Found a total of 22 errors and 1 warning
除外ルールを追加
validate-set-cookie-header
、no-protocol-relative-urls
、no-vulnerable-javascript-libraries
は Web UI でのチェック実施時に無視していたので、除外します。
また、manifest-exists
については、PWA 関連の manifest ファイル が存在しないことについての警告ですので、こちらも一旦除外します。
"rules": {
"amp-validator": "off",
"apple-touch-icons": "error",
"axe": "error",
"content-type": "error",
"disown-opener": "error",
"highest-available-document-mode": "error",
"html-checker": "error",
"image-optimization-cloudinary": "off",
"manifest-app-name": "error",
"manifest-exists": "off", // off に設定
"manifest-file-extension": "error",
"manifest-is-valid": "error",
"meta-charset-utf-8": "error",
"meta-viewport": "error",
"no-disallowed-headers": ["error",{ "ignore":["Server"] }],
"no-friendly-error-pages": "error",
"no-html-only-headers": "error",
"no-protocol-relative-urls": "off", // off に設定
"no-vulnerable-javascript-libraries": "off", // off に設定
"ssllabs": "off",
"strict-transport-security": "error",
"validate-set-cookie-header": "off", // off に設定
"x-content-type-options": "error"
},
Web UI で実行する場合との違いについて
推奨ルールを使った場合の Web UI との適用ルールの差分について説明します。
aXe
のチェック、 html-checker
のチェックがかかるため、Web UI とは警告の内容が異なります。
-
aXe のチェックが効いている
2017/10/30
時点では Web UI での aXe のチェックは実施できないようですが、CLI からは実行されており、ログに警告が出力されています。 -
“html-checker” が効いている
Web UI だと、html の妥当性検証はかかっていなかったのですが、CLI ツールで実行すると、チェックがかかるようです。 -
“ssllabs” が “off” になっている
Web UI だと、Qualys SSL Labs
のチェックが行われますが、CLI では推奨ルールで OFF になっています。
これは、イントラネット環境で Glogbal な Domain が割り当てられていない場合、チェックが失敗するからかと思います。 -
“image-optimization-cloudinary” が “off”
cloudinary の api による 画像のサイズチェックも OFF になっています。
これも、イントラネット環境で Glogbal な Domain が割り当てられていない場合、チェックが失敗するからかと思います。
Cloudinary offers support for sonar | Cloudinary Blog -
“amp-validator” が “off”
これは、Web UI でも OFF になっていました。AMP ページの場合は有効にするのかと思います。
警告に対処する
出力された Found a total of 22 errors and 1 warning
に対して対処していきます。
Web UI で無視していた警告は、特に触らず修正は行なっていません。
html checker の警告
以下、出力されていた html checker
の警告になります。それぞれ対処していきます。
-
Error Element “ul” not allowed as child of element “ul” in this context. (Suppressing further errors from this subtree.)
ul の 子要素として ul が使用されているという警告です。
確かに不要な ul がありましたので削除しました。 -
Error Element “p” not allowed as child of element “h1” in this context. (Suppressing further errors from this subtree.)
h1 の 子要素として、p タグが使われているという警告です。
h タグの中に入れていいのはインライン要素のみなので、ブロックタグ である p タグは削除する必要があります。
対象箇所の p タグを削除しました。1 -
Warning Text run is not in Unicode Normalization Form C.
「Text run is not in Unicode Normalization Form C.」というHTML Validation Serviceの警告について: 小粋空間 を見る限りUnicode正規化形式C
ではない文字列が混じっているとこの警告がでるようです。対象箇所をValidator.nu (X)HTML5 Validator で確認したところ、濁点まじりの文字で警告が出ているようでした。
Pythonのunicodedata.normalize(‘NFKC’, x)で正規化される文字一覧 - めもちょう を見ると、unicodedata.normalize
で正規化はできそうなので、後日やってみようかと思います。
axe の警告
続いて、axe
の警告に対処します。
sonar ではエラーとしては認識できますが、実際の修正には、axe
の chrome plugin や、 firefox の plugin を使ったほうが修正作業はしやすいかと思います。
私は以下の chrome plugin を使って修正作業を行いました。
aXe - Chrome ウェブストア
-
Error Form elements must have labels
Form の input タグに label が付与されていないという警告です。
これは Form の デザイン的に入れるのが難しいため、無視しました。 -
Error
<ul> and <ol> must only directly contain <li>, <script> or <template> elements
これは、ul タグ ol タグ の配下に含められない 要素が含まれているという警告です。
html checker
で警告が出ていた ul タグの子要素の ul タグを削除したところ解消されました。 -
Error Frames must have title attribute
Frame タグに、title 属性が付与されていないことを示す警告です。
タイトルがついているとスクリーンリーダが読み上げてくれるようです。
Google Tag Manager の iframe で警告が出ていて、あまり title を設定する意味が感じられず、設定せず無視しました。2,3 -
Error Links must have discernible text
a タグのリンクにリンクテキストがないという警告です。これもスクリーンリーダーの読み上げの対象にならないようです。
リンクテキストを対象箇所には付与できなかったので、a タグに title 属性を付与することで対応しました。 -
Error Elements must have sufficient color contrast
テキストと背景色のコントラストが足りないという警告になります。
再チェックを実行
警告に対処した後、再度チェックを実行したところ、以下の結果になりました。
だいぶ無視しましたが、Found a total of 9 errors and 1 warning
なので、努力の甲斐はあったかと思います。
https://www.monotalk.xyz/
line 16 col 205 Error Form elements must have labels axe
line 16 col 310 Error Form elements must have labels axe
line 16 col 738 Error Element “p” not allowed as child of element “h1” in this context. (Suppressing further errors from this subtree.) html-checker
line 16 col 1593 Error Frames must have title attribute axe
line 16 col 2158 Error Frames must have title attribute axe
line 19 col 2149 Warning Text run is not in Unicode Normalization Form C. html-checker
line 20 col 7460 Error Elements must have sufficient color contrast axe
line 31 col 684 Error Frames must have title attribute axe
line 31 col 1249 Error Frames must have title attribute axe
line 33 col 11168 Error Elements must have sufficient color contrast axe
✖ Found a total of 9 errors and 1 warning
まとめ
sonar, a linting tool for the web の CLIツールを使ってみました。
以下まとめます。
-
Web UI とはチェックルールが異なり、
axe
は CLI ツールでないと現状チェックがかからない。 -
axe
は Chrome plugin と併用したほうがいい。 -
output の形式がいろいろ選択できるので、CIに組み込んで実行ができそう。
-
何回か叩いたが、何故か
html check
でエラーになることがあったり、rule を設定すると outputが微妙に変わったりする。4 -
axe
、 と、html check
初めてで勉強になった。
以上です。
-
HTML 素人だなと我ながら思いました。もっと勉強します。
html 上の p タグ は消すことはできたのですが、blog システムの都合上出る部分もあり、対応することを諦めました。 ↩ -
目が見える人にとっても見えない隠しフレームになっているので、それを読み上げる意図を感じませんでした。 ↩
-
設定している方もいるようです。Tag Manager no JavaScript WCAG 2.0 A / AA Compliance - Google プロダクト フォーラム ↩
-
多少バグっぽい動作はしますが、そんなに問題になるレベルではないかと個人的には思います。 ↩
コメント