Subscribed unsubscribe Subscribe Subscribe

[js][chrome] dotjsの仕組み

Githubのdefunktさんが作ったdotjsというchrome extensionがよさげだったので、ちょっと中身を見てみた。
簡単に説明すると、~/.js/にホスト名.jsファイルをおいておくとそのホスト名にマッチするURLを開いたときにページにホスト名.jsを適用してくれる。~/.js/配下にuserscriptが一元管理されるので非常に便利な拡張です。
インストール方法や、使い方は公式ページで。今のところOSX限定です。http://defunkt.io/dotjs/

仕組み

djsd
#!/usr/bin/env ruby

if (%w( -h --help -help help ) & ARGV).length > 0
  puts "usage: djsd [-hv]"
  puts "starts dotjs server in the foreground. kill with ^C"
  exit
end

if ARGV.include?('-v')
  puts "djsd 1.3"
  exit
end

require 'webrick'

dotjs = Class.new(WEBrick::HTTPServlet::AbstractServlet) do
  def do_GET(request, response)
    file    = File.expand_path("#{request.path.gsub('/','')}")
    default = File.expand_path("default.js")

    body = "// dotjs is working! //\n"
    body << File.read(default) + "\n" if File.file?(default)
    body << File.read(file) if File.file?(file)

    response.status = body.empty? ? 204 : 200
    response['Access-Control-Allow-Origin'] = '*'
    response['Content-Type'] = 'text/javascript'
    response.body = body
  end
end

server = WEBrick::HTTPServer.new(:Port => 3131)
server.mount('/', dotjs)

%w( INT TERM ).each do |sig|
  trap(sig) { server.shutdown }
end

server.start

localhost:3131にwebrickでサーバーを立てます。chromeでwebを開くたびにこのサーバーにリクエストを送ります。この辺ちょっと富豪な感じが少し気になりますが、実際使って見ても体感速度は問題ありません。
default.jsというファイルを用意するとそれも読み込んでくれるのでこの中に便利ライブラリなんかを入れておくといいかもしれません。
greqsemonkeyのGM_*対応みたいな物を入れておくと過去の資産が流用できて便利かも知れません。 https://gist.github.com/1000836

manifest.json
{
  "name": "dotjs",
  "version": "1.3",
  "description": "~/.js",
  "icons": { "48": "icon48.png",
            "128": "icon128.png" },
  "content_scripts": [{
    "all_frames": true,
    "run_at":     "document_start",
    "matches":    ["http://*/*", "https://*/*"],
    "js":         ["jquery.js", "dotjs.js"]
  }],
  "permissions": [
    "tabs"
  ]
}

jquery.jsを呼んでいるので、~/.js/配下のuserscriptはjqueryが使えます。これはちょろっとしたスクリプト書くのにjqueryが使えるので便利です。

dotjs.js
$.ajax({
  url: 'http://localhost:3131/'+window.location.host.replace('www.','')+'.js',
  dataType: 'text',
  success: function(d){
    $(function(){ eval(d) })
  },
  error: function(){
    console.log('no dotjs server found at localhost:3131')
  }
})

host.replace('www.', '') + 'js'なのでhttp://www.google.comならgoogle.com.jsになります。
要するに~/.js/以下に用意するスクリプトはhost名までのマッチしかできません。http://hoge.com/foo/*にマッチするスクリプトを書きたくてもhttp://hoge.com/*にマッチするスクリプトしか書けない訳です。このへんがちょっといまいちだなぁと思っています。
例えば、先日書いたhttp://d.hatena.ne.jp/samurai20000/20110701/1309482139のスクリプトだとgoogle calenderのURLはhttps://www.google.com/calendar/*なのですが、google.comに適用するスクリプトしか書けません。スクリプトの中でpathnameでmatchするしかないので、こんな感じに書かなければなりません。https://gist.github.com/1067459

if (window.location.pathname.match(/^\/calendar\//) != null) {
    $('div.onegpad').hide('fast');
    $('#srreg').css({'top': '10px'});
    $('#vr-proto-header').css({'height': '48px'});
    $('div.domainlogoparent').css({'height': '48px'});
    $('div.domainlogo').html(function() {
        return '<img onmousedown="_SR_backToCalendar();return false;" src="' + IMG + '" alt="Google"></img>'
    });
}