1. 使い分け
-
exports
は const だと思った方が良い (常にexports.hoge = fuga;
の形で使う) -
module.exports
は自由 - モジュール内で併用しない
これらの条件を守っていれば、どちらを使っても同じ。
class をまるっと入れたいときは module.exports
になる。
2. 仕組み
イメージ
let a = {}; /* module.exports */
let b = a; /* exports */
//
b.foo = 'foo';
//
a = {bar: 'bar'}
//
return a;
-
b
に新しいオブジェクトを入れても反映されない -
a
に新しいオブジェクトを入れるとb
が無視される - どちらも新しいオブジェクトを入れなければ両方反映 (でも、統一したほうが見やすい)
参考「exports と module.exports の違い - Qiita」
参考「Node.js : exports と module.exports の違い(解説編) - ぼちぼち日記」
3. 循環参照の対策
以下のいずれか。
-
module.exports
の参照を破壊しないで使う -
exports
を使う ( = 参照を破壊しない) -
module.exports
の参照をrequire()
前に書き換える - ソースコードの先頭ではなく使うときに
require()
- 「依存性の注入 (Dependency injection)」
参考「exports と module.exportsの使い分け - Qiita」
参考「webpackなどでCommonJSモジュール循環参照を回避する方法 - Qiita」
参考「node.jsにおける循環参照に対処するための3つの方法 - Qiita」
4. おまけ
exports
だけでなく module
も似た感じなので、オブジェクトをまるっと入れるとまずい。
(module = {exports: {hoge: fuga}};
は意味がない)
require() 疑似コード
function require(/* ... */) {
const module = { exports: {} };
((module, exports) => {
// ... モジュールのコード
})(module, module.exports);
return module.exports;
}
参考「exports shortcut - Modules | Node.js v9.6.1 Documentation」