npm v3.x 試してみた & 注意する点

  • 43
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

ふと思い立って npm install -g npm@3 した。3.1.2 は VERY BETA とのこと(ニュアンスがよくわからん。アルファとの対比なのか、アルファ相当なのか) ので、そのうち出るでしょう。

node_modulesのフラットな展開

npm@3 だとnode_modulesの依存がパッケージ間のバージョンが衝突しない限り、トップレベルのnode_modulesにフラットに展開される。これによって同一のモジュールを依存ツリー間でモジュールが重複した時にnode_modules以下のサイズが膨らむのを抑えることができる。

衝突した場合はそのモジュールの子のnode_modulesに格納されて衝突は回避される。

気になるrequireの仕様

とはいえ、requireの仕様が変わってるわけじゃないので、トップレベルから子だけじゃなく孫モジュールも直接requireできてしまう。手元でたとえば a -> b な依存のときに、今までは require('b') できなかったのができるようになる。

これはある時点でrequireできたモジュールが何の依存だったのかあとでわからないという、将来的に禍根になる可能性があるケースがあるのではないか。怖い。

壊れるケース

気にしないといけないのが一点。

子と孫で同じバージョンの場合はrequireキャッシュに引っかかって同一参照になる。依存自身からみた場合に子が孫をシングルトンだと想定してグローバルオプションをセットしている場合npm3にしたことで壊れる。

ちょうどmarkedが判りやすく壊れそうだったので、例に出す。

gfm-marked/gfm-marked.js

var marked = require('marked');
marked.setOptions({
  renderer: new marked.Renderer(),
  gfm: true
});
module.exports = marked

not-gfm-marked/not-gfm-marked.js

var marked = require('marked');
marked.setOptions({
  renderer: new marked.Renderer(),
  gfm: false
});
module.exports = marked

index.js

var notGfm = require('not-gfm-marked');
var gfm = require('gfm-marked');
notGfm('```aaa```'); // fenced code block はgfmでないと存在しないが、参照が同一な為あとで読み込んだsetOptionsで有効になってしまう。

まあ意図しないとなかなか起こせないとは思うんだけど、ハマった時の根は深そう。他に気づいた点としてはbrowserifyが対応してなかったので、browserify使っている人も対応待ちになるはず。

そういえば es modules と commonjs の関係ってどうなるか話進んでるんだろうか。