> あと、 TJ は「自由にやれよ」みたいなスタンスみたいですw
> が、これをどう扱うかは大事な議論だと思います。
モジュール間を跨ぐ変数の共有方法について作法は気になるところでしたが、未だ無いんですねぇ。
私自身は、未だに express のようなフレームワークに触れず、色々と自前コードを書きながら遊んでる段階なのですので、express
での扱い方は判りませんが、モジュールのスコープを律儀に守る手法ですと
server.js 内でこんな風に書いたものを
exports.HTDOCS_DIR = path.join( __dirname, 'htdocs' );
require() で呼ばれたコード内で参照する時は、こんな感じ。
var HTDOCS_DIR = module.parent.exports.HTDOCS_DIR;
この場合、モジュールオブジェクトが管理する構造を調査しないと、参照できずに面倒に感じていました。。
で、自前のモジュールを擬似的なグローバル変数として扱うというのはどうでしょう?
require() されたモジュールは、moduleオブジェクトで管理され、同じpathのモジュールがrequire()されると、メモリ上で管理中のmoduleを参照する。これを上手く利用すれば自前のモジュールを擬似的なグローバル変数として代用できると思います。
たとえば、MyObjects.js というモジュールを次のように1行だけ書いておき、
[MyObjects.js]
module.exports = {};
require('path/to/MyObjects,js') を書いた全てのモジュールで共有するオブジェクトを保持できる。
var myObj = require( 'path/to/MyObjects.js' );
myObj.hoge = 'hogeValue';
とか、他のモジュールでも参照できる。
JavaSciptなので、生成したインスタンスのメンバですら変更可能という特徴を活かす感じです。
クライアントサイドではオブジェクト汚染などと言われる事を、しっかりと管理しつつ、
意図的に行うことで安全な変数の役割を持たせることができる。というコンセプトです。
他にも
[MyClass.js]
function MyClass(){}
MyClass.prototype.method1 = function(){}
MyClass.prototype.method2 = function(){}
exports.MyClass = MyClass;
のようなモジュールは、こんな風に利用されますが、
var MyClass = require('path/to/MyClass.js').MyClass;
var myClass = new MyClass();
myClass.method1();
myClass.method2();
ここで、
MyClass.hoge = (任意の値)
というように、MyClass.js で定義した MyClass
のスタティックなプロパティにアクセスすることで、モジュールオブジェクト内で管理されるMyClassの内容も変更されるため、他のモジュールからも
(任意の値) を参照できます。
2011年12月28日19:36 兼平 卓史 <takut...@gmail.com>:
On 12月28日, 午後9:58, yusuke kagiwada <block.rxckin.be...@gmail.com>
wrote:
> Jxck です。
>
> takuto1981 さん。
>
> 一番重要なのは、ここですよね?
>
> > [./app.js] : メイン
> > var express = require('express')
> > Events = require('./models/eventSchema');
>
> これは、
> var express = require('express');
> Events = ...;
>
> と
>
> var express = require('express'),
> Events = ..;
>
> では大きく意味が変わってしまいますが、
> 恐らく前者の方で、 プロセス上のどっからでも Events が見えるからっていうのが、
> 最初に言ってた「グローバル変数」だと思って進めます。
>
> このグローバル変数は、恐らくお行儀がいいとは言えないでしょう。
> 普通にバッドパーツと扱われるだろうし、
> Ruby でも「グローバル変数($) は将来無くしたい」などと言われています。
>
> それに、他のライブラリと組み合わせてバッティングなんかしたりしたら、
> デバッグが地獄です。
> モジュールの仕組みが有るから、そちらを使うべきだと自分は思います。
>
> そして実は、そもそも「グローバル変数」やったこと無かったし、出来ること知りませんでした(汗http://twitter.com/#!/hakobera/status/151971594359685120
> 2011年12月28日20:32 Akitoshi Manabe <akitoshi.man...@gmail.com>:
> > 2011年12月28日19:36 兼平 卓史 <takuto1...@gmail.com>:
> > > 2011年12月28日18:36 たくと <takuto1...@gmail.com>:
>
> > >> はじめまして。takuto1981と申します。node.jsをはじめたばかりの初心者です。
> > >> モジュール分割とグローバル変数のお作法についてお聞きしたく、メールしました。
> > >> # まだ右も左も分からない状態なので、用語などに誤りがあれば申し訳ありません。
>
> ...
>
> もっと読む ≫
kysnm と申します。
> [index.js]
> var share = require('../../../../share');
> console.log(share);
>
> となってしまうんですよね。
> 相対パス指定しない場合は、コアモジュールか node_modules しか呼んでくれません。
>
> $ tree
> .
> ├── node_modules
> │ └── share.js
> └── path
> └── to
> └── my
> └── module
> └── index.js
>
> これなら、index.js 内で require('share'); できます。
> でも、 node_modules は npm install したもののみ、という暗黙の了解が有るし、
> 基本 .gitignore に足されます。
この間 npm についてまとめた勢いでの発言ですが、
npm install では package.json を含んだディレクトリも
インストール対象に出来るので以下の様な解決方法もあ
るかと思います。ただファイル構成が冗長なのであまり
きれいではないかと思いますが、、、
$ tree
.
├── mymodule
│ ├── app.js
│ └── package.json
└── test_ml
├── app.js
└── package.json
2 directories, 4 files
$ cat mymodule/app.js
exports.hello = function (msg) {
console.log('Hello, ' + msg);
}
$ cat mymodule/package.json
{
"name": "mymodule",
"version": "0.0.0",
"main": "app.js",
"private": "true"
}
$ cat test_ml/app.js
var socket = require('socket.io');
var mymodule = require('mymodule');
mymodule.hello('Jxck');
$ cat test_ml/package.json
{
"name": "test_ml",
"version": "0.0.0",
"private": "true",
"dependencies": {
"socket.io": "*"
}
}
$ npm install mymodule
mymo...@0.0.0 ./node_modules/mymodule
$ tree
.
├── mymodule
│ ├── app.js
│ └── package.json
├── node_modules
│ └── mymodule
│ ├── app.js
│ └── package.json
└── test_ml
├── app.js
└── package.json
4 directories, 6 files
$ cd test_ml/
$ npm install
npm http GET https://registry.npmjs.org/socket.io
npm http 200 https://registry.npmjs.org/socket.io
npm http GET https://registry.npmjs.org/redis/0.6.7
npm http GET https://registry.npmjs.org/socket.io-client/0.8.7
npm http GET https://registry.npmjs.org/policyfile/0.0.4
npm http 304 https://registry.npmjs.org/redis/0.6.7
npm http 304 https://registry.npmjs.org/socket.io-client/0.8.7
npm http 304 https://registry.npmjs.org/policyfile/0.0.4
npm http GET https://registry.npmjs.org/uglify-js/1.0.6
npm http GET https://registry.npmjs.org/websocket-client/1.0.0
npm http GET https://registry.npmjs.org/xmlhttprequest/1.2.2
npm http 304 https://registry.npmjs.org/uglify-js/1.0.6
npm http 304 https://registry.npmjs.org/websocket-client/1.0.0
npm http 304 https://registry.npmjs.org/xmlhttprequest/1.2.2
sock...@0.8.7 ./node_modules/socket.io
├── polic...@0.0.4
├── re...@0.6.7
└── socket.i...@0.8.7
$ tree -L 4 ../
../
├── mymodule
│ ├── app.js
│ └── package.json
├── node_modules
│ └── mymodule
│ ├── app.js
│ └── package.json
└── test_ml
├── app.js
├── node_modules
│ └── socket.io
│ ├── History.md
│ ├── Makefile
│ ├── Readme.md
│ ├── benchmarks
│ ├── examples
│ ├── index.js
│ ├── lib
│ ├── node_modules
│ ├── package.json
│ ├── support
│ └── test
└── package.json
12 directories, 11 files
$ node app.js
Hello, Jxck
※socket.io は一応インストール出来て、require
出来る事を確認する為だけに利用しています。
これはこれで管理もめんどくさそうですね。
参考程度にお考えください。
2011年12月28日21:58 yusuke kagiwada <block.rxc...@gmail.com>:
--
twitter: https://twitter.com/kysnm
email: tokyoinc...@gmail.com
2011年12月29日3:34 kysnm <tokyoinc...@gmail.com>:
--
----------------------------------------
Name : 外村 和仁
Email : k.hok...@gmail.com
URL : http://webtech-walker.com/
----------------------------------------
ポイントとしては、モジュール間でシェアしたい変数をセットするためのモジュールを作成して、
必要に応じてrequireすることで、(C言語でいうところの)共有メモリ的に使うということですね。
また、expressの場合はそもそも以下のように、各モジュールでexpress.createServer()のインスタンス(?)にアクセスすることが多いので、
express.createServer()を上記の共有用モジュールに置き換えて使用してもいいということですね。
[app.js]
var app = module.exports = express.createServer();
[appを使う各モジュール]
var app = module.exports = module.parent.exports;
手軽さの面ではapp.setのように感じるので、当面はこれを使いながら様子をみてみようと思います。
以下、参考までに両方のパターンで書いたコードの一部を添付します。
まず、app.setを使うパターンです。
[./app.js]
var test = require('./routes/test');
var app = module.exports = express.createServer();
・
・
app.set('Events', require('./models/eventSchema'));
・
・
app.get('/neworder/:id', test.index);
・
・
[./routes/test.js]
exports.index = function(req,res){
var app = module.exports = module.parent.exports;
var Events = app.set('Events');
・
・
var query = Events.find({});
・
・
}
次に、シェア用のモジュールを使うパターンです。
[./app.js]
var test = require('./routes/test');
var app = module.exports = express.createServer();
・
・
var share = require('share.js');
share.Events = require('./models/eventSchema');
・
・
app.get('/neworder/:id', test.index);
・
・
[./routes/test.js]
exports.index = function(req,res){
var app = module.exports = module.parent.exports;
var share = require('share.js');
share.Events = 'Events';
・
・
var query = share.Events.find({});
・
・
}
[./lib/share.js]
// Node.js : exports と module.exports の違い(解説編)
// http://d.hatena.ne.jp/jovi0608/20111226/1324879536
// これを読む限り"module.exports = {};"は明示的に書く必要無さそうだったので、
// 書かずにファイルだけ作成して試してみたところ、問題なさそうです。
とても勉強になりました。皆様、ありがとうございました。
ちょうど似たようなところで どうするのが良いのか考えていたところだったので、興味深かった方法を書いてまとめてみました。
http://d.hatena.ne.jp/sugyan/20120110/1326197416
何か間違い、補足、ご指摘ありましたらお願いします。
2012年1月3日18:06 Muddy Dixon <muddy...@gmail.com>:
--
杉 義宏
sugi...@gmail.com
主題じゃないけど,require() は .json も読めるんだぜ?
var config = JSON.parse(require('fs').readFileSync('config.json'));
↓
var config = require('./config');
http://nodejs.jp/nodejs.org_ja/docs/v0.6/api/modules.html#file_Modules
Java では普通になった DI (Dependency Injection) とか
IoC (Inversion of Control) ってやっぱり便利だよなーと
このスレを見てて思いました.
--
{
name: "Koichi Kobayashi",
mail: "koi...@improvement.jp",
blog: "http://d.hatena.ne.jp/koichik/",
twitter: "@koichik"
}
> var宣言を外すことで、変数がグローバルになる。
global オブジェクト (クライアントサイドの window みたいな) を
明示的に使うこともできます.
config = JSON.parse(require('fs').readFileSync('config.json'));
↓
global.config = JSON.parse(require('fs').readFileSync('config.json'));
http://nodejs.jp/nodejs.org_ja/docs/v0.6/api/globals.html#global
所詮はグローバルだけど,var 付け忘れたんじゃないんだぜ?感が
少しだけあるかも.かも.
koichikさん、ご指摘ありがとうございます!
requireで普通にjson読めたんですね…知りませんでした orz v0.6からですか。
globalオブジェクトを明示的に書くことで、というのもよりハッキリ意図が伝わりますね。
追記しておきます。ありがとうございました。
2012年1月11日0:12 Koichi Kobayashi <koi...@improvement.jp>:
--
杉 義宏
sugi...@gmail.com
エントリポイントのモジュール(app.js)で、各種インスタンス(instanceA)を exports し、
require.main.exports.instanceA でアクセスする、という手法を思いついたのですがいかがでしょう。
テストするときにエントリポイントが変わってしまって面倒、という欠点はあるのですが。
2012年1月11日14:08 Muddy Dixon <muddy...@gmail.com>: