◆ Fetch as Google のクライアントは Chrome 27 のよう
◆ その頃に対応してなかった機能は動かない
◆ そこでエラーになるので JavaScript が全く実行されないときもある 

これの続きです

前回は アロー関数が Google の JavaScript 実行環境だと動かなくてその JavaScript のブロックがエラーになってしまって正しく表示されないことがわかりました

ですが const など ES6 で追加された機能で動くものもあります
Fetch as Google を他人のサイトでも使えれば ECMAScript 6 compatibility table などに試してみれば一覧がわかるのですが そうは行かないので 自分が使いそうな機能を適当にいくつか試してみました


こんな HTML を用意しました
<!doctype html>
<meta charset="utf-8">

<div></div>
<script>
function add(title, contents){
var h1 = document.createElement("h1")
h1.innerHTML = title

var div = document.createElement("div")
div.innerHTML = JSON.stringify(contents, null, "  ")

var hr = document.createElement("hr")

document.body.appendChild(h1)
document.body.appendChild(div)
document.body.appendChild(hr)

}

function tryAndPrint(title, text){
try{
add(title, eval(text))
}catch(e){
add(title, "Error\n" + e.message + "\nstack" + e.stack + "\n")
}
}

tryAndPrint("Map.toString", "Map.toString()")
tryAndPrint("Set.toString", "Set.toString()")
tryAndPrint("fetch.toString", "fetch.toString()")
tryAndPrint("Array.from.toString", "Array.from.toString()")
tryAndPrint("Promise.toString", "Promise.toString()")
tryAndPrint("let", "const l = 1")
tryAndPrint("const", "const c = 1")
tryAndPrint("typeof symbol", "typeof Symbol()")
tryAndPrint("arrow function", "(e => 1)")
tryAndPrint("template", "String.raw `a\nb`")
tryAndPrint("generator", "(function* gen(){})")
tryAndPrint("expo operator", "3 ** 4")
tryAndPrint("for of", "for(var i of [99]) i")
tryAndPrint("async function", "(async function f(){})")
tryAndPrint("default param", "(function(a = 1){})")
tryAndPrint("... operator", "[...[1]]")
tryAndPrint("method definition", "({method(){}})")
tryAndPrint("object initializer", "var oi = 100;({oi})")
tryAndPrint("object key expression", "({['a' + 'b']: 1})")

</script>

Chrome で実行するとエラー無しでこうなります
Map.toString
"function Map() { [native code] }"

Set.toString
"function Set() { [native code] }"

fetch.toString
"function fetch() { [native code] }"

Array.from.toString
"function from() { [native code] }"

Promise.toString
"function Promise() { [native code] }"

let
undefined

const
undefined

typeof symbol
"symbol"

arrow function
undefined

template
"a\nb"

generator
undefined

expo operator
81

for of
99

async function
undefined

default param
undefined

... operator
[ 1 ]

method definition
{}

object initializer
{ "oi": 100 }

object key expression
{ "ab": 1 }

console 出力じゃないので 文字列化するために JSON.stringify してます
その都合で関数は なくなりますが エラーが出てないなら使えていると判断できます


これを Fetch as Google にかけると

search-console10

小さくて見づらいのですが Unexpected token となっているものが多いです

まとめると

