依存関係の依存関係

この物語は、11月30日の朝に始まりました。 テスト環境で完全に正常なビルドが突然クラッシュしたとき。 たぶん、ある種のリンターが落ちて、目を覚まさずに、間違っていると思った。
誰にこの物語がどのように終わり、それがどのような考えを促したのかが面白い-私は猫の下で尋ねます。
ビルドログを開くと、npmインストールが失敗したことがわかりました。 奇妙な、私は思った。 昨夜はすべてうまくいった。 ログを調べたところ、疑わしい行が見つかりました。
疑わしい...node --eval 'if (require("./package.json").name === "coffee-script") { var red, yellow, cyan, reset; red = yellow = cyan = reset = ""; if (!process.env.NODE_DISABLE_COLORS) { red = "\x1b[31m"; yellow = "\x1b[33m"; cyan = "\x1b[36m"; reset = "\x1b[0m"; } console.warn(red + "CoffeeScript has moved!" + reset + " Please update references to " + yellow + "\"coffee-script\"" + reset + " to use " + yellow + "\"coffeescript\"" + reset + " (no hyphen) instead."); console.warn("Also, a new major version has been released under the " + yellow + "coffeescript" + reset + " name on NPM. This new release targets modern JavaScript, with minimal breaking changes. Learn more at " + cyan + "http://coffeescript.org" + reset + "."); console.warn(""); }
ここで私は再び驚いた。 繰り返しますが、昨日はプロジェクトでコーヒースクリプトを使用しませんでしたが、一晩で何かが大きく変わることはまずありません。 package.jsonをざっと見てみると、そこに新しいものを追加している敵はいないことが確認されました。 そのため、おそらく、コーヒースクリプトを使用するある種の依存関係を更新しました。 しかし、この考えに反して、私はかなり長い間、プロジェクトのすべての依存関係の厳密なバージョンを公開し、私にはそう思われたように、これは起こり得ないと言われました。 インターネット上で同様の問題を無駄に検索した後、私は再び更新された依存関係の考えに戻りました。 そのため、node_modulesのすべてのpackage.jsonを巡回してcoffee-scriptを検索するスクリプトがひざまずきました。 約5〜6個のそのような依存関係がありました。 これはさらに疑念を強め、あまり考えずにすべてのnode_modulesを破壊し、同時にローカルリポジトリにあるものを除くすべての依存関係を破壊し、npm installを再度実行しました。 プロセスは成功しました。 さらに、ステップバイステップで、インストールをインストールする依存関係が見つかりました。
それはカルマタイプスクリプトであることが判明しました。これは推移的な依存関係に「パッド」を持ち、コーヒースクリプトに依存していました。 そして、私は再び落ち込んだ。 オプションはほとんどありませんでした。 テストを一時的に無効にするか、修正を待つか、自分で分岐して修復します(修正が必要なものは明確ではありません)。 あまり希望がなかったので、問題を作成するためにGithubに行きました。 彼らが文字通り20分で私に答えたとき、私の驚きを想像してください。 一部の同志がnpmでcoffee-scriptパッケージを更新することを決定し、古いパッケージを廃止することを宣言する代わりに、単に非公開にしました。
幸いなことに、@ ondrejbaseはすでに提案しました 松葉杖 私を助けた一時的な解決策。 そして、この全体の話は比較的安く終わりました。 しかし、それは完全に間違っている可能性があります。
それは格言でした。 そして今、私は私たちのプロジェクトの依存関係とそれらがもたらす問題について話すことを提案します。
シンプルから始めましょう。
グローバルな依存関係
最近、私はもう一度、初心者向けの記事を見つけました。
npm install -g typescript
そして、我慢できませんでした。 私の意見では、これは初心者の開発者に与えることができる最悪のヒントの1つです。 私は本気です。 このヒントがもたらす問題は次のとおりです。
- ローカルリポジトリの競合。 グローバルな依存関係(tscなど)を使用してすべてのコードを収集するか、グローバルリンターで検証すると、これらの依存関係を簡単に更新できなくなります。 グローバルなものを更新した後、それが使用されているすべてのリポジトリを危険にさらします。 その結果、すべてのリポジトリでこれらの依存関係の更新に時間を費やすか、まったく更新しない必要があります。
- チームメンバーとの競合。 チームワークでグローバルな依存関係を使用すると、非同期化につながります。 そして、その結果、私のコードはコンパイルされないか、同僚による検証に合格しません。
- ビルドマシンとの競合。 私から収集されたものがビルドマシンで収集されることは保証されていません。 または、それははるかに悪いとより陰湿です-それは私のように組み立てられません。 そして、これは次の1時間以上のデバッグ地獄を保証します。
ほとんどのチュートリアルはnpm install abc -g
始まるため、これはすべて起こります。 すべてをローカルに配置し、package.jsonに./node_modules/.bin/tsc
として接続できますが
ガイドを書くことを計画している場合は、この記事を覚えておいてください。そして、私の神経だけでなく、実際にガイドを使用するすべての人の神経も救ってください。
NBグローバルにコードジェネレーター(create-react-app、create-angular-app)をインストールするのは問題ありません。 彼らは一度動作し、それがすべてです。 また、次のリポジトリを作成する場合、それらを再インストールする必要はありません。
緩い中毒
続けましょう。 create-react-appをインストールし、ベースアプリケーションを作成します。 package.jsonに移動すると、そこに何が表示されますか?
"react": "^16.2.0"
すべて(またはほとんどすべて)は^記号の意味を知っています。 これは、npmがメジャーリリース内で指定されたバージョン以上の任意のバージョンをインストールできることを意味します。 それに何が問題なのですか? カテゴリにしたくありませんが、私にとっては、このアプローチも「それほどではない」ので、それが理由です。
- コントロールの喪失。 package.jsonに^または〜を残すと、コードの制御が失われます。 もちろん大げさですが、考えてみてください。 プロジェクトのバージョンがわからないサードパーティライブラリのバージョンをプロジェクトにアップロードします。 ある出版社のリポジトリにあるだけです。 そして突然何が起こるか、このパッケージがこれに気づくためにかなり組織化されたコミュニティを持っていることを望むことができるだけです。
- 下位互換性を壊す変更。 もちろん、メジャーバージョンを公開することで、開発者はそのフレームワーク内に重大な変更がないことを約束します。 しかし、紳士、現実的になりましょう。 これはインターネットであり、オープンソースです。誰もあなたに何も負いません。 1時間前に機能したものは、「この新しいリリースは最新のJavaScriptを対象とし、重大な変更は最小限です」というようなコメントで落ち着くかもしれません。
- 更新の非自明性。 abc:^ 2.1.1という形式のライブラリがあるとします。 そして、結局のところ、私が本当に持っているライブラリのバージョンがわかりません。 たぶん2.1.1、そしておそらく2.9.9。 反対に、これは問題ではないようです。 特定のバージョンのドキュメントを探す必要はありません。常に最新版を見るだけで十分です。 そして、私はそれを見て、新しいチップを見つけましたが、動作しません。 しかし、ライブラリを更新するのを忘れたため、機能しません。 私はそれを更新し、コードはコミックであり、30分後に彼のアプリケーションが機能しないために私の同僚が私に走ります! そして、さらに3人が彼のために来て、私を悲しませます。 誰がこれを必要としますか?
- そして最後に:依存関係。 これはケーキの上のチェリーであり、これは私があなたに考えて欲しいものです。
依存関係またはZNZの依存関係
ビルドが壊れた理由から始めましょう。 すべての依存関係は厳しく設定されましたが、それでも落ちました。 主な依存関係のバージョンは同じままであったにもかかわらず(package.jsonには^、〜はありません)、それらの依存関係はそれほど厳密ではありませんでした。 試しましたが、依存関係の依存関係を制御しませんでした。 そして、最も不快なそのような動作はデフォルトで推奨されています。 誰が、なぜこれをしたのかはわかりませんが、彼は私たち全員、特に継続的インテグレーションを実践している人たちに大きな豚を植えました。
もちろん、特にこの問題は簡単に修正できます。 ロックファイルを作成する(たとえば、npm shrinkwrapコマンドを使用する)か、デフォルトでプロジェクトのすべての依存関係をキャプチャするパッケージマネージャーであるyarnを使用するだけで十分です。
ただし、これは問題の一部のみを解決します。 もう1つ、はるかに危険な部分が残っており、その名前はunpublishです。 以前にこの問題に遭遇したことがない場合は、最新のWeb開発の脆弱性を示す優れた記事があります。 故意または過失により、誰かがnpmからパッケージを削除したからといって、いつでもプロジェクトのコンパイルが停止する場合があります。 そして、これを行うことは決して難しいことではありません。 unpublishコマンドを入力するだけです。 この不幸は戦うことができます 。 しかし、自分に正直になりましょうか? 独自のローカルnpmを持っているのはどれですか? そして、少なくとも誰がこれについて考えましたか? そんなに怖くない。 そして今、あなたが警告されていることを願っています。
ちなみに、私のリポジトリにアクセスすると(これをしないでください)、私のプロジェクトのほとんどすべてが上記のすべてに違反していることがわかります。 そして、これは問題がどれほど一般的であるかの別の証拠です。
結論
- グローバルインストールフラグを賢く使用してください。 プロジェクトが常に依存する依存関係には使用しないでください。
- 複数の物理マシンで作業している場合は、依存関係を厳密に設定することを検討してください。 これにより、すべてのリポジトリおよび同僚間でプロジェクトの同じ基本的な依存関係を持つことができます。 さらに、独自のコードとその更新プロセスの制御を強化します。
- ロックファイルを使用します。 特にcontinues-integrationを使用する場合。
- プライベートパッケージレジスタについて考えてください。 これはパッケージの突然の削除からあなたを救うだけでなく、ビルドマシンへの依存関係のインストールをスピードアップします。 これにより、プルリクエスト中にビルドが行われている間に飲む時間とコーヒーの量を節約できます。
それは私にとってすべてです、私はそれが面白くて便利だったことを願っています。 奇妙な伝統により、ここには何らかの広告があるはずですが、私はそれを持っていませんので、この消防士を連れて行ってくれた同僚に感謝します。
そして、私は英語の単語をおaびしますが、ロシア語の相当語では目を大きく傷つけます。