🖇

モノレポでの依存設定忘れを防ぐ

2023/03/05に公開

結論

eslint-plugin-importimport/no-extraneous-dependenciesを使え。

以下、経緯。

概要

もっと早く気付けばよかったのだけど、

error: TypeError: debug_1.green.bold is not a function

という時点でansi-colorsを使った処理に関するところなので、そのパッケージまわりを見ればよかった。
越智さんが直接の依存パッケージをすべて洗ってくれていたので、その後の特定は早かった。ありがとうございます。

原因

結論から言うと、依存パッケージの設定し忘れ

エラーが起こった箇所は@markuplint/rulesの一部のコードで起こっている。この@markuplint/rulesのdependenciesにansi-colors設定し忘れていただけだった。完全に凡ミス。恥ずかしいを通り越して情けない。

何故気づけなかったのか

  • @markuplint/rulesはMarkuplintのデフォルトのルールを集めたパッケージで単体で利用するものではない
  • markuplint本体がenquirerというパッケージを採用していて、これがansi-colorsに依存していた
  • @markuplint/rulesはモノレポでmarkuplintと一緒に管理・開発しているので、開発中はもちろん、CIのテストでもenquirer経由でansi-colorsが常にインストールされた状態なので、dependenciesにansi-colorsを設定していなくても問題なかった
  • さらに基本的な利用においてもmarkuplint@markuplint/rulesに依存しているので、@markuplint/rulesansi-colorsはほぼ必ず一緒にnode_modulesに入ることになる

ちなみにansi-colorsがどういうパッケージを経由して依存しているかは次のコマンドで確認できる

yarn list ansi-colors

gulpでは何が起きていたのか

問題が起こるgulp関連のパッケージはほとんどがplugin-errorを経由してansi-colorsのv1.0.1に依存している。Markuplintがenquirer経由で依存していたansi-colorsのバージョンはv4.1.1

ツリーを作るとこんな感じ。

  • dskd.jp
    • └ gulp-*
      • └ plugin-error
        • ansi-colors@1.0.1
    • └ markuplint
      • └ enquirer
        • ansi-colors@4.1.1
      • └ @markuplint/rules
        • ansi-colors設定し忘れ

ansi-colors設定し忘れている@markuplint/rulesは、import * from "ansi-colors"したときにansi-colors@1.0.1ansi-colors@4.1.1のどちらかをインポートする。どうやらここでインストールされた順番が関係してくるらしい。

越智さんの検証では、要するにansi-colors@1.0.1が先にインストールされているケースで問題が発生していた。@markuplint/rulesansi-colors@1.0.1をインポートし、その結果v1とv4のAPIの違いからerror: TypeError: debug_1.green.bold is not a functionというランタイムエラーを引き起こしてしまったようだ。

@markuplint/rules"ansi-colors": "^4.1.3"を追加し、Canaryリリース(markuplint@3.0.0-dev.96+3b9f1720)をして試したところ正常に動作することを確認できた。ansi-colors@1.0.1を先にインストールしていたとしても、@markuplint/rulesがきちんとansi-colors@4.1.3を持つようになるので問題は解消された。実際に問題が解消されたnode_modulesのディレクトリを覗くと以下のように解消されている。

  • node_moduules
    • └ ansi-colors (1.0.1)
    • └ enquirer
      • └ node_modules
        • └ ansi-colors (4.1.3) ※キャレット設定されているので設定バージョンより上がる
    • └ @markuplint/rules
      • └ node_modules
        • └ ansi-colors (4.1.3)

どうやってこのミスを防ぐのか

原因がわかったところで、このミスを防ぐ方法を考えないといけない。依存パッケージによってはすぐに見つかるだろうけど、今回のは組み合わせが絶妙すぎたとも思う。gulp以外でもansi-colorsを依存にもつパッケージを組みわせてMarkuplintを利用している人もいると思うけど、おそらくansi-colorsがv1.xではなく偶然APIが一致していてエラーを起こしていないだけだろう。たまたま上手くいってる。このたまたまというのがプログラミングの世界では一番怖いんだよ。なんとかしたい。

ということで調べてみるとESLintのプラグインのeslint-plugin-importimport/no-extraneous-dependenciesというルールがある。依存設定していなかったりdevDependenciesに設定しているものをインポートしようとすると警告するものだ。

eslint-plugin-importは他のルールを利用していて導入していたのに、このルールを有効にしていなかった…。なんてことだ。もったいないことしていたし、実際迷惑をかけてしまった。申し訳ない。

これを読んでESLintのルール周りに詳しい方がいたら、Markuplintのpackage.jsonを見てPRしてほしい。「これ導入/有効にしてないのかよ、ありえんのやけど」というやつがあったら是非よろしくおねがいします。

GitHubで編集を提案

Discussion