Fetch as Google で使える

  • Map, Set, Promise, Symbol 関数
  • let, const 宣言
  • テンプレートストリング (`)
  • generator (function*(){})
  • for-of

Fetch as Google で使えない

  • Array.from 関数
  • アロー関数
  • ** 演算子
  • async 関数
  • 関数のデフォルトパラメータ
  • ... 演算子
  • メソッド定義構文 ({method1(){}, method2(){}})
  • 変数名そのままのキーでオブジェクト作成 ({a, b, c})
  • オブジェクトのキーに式を書く ({[1+1]: 100})




というところ

まだ試してない機能もいろいろですが 使える基準がよくわかりません
polyfill 可能な関数は使えて 構文はダメ ならわかりやすいのですけど for-of や let はつかえますし Array.from は使えません

navigator

もしかすると古い Chrome を使っていて そのバージョンの対応してたものだけかも と思ったので navigator を確認してみました
<!doctype html>
<meta charset="utf-8">

<style>pre{width:600px;white-space:pre-wrap;}</style>
<div></div>
<script>
function add(title, contents){
var h1 = document.createElement("h1")
h1.innerHTML = title

var pre = document.createElement("pre")
pre.innerHTML = JSON.stringify(contents, null, "  ")

var hr = document.createElement("hr")

document.body.appendChild(h1)
document.body.appendChild(pre)
document.body.appendChild(hr)

}

var obj = {}
var navigator_keys = [
"appCodeName",
"appName",
"appVersion",
"cookieEnabled",
"credentials",
"doNotTrack",
"geolocation",
"hardwareConcurrency",
"language",
"languages",
"maxTouchPoints",
"mediaDevices",
"mimeTypes",
"onLine",
"permissions",
"platform",
"plugins",
"presentation",
"product",
"productSub",
"serviceWorker",
"storage",
"userAgent",
"vendor",
"vendorSub",
]
navigator_keys.forEach(function(e){
obj[e] = navigator[e]
})

add("navigator", obj)

</script>

navigators のキー一覧は enumerable:false のようで取れないので 今の Chrome にあるものを直接指定しました

まずは Chrome 56 のときの場合
{
  "appCodeName": "Mozilla",
  "appName": "Netscape",
  "appVersion": "5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36",
  "cookieEnabled": true,
  "credentials": {},
  "doNotTrack": null,
  "geolocation": {},
  "hardwareConcurrency": 8,
  "language": "ja",
  "languages": [
    "ja",
    "en-US",
    "en"
  ],
  "maxTouchPoints": 0,
  "mediaDevices": {},
  "mimeTypes": {
    "0": {},
    "1": {},
    "2": {},
    "3": {},
    "4": {},
    "5": {},
    "6": {}
  },
  "onLine": true,
  "permissions": {},
  "platform": "Win32",
  "plugins": {
    "0": {
      "0": {}
    },
    "1": {
      "0": {}
    },
    "2": {
      "0": {},
      "1": {}
    },
    "3": {
      "0": {},
      "1": {}
    },
    "4": {
      "0": {}
    }
  },
  "presentation": {},
  "product": "Gecko",
  "productSub": "20030107",
  "serviceWorker": {},
  "storage": {},
  "userAgent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36",
  "vendor": "Google Inc.",
  "vendorSub": ""
}

Search Console だと
{
  "appCodeName": "Mozilla",
  "appName": "Netscape",
  "appVersion": "5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)",
  "cookieEnabled": true,
  "doNotTrack": null,
  "geolocation": {},
  "hardwareConcurrency": 1,
  "language": "en-US",
  "languages": [
    "en-US"
  ],
  "maxTouchPoints": 0,
  "mimeTypes": {
    "length": 0
  },
  "onLine": true,
  "platform": "Linux x86_64",
  "plugins": {
    "length": 0
  },
  "product": "Gecko",
  "productSub": "20030107",
  "userAgent": "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)",
  "vendor": "Google Inc.",
  "vendorSub": ""
}

bot という情報しかわかりません

諦めかけたのですが これまで違いがなかった左右で結果が変わっていました
右側の結果はこうなっていました
{
  "appCodeName": "Mozilla",
  "appName": "Netscape",
  "appVersion": "5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko; Google Search Console) Chrome/27.0.1453 Safari/537.36",
  "cookieEnabled": true,
  "doNotTrack": null,
  "geolocation": {},
  "hardwareConcurrency": 1,
  "language": "en-US",
  "languages": [
    "en-US"
  ],
  "maxTouchPoints": 0,
  "mimeTypes": {
    "length": 0
  },
  "onLine": true,
  "platform": "Linux x86_64",
  "plugins": {
    "length": 0
  },
  "product": "Gecko",
  "productSub": "20030107",
  "userAgent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko; Google Search Console) Chrome/27.0.1453 Safari/537.36",
  "vendor": "Google Inc.",
  "vendorSub": ""
}

Chrome27 !


Google ってセキュリティがどうこういう割には古いの使ってるんですね

まとめ

Fetch as Google は Chrome 27 で動いてるのでそのときに使えなかった ES6 以降の機能は使えません

あくまで右側の 「あなたのサイトはこう見えてます」 の方で 「Googlebot はこう認識しました」 の方ではありません
ただ ES6 の対応具合などいくつかのパターンを試してみても navigator 以外は全く一緒の結果なので Chrome 27 と考えて大丈夫かと思います