アプリケーションを跨いでプライベートな共通npmモジュールを使う方法

## はじめに
今回、私が試したのはReact、PostCSSを使っているプロジェクトです。基本的に各プロジェクトがGitHubで管理されているものとします。
Reactのバージョンなどは後述の`package.json`をご確認ください。

## 今回やりたいこと

こんな感じで、各アプリケーションにそれぞれcommonが存在してしまっている状態でした。
commonの中には各アプリケーションで汎用的に使えるcomponentやhelperメソッドやutil的なstyleなどが入っています。

```
├─ app_1
|   ├─ admin
|   ├─ user
|   ├─ common
|
├─ app_2
    ├─ admin
    ├─ user
    ├─ common
```

二重管理になってしまっていたcommonを下記のようにプライベートな共通npmモジュールとして使えるようにしたいというのが今回の趣旨になります。

```
├─ common
├─ app_1
├─ app_2
```

## プライベートな共通npmモジュールを作る

`src`の中で開発を進めるようにします。今回はes2015で書いているので、npmモジュールとして使うためにbabelでトランスパイルする必要があります。トランスパイルされたものの置き場所として`public`があります。

```
├─ common
    ├─ public
    ├─ src
        ├─ components
        ├─ helper
        ├─ styles
```

### package.json

はじめに`npm run build`をしたらあとは`npm start`でwatchしながら開発する形になります。

```
{
  "name": "common",
  "version": "0.0.1",
  "description": "",
  "main": "./bundle.js",
  "scripts": {
    "build": "npm run build:babel & npm run build:css",
    "build:babel": "npm run clean && ./node_modules/.bin/babel ./src --out-dir ./public",
    "build:css": "npm run clean && postcss --u postcss-import postcss-cssnext cssnano --dir public/css/ src/styles/**/*.pcss",
    "start": "npm run watch:babel & npm run watch:css",
    "watch:babel": "./node_modules/.bin/babel ./src --out-dir ./public -w",
    "watch:css": "postcss --u postcss-import postcss-cssnext cssnano --dir public/css/ src/styles/**/*.pcss -w",
    "clean": "rimraf ./public"
  },
  "devDependencies": {
    "babel-cli": "6.26.0",
    "babel-core": "6.26.0",
    "babel-eslint": "8.1.2",
    "babel-loader": "7.1.2",
    "babel-plugin-transform-class-properties": "6.24.1",
    "babel-plugin-transform-object-rest-spread": "6.26.0",
    "babel-plugin-transform-react-constant-elements": "6.23.0",
    "babel-plugin-transform-react-remove-prop-types": "0.4.12",
    "babel-preset-es2015": "6.24.1",
    "babel-preset-react": "6.24.1",
    "css-loader": "^0.28.0",
    "cssnano": "^3.10.0",
    "eslint": "4.14.0",
    "eslint-plugin-react": "7.5.1",
    "file-loader": "1.1.6",
    "postcss": "6.0.15",
    "postcss-cli": "4.1.1",
    "postcss-cssnext": "3.0.2",
    "postcss-import": "11.0.0",
    "postcss-loader": "2.0.10",
    "rimraf": "2.6.2",
    "style-loader": "0.19.1",
    "stylelint": "8.4.0",
    "stylelint-config-standard": "18.0.0"
  },
  "dependencies": {
    "babel-polyfill": "6.26.0",
    "classnames": "2.2.5",
    "prop-types": "15.6.0",
    "react": "16.2.0",
    "react-dom": "16.2.0"
  }
}

```

## 各アプリケーションで呼び出す

package.jsonで呼び出しできるようにします。ブランチの指定とか、バージョンの指定もできるみたいです。これにより、こっちのプロジェクトでは、まだAPIの実装できてないから一旦npmモジュールの方のバージョンはあげないでおこうとかできそうな予感。

参照: [package.json | npm Documentation](https://docs.npmjs.com/files/package.json#urls-as-dependencies)

```
{
  "name": "app_1",
  "version": "0.0.1",
  "description": "",
  "author": "",
  "dependencies": {
    "common": "git+ssh://git@github.com:hogeAccount/common.git",
    ・・・
  }
}
```

あとは普通にnpmパッケージを使うのと一緒です。


```
rm -rf package-lock.json // 必要なら
rm -rf node_modules // 必要なら
npm install
npm run build
npm start
```

npmパッケージ使うのと同じなので、例えばcomponentsを使いたければ以下のような感じで使えます。

```
import hoge from 'node_modules/common/public/components/hoge'

<hoge>ホゲホゲ</hoge>

```


## 問題点

ただ、このままだと開発時に問題というかめんどくさい部分があります。というのも、GitHubに上がっているものを使うことになるので`commonリポジトリ`をいちいち`push`してから
アプリケーション側で`npm update`,`npm start`をやり直さなければなりません。ステージングやプロダクションであればそれで問題ないのですが、どうしても開発している時、特に開発の初期段階ではcommonをいじることはどうしても避けられません。(commonという性質上あまり変更が加わるのはあまり良いとは言えないけど・・・)

### 問題点の改善

開発がスムーズに行えるように改善します。

### 1. commonリポジトリをclone
commonリポジトリをローカル環境にcloneします。

### 2. webpackの設定

webpackにてaliasにcommonリポジトリを登録します。ちなみに、開発環境とステージング・プロダクション環境で呼び出しを変えたいので`webpack.config.js`、`webpack.production.config.js`、`webpack.staging.config.js`が必要になります。

#### webpack.config.js

```
・・・
resolve: {
  modules: ["node_modules"],
  alias: {
    common: path.join(__dirname, '../../project-common/public') //任意の相対パス
  }
},
・・・
```

#### webpack.production.config.js, webpack.staging.config.js

```
・・・
resolve: {
  modules: ["node_modules"],
  alias: {
    common: path.join(__dirname, './node_modules/project-common/public')
  }
},
・・・
```

### 3. 開発するときはwatch必須

開発する時には共通npmモジュール側でbabel等でwatchしている状態にしなければ変更を加えても、ブラウザ上に反映されません。

```
npm start
```


これでimportは下記のようにすれば、開発とステージング等で呼び出すモジュールを変えられます。

```
import hoge from 'common/componetns/hoge'

<hoge>ホゲホゲ</hoge>

```


## 最後に

以上、参考になれば幸いです。

また必要に応じて追記・更新したいと思います。