meteorについて

わかってる依存関係

  • underscore
  • git

meteorのbin (/usr/local/bin/meteor)

やってることは、引数をつけて、meteor.js (僕のmac OSXでは/usr/local/meteor/app/meteor/meteor.js)を実行する

exec "$DEV_BUNDLE/bin/node" "$METEOR" "$@"

以降「$METEOR_HOME=/usr/local/meteor」と読んでください。

meteor.js

$METEOR_HOME/lib/files.js

一番最初にrequireしていて、ファイル操作系のutilを提供してる

  • sort
  • pre_filter
  • file_list_async
  • file_list_sync
  • is_app_dir
  • is_package_dir
  • is_package_collection_dir
  • find_upwards
  • find_app_dir
  • add_to_gitignore
  • in_checkout
  • get_dev_bundle
  • get_package_dir
  • get_core_dir
  • pretty_path
  • rm_recursive
  • mkdir_p
  • cp_r
  • mkdtemp
$METEOR_HOME/meteor/deply.js

このファイルの中でdeply先が定義されていて、その他、deploy/delete/mongoの操作が提供されます

var DEPLOY_HOSTNAME = 'deploy.meteor.com'; 

// (略

exports.deploy_app = deploy_app;
exports.delete_app = delete_app;
exports.mongo = mongo;
exports.logs = logs;

exports.run_mongo_shell = run_mongo_shell;

deply_appの中ではbundleメソッドが呼ばれ、tar.gzが作成され、meteor_rpcでdeployされて、その後、tarが削除されます
mongoでは、同じく、meteor_rpcでmongoが呼ばれます。


meteor.jsに戻って

配列Commandsに名前、ヘルプ、関数実装からなる以下のオブジェクトを追加しています

  • run / [default] Run this project in local development mode
  • help
  • create / Create a new project
  • update / Upgrade to the latest version of Meteor
  • add / Add a package to this project
  • remove / Remove a package from this project
  • list / List available packages
  • bundle / Pack this project up into a tarball
  • mongo / Connect to the Mongo database for the specified site
  • deploy / Deploy this project to Meteor
  • logs / Show logs for specified site
  • reset / Reset the project state. Erases the local database.

上記、Commandsを追加したところで、mainメソッドが実行されます。
optimistが使われていて、デフォルトではrunが実行されます。

実際にappを起動するrunメソッド

runメソッドは下記のようになっています。

    var app_dir = require_project("run", true); // app or package
    var bundle_opts = { no_minify: !new_argv.production, symlink_dev_bundle: true };
    require('./run.js').run(app_dir, bundle_opts, new_argv.port);

ちょいちょい出てくる

var app_dir = files.find_upwards(files.is_app_dir);

ですが、これは、process.cwd()を起点として、親ディレクトリに登りながら「.meteor/package」のあるディレクトリ、つまり、app_dirを探す処理です。なければpackageを探したりしていますが、省略します。

app_dirが見つかれば、

require('./run.js').run(app_dir, bundle_opts, new_argv.port)

で実行します。

$METEOR_HOME/run.js

meteorでは、portを4つ使用します。
1つは(outer)webapp用で、これをmeteorの起動時にportとして渡します。2つ目は内部用のportでwebapp用+1を、3つ目がwebapp用+2でmongo用に使います。最後がテスト用でwebapp用+3になります。

meteorのリアルタイムを実現している肝がexports.runの内部の下記2つの関数です。

  • start_watching
  • restart_server

start_proxyでは、httpServerを内向き・外向きで立ち上げ、launchの中では、mongoを立ち上げます。launchの中で一度restart_serverがcallされ、監視が始まります。

start_watching

DependencyWatcherの内部で、fs.watchが実行され、各種meteorのファイルおよびappのファイルが監視対象となります。
変更があった際には、restart_serverが呼び出されることで、リアルタイムな変更を可能にしています。

まとめ

駆け足でしたが、リアルタイムを実現する仕組みを含めて、meteorの内部を調べてみました。
このあとは、coffeeやlessを含めてbundle周りをもう少し見てみたいと思います。