こんにちはほそ道です。
今回はnodeモジュールについて備忘録的に書き倒したいと思います。
モジュール
Node.jsではrequire('モジュール')
という文法を使って機能拡張を行います。
ブラウザのJSでは<script>タグ
を使って外部JSを読み込んで利用する事ができますが、
こちらは外部ファイルを読み込んで使用するにはrequire
を使用します。
組み込みでいくつかの コアモジュール と呼ばれるモジュール群が提供されています。
コアモジュールはインストール後はビルド済みのバイナリになっており、
いままでの記事で登場したfs
やevents
はコアモジュールです。
ソースや一覧を確認する場合はgithubの./libを参照しましょう。
その1:簡単なサンプルモジュールのロード
早速、自作のモジュールを作り、ロードしてみようと思います。
下記のような構成です。main.jsがnode_modules/my_math.jsをロードします。
.
├── main.js
└── node_modules
└── my_math.js
console.log('module load!');
var myMath = {};
myMath.double = function(n) {
return n * 2;
};
myMath.square = function(n) {
return n * n;
};
module.exports = myMath;
var myMath = require('my_math');
console.log(myMath.double(8));
console.log(myMath.square(8));
とりあえず実行してみましょう。
$ node main.js
module load!
16
64
ポイント
require('my_math')
の結果、node_modules/my_math.jsに記述されたconsole.log('module load!');
が実行されます。
そしてmodule.exports
に代入されたオブジェクトがrequire('my_math')
の戻り値として返ります。
ちなみにmodule.exports
に代入せずに宣言した変数や関数は外部から呼び出す事は出来ません。
node_modulesはマジックディレクトリです。ここに宣言されたモジュールはパスの指定を省略して検索されます。細かいルールは下記にまとめます。
その2:ディレクトリ形式のモジュールでもっとパッケージライクに
その1のファイルを指定するやり方だけではモジュールが複雑化してきた場合の整理が大変そうです。
そこで、構造的にモジュールを管理できるディレクトリ形式のモジュールを作ってみましょう。
下記のような構成です。
やはりmain.jsがmy_mathモジュールをロードします。
.
├── main.js
└── node_modules
└── my_math
├── index.js
├── lib
│ └── my_math.js
└── package.json
{
"name": "my_math",
"version": "0.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
console.log("call index.js");
module.exports = require('./lib/my_math.js');
node_modules/my_math/lib/my_math.jsの中身はその1で登場したmy_math.jsと全く同じにします。
console.log('module load!');
var myMath = {};
myMath.double = function(n) {
return n * 2;
};
myMath.square = function(n) {
return n * n;
};
module.exports = myMath;
main.jsの中身もその1で登場したmain.jsとまったく同じにします。
var myMath = require('my_math');
console.log(myMath.double(8));
console.log(myMath.square(8));
$ node main.js
call index.js
module load!
16
64
ポイント
main.js内のrequire('my_math');
がコールされると、
node_modules
ディレクトリからpackage.json
が検索されます。
さらにpackage.json
のmainキーの値に指定されたindex.js
が実行されます。
今回はお作法的にpackage.jsonには入り口としてのindex.jsを指定しています。
そこから外部のOSや環境に合わせたモジュールを返すようにすると環境スケールできる、という想定にしてみています。
それではモジュールのロードルールを下記にまとめます。
モジュールのロードルール
モジュールのローディングにはいくつかのルールがあるのでまとめておきます。
- .jsファイルを指定する場合は拡張子の.jsはあっても無くても良い
- json形式のファイルをロードする事も出来、配列内にオブジェクトとして要素が格納される
- ロードするファイルはパスで指定する方法と、パスを指定しない自動探索方式がある
- パス指定は絶対パスでも相対パスでも可
- 自動探索方式は下記のようなルールがある
- カレントディレクトリの
node_modules
ディレクトリから名前の合致するモジュールを探す - カレントディレクトリに
node_modules
が存在しなければ、親ディレクトリをたどってnode_modules
ディレクトリを探し、あればそこから名前の合致するモジュールを探す -
環境変数NODE_PATH
で指定されたディレクトリから名前の合致するモジュールを探す -
$HOME/.node_modules
ディレクトリから名前の合致するモジュールを探す -
$HOME/.node_libraries
ディレクトリから名前の合致するモジュールを探す -
/usr/local/lib
ディレクトリから名前の合致するモジュールを探す
- カレントディレクトリの
- 指定モジュール名にはディレクトリを指定する事ができる
- 指定ディレクトリの
package.json
のmainフィールドに記述されたモジュールをロードする -
package.json
が存在しなければindex.js
ファイルをロードする -
index.js
ファイルが無ければindex.node
ファイルをロードする。無ければ例外発生。
- 指定ディレクトリの
npm
モジュールの基本は大体網羅出来ました。
こんどはモジュール機能に即して作られたパッケージ管理ツール npm を見て行きます。
npmはnode v0.6.3から標準パッケージとして提供されており、nodeインストール時に併せてインストールされます。
npmを使うと第三者が作成したサードパーティモジュールを使う事が出来ます。
npmのインストール方式には現在のプロジェクトのみで使用するローカルインストールと、PC全体で使用するグローバルインストールがあります。
ローカルインストール
さっそくサードパーティモジュールをインストールしてみましょう。
今回は試しにasyncという非同期の制御構造を提供してくれるモジュールを入れてみます。
プロジェクトディレクトリに入って下記のコマンドを実行します。
$ npm install async
npm http GET https://registry.npmjs.org/async
npm http 200 https://registry.npmjs.org/async
async@0.8.0 node_modules/async
node_modules/asyncディレクトリにインストールされました。
構成を見てみましょう。
.
└── node_modules
└── async
├── LICENSE
├── README.md
├── component.json
├── lib
│ └── async.js
└── package.json
package.json
が存在しておりモジュールの仕組みに即していますね。
それではmain.jsを作成し、利用してみます。
配列のそれぞれの値を2乗して表示します。
var async = require('async');
var list = [1,2,3,4,5]
var square = function(n, callback) { callback(null, n * n); };
var finish = function(err, result) { console.log(result); };
async.map(list, square, finish);
$ node main.js
[ 1, 4, 9, 16, 25 ]
うまく動いてくれました。
グローバルインストール
PC全体からモジュールを使用する場合はグローバルインストールを使います。
やり方は-gオプションをつけます
sudo npm install -g async
Password:
npm http GET https://registry.npmjs.org/async
npm http 200 https://registry.npmjs.org/async
async@0.8.0 /usr/local/lib/node_modules/async
/usr/local/lib/node_modules/
にインストールされました。
ここはモジュールのローディングルールでも触れた部分で、必ず参照されるディレクトリです。
ローカルモジュールがあればそちらが優先されますが、無ければ最終的にはココが参照されます。
依存モジュールの登録
npm install hoge --save-dev
package.jsonのdevDependenciesに依存関係のあるパッケージとそのバージョンが登録されます.
最後に
パッケージの仕組みはそんなに複雑なものではないですが
知らないと混乱してしまいがちなので基本的な情報をまとめてみました。
モジュールロードの仕組みはEcmaScript6の仕様にも組み込まれたようですし、
ブラウザもサーバも問わず、今後の為には押さえておいた方が良さそうです。
ブラウザに実装された場合も「どこからどこまでがこの部品」というカテゴリーの判別という意味では充分機能すると思います。
今回もお付き合いいただきありがとう御座いました。
次回はWebサービスを爆速で提供してみようと思います。