練習も兼ねて「艦これタイマー」という Extension を開発しました。
艦これタイマー for Google Chrome™をつくったぞ〜!!!
できるだけ楽をして綺麗にコードを書いていくために使ったツールなどをまとめておきます。
.
|--- bower_components/ -> bower のライブラリ
|--- build/ -> ビルドしたら生成される
|--- images/
|--- node_modules/ -> npm のライブラリ
|--- sounds/
|--- src/ -> メインの coffee はここ
|--- stylesheets/
|--- views/
|--- component.json -> bower の設定ファイル
|--- Gruntfile.coffee -> grunt の設定ファイル
|--- manifest.json -> extension の設定ファイル
|--- package.json -> npm の設定ファイル
Grunt: The JavaScript Task Runner
node.js 製のタスクランナーです。今回は
- grunt-contrib-coffee
- grunt-contrib-jade
- grunt-contrib-stylus
- grunt-contrib-copy
- grunt-contrib-uglify
- grunt-contrib-watch
を使いました。
Javascript を生で書くのはダルいのでもっぱら Coffeescript で書いています。Watch タスクでファイルを監視して、変更があれば即座にビルドをかけます。
grunt.registerTask "c", ["coffee"]
というタスクをつくっておくといざというときも
$ gr c
で息をするようにコンパイルできて便利です。(ちなみに grunt は gr というエイリアスを張っているよ!)
お好みで Typescript でもなんでも。
生の HTML を書くのはめんどくさいので Jade で書きます。これも Coffee 同様 Watch タスクで views/ を監視させて変更を検知したらすぐビルドをかけます。
ejs でもOKだとおもいます。
CSS を直で書くのはダルいので Stylus で書きます。これも Watch タスクで監視して自動でビルドさせます。
Sass や Less でも。
静的なリソースをビルド時にコピーするためのタスクです。manifest.json や bower でインストールしたライブラリなどをこれで build/ にコピーします。
開発時には使いませんが、リリースのときには Javascript を全て圧縮するのでこのタスクを用います。
開発時の build とリリース時の release を用意しておきました。といっても、uglify するかどうかしか変わらないです。
grunt.registerTask "b", ["coffee", "jade", "stylus", "copy"]
grunt.registerTask "build", ["coffee", "jade", "stylus", "copy"]
grunt.registerTask "r", ["coffee", "jade", "stylus", "copy", "uglify"]
grunt.registerTask "release", ["coffee", "jade", "stylus", "copy", "uglify"]
のような感じです。普段は grunt watch で監視をしておいて、クリーンアップするときはビルドしたディレクトリをまとめて消去して build するなり release するなりといった感じで。
BOWER: A package manager for the web
bower はフロントサイドのパッケージマネージャです。フロントサイドでパッケージを管理するという文化がまだあまり浸透していないせいか、レジストリに登録されているものが少ない気はします。といっても Github にリポジトリが有りさえすればインストールできるのでなんとかなります。
DOM が絡んだりすると jQuery なしにはもう書けません。せっかくなのでバージョン2系列を使ってみました。一応アップグレードガイドも見つつ。
jQuery Core 1.9 Upgrade Guide | jQuery
チョー便利ユーティリティ集の Underscore も使っています。
Moment.js | Parse, validate, manipulate, and display dates in javascript.
時間を扱うプロダクトだったので、Moment も使いました。時間の変換などがスッキリできます。
ちょっと使ってみたかっただけです。フラットな感じの CSS ライブラリです。Bootstrap でもいいとおもいます。
今回は規模がさほどでもなかったのでスルーしましたが、大規模な Extension だと Backbone があると混乱を少なく書けるとおもいます。
すっかり忘れていたんですが、Chrome Web Store で Extension を公開するときは Google 先生に $5 のお布施が必要です。Google Wallet があればすんなりと決済できます。
Branding Guidelines - Chrome Web Store — Google Developers
「for Chrome」のように商標がある場合には商標マークをつけなくてはいけないとのことです。
アイコンボタンのところにつけられるバッジは chrome.browserAction.getBadgeText で取得できます。関数名の通り String で返ってくるため、数値でカウンターのように管理したい場合には
updateBadge = (option)->
chrome.browserAction.getBadgeText {}, (badge)->
badge = parseInt(badge)
badge = 0 if isNaN badge
badge += 1 if option is "inc"
badge -= 1 if option is "dec"
badge = "" if badge <= 0
chrome.browserAction.setBadgeText
text: badge.toString()
のようなカウンタ管理関数を用意しておくと必要なときに呼び出すだけでサクッとカウンタを管理できます。
chrome.storage - Google Chrome
manifest.json に Storage の権限を追加すると localstorage が使えるようになります。基本的にはキーバリューストアなので
chrome.storage.local.set
key: "value"
, -> done()
chrome.storage.local.get "key", (item)-> done()
のように set と get で状態を保存します。local を sync に変えるとたぶん別マシンの Chrome でもログインしていればストアを共有できるっぽいです。ちなみに localstorage では暗号化はされていないので設定程度はOKですがID/PASSなんかはご法度とのことです。
この notification が厄介で、
chrome.notifications - Google Chrome
が使えるのかなあ、とおもったら
Currently this API only works on ChromeOS and Windows.
とのこと。なので、
Desktop Notifications - Google Chrome
を使ったのですが、Mac版Chrome28では webkitNotifications.createHTMLNotification が生きているけれど、Windows版Chrome28では丸ごと抹消されてて使えないという状態だった。しかも、上の chrome.notifications が使えるのかとおもったら Chrome29 かららしく使えないっていう。渋々プラットフォーム判定をして Windows とその他で webkitNotifications.createNofitication と webkitNotifications.createHTMLNotification を使い分けるという残念な感じに。ここらへんは書いててキツかった。
chrome.runtime - Google Chrome
chrome.runtime.getPlatformInfo が使えるっぽい感じだったので、使ってみたら使えず。どうやらこれもChrome29かららしい。過酷だ。しょうがないので
if navigator.platform.match /Win/
っていう結構アレな感じになってしまった。
Chrome といえどネイティブの API 叩くような場合、バージョンやプラットフォームの差異は結局デバッグしてみて気付いたり、バッドな感じで対応しなきゃいけないところもある。がんばろう。