npm moduleを作成してローカル環境とgithubでprivateに使う
同じコードを複数のアプリでそれぞれ持つと、修正をアプリ毎に行わなければならず面倒である。そこで各アプリで共通して使えるコードをnpmモジュールとして切り出し、一元管理を行いたい。本ページでは
- npmモジュールの作成方法
- npmモジュールをローカルから取り込む方法
- npmモジュールをgithub private repositoryにpushして、取り込む方法
を試してみる。
npmモジュールを作成
sayHello関数のみを持つmoduleAを取り込み、その関数を叩くだけのappAを作成する。コンソールろぐに"Hello World"が出力されたら終わり。
まず最初に大元のアプリappAを作成する。
appAを作成
$ mkdir appA
$ cd appA
$ npm init
これでpackage.jsonだけまず作成される。package nameはappa
としておく。
moduleAを作成
同様の方法でmoduleAも作成。package nameはmodulea
としておく。ちなみに最後のaは大文字にしたかったが、package名は小文字にしろと怒られてしまう。
また、index.jsも作成しておく。package.jsonに"main": "index.js"
という記述があるが、index.jsがモジュールをロードする時のエントリーポイントとなる。すなわちappAからmoduleAを利用する時はappAのindex.jsを参照することになる。
index.jsはnodeのcommonJSの記法で次のようにsayHello関数をexportする。
module.exports = {
sayHello: () => {
console.log('Hello World');
}
};
これでnpmモジュールは完成である。index.jsとpackage.jsonのみ。
npm install 相対pathでローカルのnpmモジュールを取り込み
npmモジュールの取り込みは簡単で下記のコマンドをappAのrootで叩くだけである。
$ npm install ../moduleA
するとpackage.jsonにdependenciesが追加されて下記のようになる。
{
"name": "appa",
"version": "1.0.0",
"description": "just say hello from module",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"modulea": "file:../moduleA"
}
}
また、node_modules以下にmoduleaが取り込まれていることも確認できる。
実際に使えるかを確認するためappA側のindexjs側に下記を記述
const moduleA = require('modulea');
moduleA.sayHello();
nodeコマンドを叩いてみると無事Hello Worldが出力される事が確認できた。
$ node index.js
Hello World
.npmignoreが効かない点は注意
ブラックリスト形式で、npm installする時に不要に含まれてしまうファイルを除いてくれる.npmignore
というファイルがある。
通常、このファイルをmoduleのルートディレクトリにおいておけばよろしく不要ファイルを除いてinstallを行ってくれるのであるが、localからinstallする時は上手く行かなかった。
これはStack Overflowでも質問として上がっている。バグなのか、仕様なのかはよく分からないが気を付けよう。ちなみに次に紹介するnpm link
でもこの問題は同様である。
-
.npmignore
がローカルモジュールのnpm iで無視される件
Load an npm package from local directory without copying unnecessary files/folders such as node_modules -
npm linkで同様に
.npmignore
が無視される件。まあnpm linkは単にシンボリックリンクなので当然と言えばその通りだが。
npm link does not care for “files” in package.json or .npmignore
ローカルモジュールのアンインストールはmodule名で
インストールの逆で、npm uninstall ../moduleA
としてもアンインストールはできない。module名を直接していしてアンインストールを行ってやろう。
$ npm uninstall modulea
これでnode_module及びpackage.jsonからmoduleaの記述が消える。
npm linkでより効率的に開発できるかも
npmでローカルのモジュールを取り込むと、相対パスが記述されてしまい。今後github等に移行する場合にはその記述を消す必要がある。また相対パスを指定するのも面倒だったりする。
より手軽な方法としてはnpm linkがある。
使い方としてはmodule側のルートでnpm link
とまず打つ。
$ npm link
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN modulea@1.0.0 No description
npm WARN modulea@1.0.0 No repository field.
up to date in 0.312s
found 0 vulnerabilities
C:\Program Files\nodejs\node_modules\modulea -> C:\Users\tsuto\webapp\temp\npmtest\moduleA
次にappAのルートに行き、モジュール名を叩く
$ npm link modulea
C:\Users\tsuto\webapp\temp\npmtest\moduleA\node_modules\modulea -> C:\Program Files\nodejs\node_modules\modulea -> C:\Users\tsuto\webapp\temp\npmtest\moduleA
これで完了である。
良く見るとただのシンボリックリンクであり、図示すると次のようになる。
ln -sとか使ってシンボリックリンク貼ってもできるが、npm linkだと面倒なコマンドを叩かずによろしくやってくれるところが良い。
ちなみにlinkを解きたい時は
$ npm unlink modulea
でできる。
package.jsonの中身を変更せずにローカルのmoduleを参照できるところが肝である。
相対パスのnpm installも実のところシンボリックリンク
"dependencies": {
"modulea": "file:../moduleA"
}
でnpm installした時にnode_modules以下を見るとmodulea -> /c/Program Files/nodejs/node_modules/modulea/
とあるので、相対パスによるnpm installも結局のところシンボリックリンクをしているだけである。
よって .npmigonreは当然無視されるし、moduleAを書き替えると別にnpm installをしなくても更新されている。
github private repoからmoduleaを取り込む
まずPrivate Repositoryをgithubで作成する。
httpsでcloneしても良いが、毎回ユーザ名とパスワードを聞かれるのも面倒であるため、SSH Keyを登録しておこう。Putty Genなどでopen ssh形式のキーペアを作成してgithubに登録すれば良いが、登録方法は別の記事に任せるとする。
SSHで登録できたら下記でcloneして、そのRepositoryにmoduleAのファイルを移してpushしておく。
git clone git@github.com:tomsongazeru/moduleA.git
次にappAからgithub private repositoryに置いたmoduleAを取り込むためにappAのルートで下記を叩く
npm install git+ssh://git@github.com:tomsongazeru/moduleA.git
package.jsonが更新されていることも確認できる。
{
"name": "appa",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
+ "dependencies": {
+ "modulea": "git+ssh://git@github.com/tomsongazeru/moduleA.git"
+ }
}
gitからインストールされるファイルは.npmignore
ファイルがローカルの場合と異なりきちんと反映される。
ブランチを変更してnpm install
dependenciesの記述の最後に#ブランチ名を付ける事で、特定ブランチで作成したnpm moduleを取り込むことができる。
たとえば新たにdevelopブランチを作成した場合、package.jsonにdevelopを作成して再度npm installをしてやれば良い。
"dependencies": {
"modulea": "git+ssh://git@github.com/tomsongazeru/moduleA.git#develop"
}
ローカル開発かgithub repositoryどちらがおすすめ?
github repositoryではmodule側でpushして、app側でpullするという手間が掛かるため迅速なトライアンドエラーが難しい。よってappAもmoduleAもどちらも開発するプロジェクトならば、基本的にnpm linkで開発し、保存や共有目的としてgithub repositoryを使うと良いだろう。