2.2 Node JSのモジュールシステムとパターン

# 2.2.1 公開モジュールパターン
JavaScriptは「ネームスペース」が存在しないので、グローバルな変更が容易です。これを回避するために使うパターンが「Living Module Pattern」です。

```javascript:test.js
const module = (() => {
  const privateFoo = () => {...}
  const privateBar = () => []

  const exported = {
    publicFoo: () => {...},
    publicBar: () => {...}
  }
})()
console.log(module)
```
JavaScriptがプライベートなスコープを形成するという性質を利用して、必要なものだけ公開します。

# 2.2.2 Node JSモジュールシステムの詳細
## 2.2.2.1 自作のモジュールローダ
```javascript:test.js
function loadModule(filename, module, require) {
  const wrappedSrc = `(function(module, exports, require) {
    ${fs.readFileSync(filename, 'utf8')}
  })(module, module.exports, require)`
  eval(wrappedSrc)
}

const requireMine = (moduleName) => {
  console.log(`RequireMine invoked for module: ${moduleName}`)
  const id = requireMine.resolve(moduleName)

  if (requireMine.cache[id]) {
    return requireMine.cache[id].exports
  }

  const module = {
    exports: {},
    id: id
  }

  requireMine.cache[id] = module

  loadModule(id, module, requireMine)

  return module.exports
}
requireMine.cache = {}
requireMine.resolve = (moduleName) => {
  // モジュール名を完全な識別子に変換する。
}
```
※evalとは、引数に指定した文字列をJavaScriptプログラムコードとして評価・実行する機能をもつ関数です。
security holeを作ってしまうので、気をつけてください。

## 2.2.2.2 モジュールの定義
```javascript:test.js
const dependency = require('./anotherModule')

function log() {
  console.log('Well done ${dependency.username}')
}

module.exports.run = () => {
  log()
}
```
module.exportに代入されない限りモジュールないの全ての変数が非公開になります。

## 2.2.2.3 グローバル変数の定義
globalオブジェクトに定義されたプロパティは、自動的にグローバル変数／関数として参照可能となります。しかし、モジュールシステムのカプセル化の利点を損なうので、一般的には使わないです。

## 2.2.2.4 module.exportsとexportsの使い分け
単純に新しいプロパティ追加

```javascript:test.js
exports.hello = () => {
  console.log('Hello')
}
```
誤ったコード

```javascript:test.js
exports = () => {
  console.log('Hello')
}
```
exportsに何か入れたい時には

```javascript:test.js
module.exports = () => {
  console.log('Hello')
}
```

## 2.2.2.5 requireは同期関数
require()関数は同期関数なので、module.exportsオブジェクトへの操作も同期的に行われる必要があります。
→requireで呼ばれるモジュールの定義は同期処理として実装するしかありません。

## 2.2.2.6 依存解決
```
myApp/
  foo.js
  node_modules
     depA
        index.js
     depB
        bar.js
        node_modules
          depA
            index.js
     depC
        foobar.js
        node_modules
          depA
            index.js
```
・/myApp/foo.jsからrequire('depA')を呼び出した場合
→/myApp/node_modules/depA/index.jsをロードする
・/myApp/node_modules/depB/bar.jsからrequire('depA')を呼び出した場合
→/myApp/node_modules/depB/node_modules/depA/index.jsをロードする
・/myApp/node_modules/depC/foobar.jsからrequire('depA')を呼び出した場合
→/myApp/node_modules/depC/node_modules/depA/index.jsをロードする

このような呼び方で依存地獄を解決します。

## 2.2.2.7 モジュールのキャッシュ
パフォーマンス上不可欠ですが、次の天に注意してください。
・キャッシュによりモジュールの循環参照が可能になる。
・あるパッケージ内で同じモジュールが複数回requireされた場合、それらは同じインスタンスを参照する。
・require.cacheのキーをdeleteして、キャッシュを削除することも可能だが、しないほうがいい。

## 2.2.2.8 モジュールの循環参照
```javascript:a.js
exports.loaded = false;
const b = require('./b')
module.exports = {
  bWasLoaded: b.loaded,
  loaded: true
}
```

```javascript:b.js
exports.loaded = false;
const a = require('./a')
module.exports = {
  aWasLoaded: a.loaded,
  loaded: true
}
```

```javascript:main.js
const a = require('./a')
const b = require('./b')
console.log(a)
console.log(b)
```
結果

```
{ bWasLoaded: true, loaded: true }
{ aWasLoaded: true, loaded: true }
```
→キャッシュの影響

# 2.2.3 モジュール定義におけるパターン

参考文献
[Node.jsデザインパターン 第2版 - Mario Casciaro (著), Luciano Mammino (著), 武舎 広幸 (翻訳), 阿部 和也 (翻訳)](https://www.amazon.co.jp/Node-js%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3-%E7%AC%AC2%E7%89%88-Mario-Casciaro/dp/4873118735)