去年に ChromeRepl という Google Chrome 拡張を書いた。ChromeRepl は MozRepl のように、外部からたたける口を Google Chrome に空けてくれる。詳しくいうと Chrome には Google Chrome Developer Tools Protocol というプロセス外から制御するためのプロトコルが元々あり、これの上に汎用 eval と console.log などを足すことが ChromeRepl の仕事になる。
最近 Mac むけ Chrome でも beta なら拡張機能が使えるようになったので、今日は ChromeRepl のインストールから、実際どう便利かまでを簡単に説明してみようと思う。
インストール
まずはインストールから。ChromeRepl は核となるサーバー側と、それを便利に使うためのクライアント側にわかれている。
サーバー側は 拡張機能ギャラリー から、クライアント側は gemcutter からインストールできる。
% gem install google-chrome-client Building native extensions. This could take a while... Successfully installed json-1.2.0 Successfully installed google-chrome-client-0.2 2 gems installed Installing ri documentation for json-1.2.0... Installing ri documentation for google-chrome-client-0.2... Installing RDoc documentation for json-1.2.0... Installing RDoc documentation for google-chrome-client-0.2... %
クライアント側、サーバー側はどちらを先にインストールしても問題ない。
使い方
インストールがすんだら Chrome を引数つきで起動する。
% /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-shell-port=9222
次に、ほかのコンソールで chrome-repl を起動して、いろいろ入力してみる。
% chrome-repl Protocol version: 0.1 > chrome.tabs {"onAttached"=>{"eventName_"=>"tabs.onAttached", "listeners_"=>[]}, "onCreated"=>{"eventName_"=>"tabs.onCreated", "listeners_"=>[]}, "onDetached"=>{"eventName_"=>"tabs.onDetached", "listeners_"=>[]}, "onMoved"=>{"eventName_"=>"tabs.onMoved", "listeners_"=>[]}, "onRemoved"=>{"eventName_"=>"tabs.onRemoved", "listeners_"=>[]}, "onSelectionChanged"=> {"eventName_"=>"tabs.onSelectionChanged", "listeners_"=>[]}, "onUpdated"=>{"eventName_"=>"tabs.onUpdated", "listeners_"=>[]}} > chrome.tabs.create({ url: "http://www.google.com/" }) nil >
chrome.tabs.create... で Chrome に新しいタブが開いたはずだ。こんな感じで chrome-repl に入力した JavaScript のコードは、即座に Chrome 上で実行される。
エディタと連携させる
最後にすこし応用。chrome-repl は対話的に使うほかに -e という引数でスクリプトを実行することもできる。
たとえば Emacs と Chrome で、むかし流行った「保存したらリロード」を実行するなら、こんな感じになるだろう。
(defun google-chrome-reload() (if (eq major-mode 'html-mode) (shell-command "chrome-repl -e \"chrome.tabs.getSelected(null, function (t) { chrome.tabs.executeScript(t.id, { code: 'location.reload()' }) });\""))) (add-hook 'after-save-hook 'google-chrome-reload)
if の条件はもう少し考える余地があるけど、そこは本題ではないので、まあ。