サンゴラボ

4年目ソシャゲエンジニア

Atomコードリーディング Part 1

目的

GUIアプリのアーキテクチャを学ぶ

最近、SPAやらネイティブアプリやらで、GUIアプリの作成力が求められてる気がする。なので、Atomを教材にしてGUIアプリケーションのアーキテクチャを勉強したいと思った。Atomの実装はいいものと仮定して進めてくけど、まあ大丈夫だと思ってる。昔だったらEclipseNetBeansが勉強になったのかな、とか考えてたけど、自分には辛そう。

あと、アプリケーションのソースコードだけじゃなくて、ビルドとか開発フローとかも見ておけば参考になるんじゃないかと考え中。大規模アプリだとこの辺りも重要ということで。

エッジな技術の使われ方をみる

AtomがReactやらShadow DOMやらを使ってるというのは有名だと思うけど、そういったものがどこでどう使われるのかをちゃんと見ておきたい。Atomでxx使い始めたよ~、と聞いたらすぐに追えるようにしておきたい。Atomならフロントエンドで面白そうなことはだいたい実践してきそうな感じはある。あと、使われてるライブラリとかもその都度調べたい。

自分が使ってるエディタの中身を知る

自分で使ってるエディタの中身を理解して、あわよくば自分で改造してみたい。普段WebStormを使っていたんだけど、最近のフロントエンドの流れについていくにはエディタを自分でいじるしかない、と感じたのも動機のひとつ。ライセンス料払ってるのに常にEAP版使っているのは、ちょっともどかしい。

そんな感じで端からゆっくり読んでいく。見てるソースのバージョンどんどんあがっていくと思う。とりあえずコードリーディング開始時のコミットをメモ。Atomのバージョンでいうとv0.188.0くらい。

ビルド

アプリのソースをみるだけなら、エントリーポイントから見ていけばいいんだけど、ビルド周りも見ておきたいので、ざっくり流れを追っておく。

ビルド方法

ドキュメントに載ってる。とりあえずスクリプト実行すれば、Applications以下にAtom.appができる。

git clone https://github.com/atom/atom.git
cd atom
script/build # Creates application at /Applications/Atom.app

script/build

簡単なjsスクリプトscript/bootstrapを実行して、gruntのbuildタスクを実行している。

script/bootstrapはざっと見たところnpmやapmの依存パッケージをインストールしている。

Gruntfileとしてbuild/Gruntfile.coffeeを指定している。gruntもgulpみたいにCoffeeScriptをサポートしていたんですね。

Grunt

build/Gruntfile.coffee自体にはconfig系を定義してるくらいで、個々のタスクはbuild/tasks/*-task.coffeeなどにある。もうgrunt使ってないけど、タスクの分け方は結構参考になる。

buildタスクはその名の通りbuild/tasks/build-task.coffeeにある。buildタスク自体はcompilegenerate-license:savegenerate-module-cachecompile-packages-slugタスクに依存してる(macならcopy-info-plistタスクにも依存)。

compileタスク自体はGruntfile.coffeeにある。

grunt.registerTask('compile', ['coffee', 'prebuild-less', 'cson', 'peg'])

coffeeタスクだけ確認しておく。

coffeeConfig =
  glob_to_multiple:
    expand: true
    src: [
      'src/**/*.coffee'
      'exports/**/*.coffee'
      'static/**/*.coffee'
    ]
    dest: appDir
    ext: '.js'

appDirmacだと/Applications/Atom.app/Contents/Resources/app/になる。それ以下に出力されたjsファイルが置かれる。

他にもたくさんgruntタスクがあるけど、必要になったら見る。

起動

atomコマンドのシェルスクリプト見たけど、よくわからなかった。まあ、起動はatom-shellがやってくれるはず。

ドキュメント見てたら、atom-shellのチュートリアルにメインプロセスについて書かれていた。

package.jsonmainスクリプトを実行するプロセスがメインプロセス(main process)と呼ばれるみたい。mainには./src/browser/main.jsが指定されてるので、これがエントリーポイントだと考えてよさそう。

メインプロセスから実行されるスクリプトはウェブページを生成することによりGUIを表示できる。

atom-shellはウェブページを表示するのにChromiumを使っていて、ウェブページそれぞれにもプロセスがある。それはレンダラプロセス(renderer process)と呼ばれる。

2つのプロセスの詳細な違いは必要になったら調べる。

src/browser/main.coffee

エントリーポイント。start関数が定義されていて、それが実行される。

start関数でやってること

CoffeeScriptのキャッシュは特に追ってない。coffee-cashというものを使っていた。キャッシュディレクトリを指定して登録しておけばファイル単位でキャッシュしてくれるみたい。なんか便利そう。

コマンドライン引数のパースはsubstack氏のoptimistというライブラリでやってた。便利そうなので、コマンド作るときに使ってみたい。開発時に使えそうなコマンドオプションにdevモードがある。コマンドオプションの使い方がわからなかったら、この辺り読めばすぐわかりそう。

appモジュールというのはatom-shellアプリケーションのライフサイクルをコントロールするやつみたい。ライフサイクル系のイベントの発火もしてくれる。ここではreadyイベントはハンドラを設定してる。readyはその名の通りatom-shellの初期化が終わったところで発火する。

readyハンドラではsrc/browser/atom-applicationをrequireして、それのopenメソッドを呼んでる。いよいよ始まりといった感じがする。

app.on 'ready', ->

  # ~ 省略 ~

  if args.devMode
    AtomApplication = require path.join(args.resourcePath, 'src', 'browser', 'atom-application')
  else
    AtomApplication = require './atom-application'

  AtomApplication.open(args)
  console.log("App load time: #{Date.now() - global.shellStartTime}ms") unless args.test

最初に頑張っても続かないので、続きはあとで


参考