Hammerspoon と Karabiner Elements でキーカスタマイズした
新しいMacBook Proが届いたんだけど、Karabiner(旧 KeyRemapForMacBook)が動かない。そこで、Karabiner 使えない対策: Hammerspoon で macOS の修飾キーつきホットキーのキーリマップを実現する - Qiitaを参考にしながら、以前のMacBookでおこなっていた「Vim のインサートモードから抜ける時にIMEを英数に切り替える」というのをHammerspoonとKarabiner Elementsで実現した。
Karabiner Elementsで、EscをF13にリマップした後に、以下のHammerspoonのluaスクリプトを書いた。Control + Shift + ; はGoogle日本語入力で英数に切り替えるショートカット。
local function keyCode(key, modifiers) modifiers = modifiers or {} return function() hs.eventtap.event.newKeyEvent(modifiers, string.lower(key), true):post() hs.timer.usleep(1000) hs.eventtap.event.newKeyEvent(modifiers, string.lower(key), false):post() end end local function keyCodeSet(keys) return function() for i, keyEvent in ipairs(keys) do keyEvent() end end end local function remapKey(modifiers, key, keyCode) hs.hotkey.bind(modifiers, key, keyCode, nil, keyCode) end remapKey({}, 'f13', keyCodeSet({ keyCode('escape', {}), keyCode(';', {'ctrl', 'shift'}) }))
気持ちよく作業するために致し方ないのだけど、なんか面倒くさいね... Hammerspoon、luaスクリプトを書くことでウィンドウをリサイズしたり、メニューバーに何か出したりとか、結構色々なことが実現できるようなので、時間があったらもうちょっと遊んでみたい。
おまけで、上のスクリプトを書くために、入力しているキーを調べたくなって、以下のようなluaスクリプトも書いたので乗っけておく。モードを用意して、そのモードに切り替えると入力したキーの内容がアラートとして表示される。
local function showKeyPress(tapEvent) local charactor = hs.keycodes.map[tapEvent:getKeyCode()] hs.alert.show(charactor, 1.5) end local keyTap = hs.eventtap.new( {hs.eventtap.event.types.keyDown}, showKeyPress ) k = hs.hotkey.modal.new({"cmd", "shift", "ctrl"}, 'P') function k:entered() hs.alert.show("Enabling Keypress Show Mode", 1.5) keyTap:start() end function k:exited() hs.alert.show("Disabling Keypress Show Mode", 1.5) end k:bind({"cmd", "shift", "ctrl"}, 'P', function() keyTap:stop() k:exit() end)
Charlesの Map Local のバグ?を Map Remote で回避する
題の通りなんだけど、すぐに忘れそうなので個人用メモ。
Debugging Proxy の Charles には、Map Local という特定の通信のレスポンスボディをローカルファイルで置き換える機能がある。production のサーバーで配信している script や画像に問題があって、原因の特定をおこなうときに便利。
で、この Map Local、script でやっているとちょいちょい構文エラーが起きることがあって、調べてみると、やたら長い行があると途中でぶった切っているようだった。そんなやたら長い行になるのが問題なのでは、と突っ込まれそうだが、Browserify でビルドしたり、Uglifyをかけたりとやっていると1行が長くなることはよくある。
困って途方に暮れていたんだけど、Map Local していたファイルを配信するサーバーをローカルで適当な方法で立てて、そのサーバーに対して Map Remote すれば回避できることに気づいた。
CharlesのMap Local、やたら長い行とかあると途中でぶった切るバグがあるっぽくて困ってたんだけど、ローカルサーバー用意してMap Remoteすれば回避できることに気づいた
— きたけー/Keisuke KITA (@kitak) November 6, 2016
Browserify を使ったプロジェクトでファイルサイズを大きくしているライブラリを探す
azuさんのQiitaの記事をなぞっただけなんですが、便利だったのでメモ。
きっかけ
Browserify でバンドルされるファイル(未圧縮)のサイズが気づいたらIMを超えていて、どのライブラリがボトルネックになっているのか調べることに(個人的にPCだと1M, SPだと300kを超えたらサイズを見直すようにしている)。
調べる手順
- browserify の
full-paths
オプションを有効にしてビルドする。上の記事だとコマンドのオプションとして指定していますが、JS APIでも指定可能なので gulp や grunt plugin でも問題ない。 - ビルドされたファイルを discify に食わせて、ブラウザで可視化された依存関係を眺めて、ボトルネックとなっているライブラリを探す。
cat bundle.js | discify —open
こんなかんじで可視化される(アニメーションでけっこう酔う)
減らす
調べてみたら lodash がけっこうな割合を占めていたんですが、実際に使っている関数は片手で数えるぐらいだったのと、lodash は関数ごとにパッケージを分割してnpmに公開されているので( https://www.npmjs.com/browse/keyword/lodash-modularized )、lodash を丸ごと使わずに必要な関数のパッケージをインストールして使うことにしました(自分で書いちゃってもよさそうですが)。 これで約400k減らすことができました。
他にも core.js とか moment がけっこうな割合を占めているという印象。なんとかして減らせないかな。
世界のドキュメンタリー オバマのホワイトハウス を見た
見た。
4回に分けて、オバマ政権8年の軌跡を描くドキュメンタリー。 リーマンショック、医療保険改革、中東の春、シリア問題、ISの台頭、銃規制、移民制度改革といった国内外の問題に大統領が立ち向かう様子を取り上げている。
演説の名手の民主党の大統領。リベラルな政策で保守派とぶつかり、下院の多数派が共和党になり妥協を強いられる。昔見た「The West Wing」というポリティカルな海外ドラマと重なる。巧みな言葉使いで人々をリードし、大胆かつ粘り強く物事を進めていく、本当に何かの映画かドラマを見ているような気持ちになるドキュメンタリーだった。
依存する npm パッケージのバージョンを上げ続けるために ci-npm-update を導入した
題の通りなんですが、導入。
プロジェクトが依存する npm パッケージのバージョンを上げるのを、忙しさにかまけてサボりがちになっていた。意識が低くてもいいかんじにできないかなぁ、と思っていたところ、ci-npm-update を見つけた。
GitHub - bitjourney/ci-npm-update: Keeps npm dependencies up-to-date, making pull-requests from CI
npm-shrinkwrap.json
(Ruby の Bundler でいう Gemfile.lock
に相当するもの) を再生成して差分があったら、GitHub に PullRequest を出してくれるコマンド。PullRequest には、パッケージのリポジトリの Compare View の URL が書かれていて、バージョン間でどんな変更があったかすぐ確認できて便利。
今のところ、Jenkins で週に1回程度 ci-npm-update を実行するジョブを実行させて、差分を確認したり、自動化テストが通るか、手元で動かして問題ないか調べて、良さそうだったらマージ。その後、テストエンジニアの人が週に1回おこなっているリグレッションテストで問題がないか確認してもらっている。
ただ、package.json
に書かれた範囲内でしかアップデートできないので、ライブラリのメジャーバージョンアップがあった場合は気づけないのが難点。それは半月に一回くらい、npm outdated
や npm-check-updates
の出力を通知したり、package.json
の dependencies
や devDependencies
を更新する PullRequest を出させると良いのかなぁ、とぼんやりと考えている。
JavaScript のメモリや GC を扱った記事のメモ
JavaScript のメモリ や GC を意識したプログラミングに関する記事をふたつばかり読んだので、個人用のメモ。
- V8 が minor GC を実行するときは 10ms オーダーの時間がかかる。
- 60fps を実現する場合の 1フレームは 16ms であるから、GC が頻発すると全体の fps が低下し、表示のかくつきや操作の違和感に繋がる。
- GC が発生するのは大量のオブジェクトの生成・破棄を繰り返したときだから、事前にオブジェクトを生成しておいてそれを使い回せばいい。(オブジェクトプール)
- 万能ではない。初期化に時間がかかるし、大してオブジェクトを作らない場合でもメモリを無駄に使用することになる。また、その無駄なメモリを解放するタイミングが難しい。
- ( モバイルの場合は、大量のメモリの使用がバッテリーの著しい消費に繋がるから、滑らかな UI を実現することとのトレードオフな気がする )
- (どこで聞いたか忘れたけども、React は生成したインスタンスをプールするutil関数を定義している react/PooledClass.js at 19b8eadb242054e2668cf90e83490ef552bcdbfe · facebook/react · GitHub )
- ( 話がズレるが、↑のコードで引数の個数毎に関数を定義しているのは apply よりも call のほうがパフォーマンスが良いため )