node_modules をシンボリックリンクで管理する

プロジェクトごとの node_modules ディレクトリ、みなさんはどう管理されてます?

案件ごとに利用するプラグインがほとんど共通なこともあって、極力重複するデータをなくしてストレージ容量を確保しておきたい・・・と考えた BUN は、シンボリックリンクを利用してパッケージを一括管理するようになりました。

果たしてそれがいいのか?は謎ですが、個人的に便利だと思うので共有してみます。
間違っていたらきっと誰かにツッコミをいただけるだろうという、淡い期待を込めつつ(。-_-。)

グローバルな node_modules のパスを確認

はじめに Terminal.app で Node.js のインストール先を確認します。
出力結果に表示されたパスの bin と同階層にある node_modules がグローバルにあたります。

$ which node
# /Users/hoge/.nodebrew/current/bin/node <- 出力結果

Node.js の管理に nodebrew を利用している BUN の場合は、ホームディレクトリの「.nodebrew/current」にありましたので、これを元に任意のプロジェクトディレクトリ直下へシンボリックリンクを生成します。

プロジェクトにシンボリックを生成

生成先に node_modules が既にあればあらかじめ削除しておきつつ、コマンドを実行すれば完了です。

$ ln -s ~/.nodebrew/current/lib/node_modules ~/PathTo/MyProject

プロジェクトごとに必要なパッケージは、従来通り --save-dev オプションを付けてインストールします。プロジェクトメンバーと共有する際でも package.json があれば環境を再現できるので、問題ない・・・ハズです(。-_-。)

ファイル同期にあたって

AeroFS や GoodSync を利用している場合、シンボリックリンクは同期対象から外れるようです。最近利用していないため未検証・・・ではありますが、Dropbox の場合シンボリックリンクを明示的に外す必要があったように記憶していますので、その際は公式リファレンスを参考にしてみてください。

Dropbox - コンピュータと同期させるフォルダを選択する方法:https://www.dropbox.com/help/175/ja

Grunt を利用したシンボリックリンクの再設定

はい。やっと本題です w

nodebrew で Node.js のバージョンを切り替えた場合、各プロジェクトのシンボリックリンクは生成時点の node_modules を参照しているため、再設定が必要です。そこで grunt-contrib-symlink プラグインを利用して、一括処理します。

シンボリックリンクだけ管理できればよいので、専用のプロジェクトを作成します。

$ mkdir ~/updateSymlink
$ cd ~/updateSymlink
$ npm init
$ ln -s ~/.nodebrew/current/lib/node_modules ~/updateSymlink
$ npm install grunt-contrib-symlink --save-dev

次に Gruntfile.js を作成します。

symlink_src: のパスを環境にあわせて変更。あわせて、存在するプロジェクトにあわせて explicit: files: の内容も編集が必要です。

なお、カレントのプロジェクト外にあるディレクトリを操作するため、 --force オプションをデフォルトで有効にしています。

module.exports = function(grunt) {
    var _package, _taskName;
    _package = grunt.file.readJSON('package.json');

    grunt.initConfig({
        pkg: _package,
        symlink_src: '/Users/hoge/.nodebrew/current/lib/node_modules',

        // grunt-contrib-symlink
        symlink: {
            options: {
                overwrite: true
            },
            explicit: {
                files: [
                    {
                        src: '<%= symlink_src %>',
                        dest: '../Project-A/node_modules'
                    },{
                        src: '<%= symlink_src %>',
                        dest: '../Project-X/node_modules'
                    }
                ]
            }
        }
    });

    // load dependenciesPackages
    for(_taskName in _package.devDependencies) {
        if(_taskName.substring(0, 6) == 'grunt-') {
            grunt.loadNpmTasks(_taskName);
        }
    }

    // use --force
    grunt.option('force', true);

    // Task::default
    grunt.registerTask('default', ['symlink']);
};

あとは、Node.js のバージョン切り替え後に下記のコマンドを実行して、シンボリックリンクを再設定します。

$ ln -s ~/.nodebrew/current/lib/node_modules ~/updateSymlink
$ grunt

ここまで書いてはみたものの

gulpfile.js の方がもっと簡潔に書けそうとか、Alfred Workflow ならサクッとできるかも?とか思いはじめたのは内緒です(。-_-。)

comments powered by Disqus