lerna&yarnワークスペースでモノリポジトリを作成する

学習と糸



過去数年にわたり、 モノリポジトリの概念は、マイクロサービスベースのインフラストラクチャなどのモジュール式ソフトウェアプロジェクトの開発プロセスを大幅に簡素化できるため、成功裏に確立されました。 このアーキテクチャアプローチの主な利点は実際には明らかであるため、 糸のワークスペースlernaを使用する作業のニュアンスを同時に理解しながら、独自のテストモノリポジトリをゼロから作成することを提案します。 さあ、始めましょう!



私たちのプロジェクトの構造を考えてみましょう。これは、 パッケージ/フォルダーにある3つのライブラリーと、ルートディレクトリのpackage.jsonです。



├── package.json └── packages ├── app │  ├── index.js │  └── package.json ├── first │  ├── index.js │  └── package.json └── second ├── index.js └── package.json
      
      





firstsecondの 2つの独立したライブラリと、最初の2つの関数をインポートするアプリライブラリがあることが理解されます。 便宜上、3つのパッケージはすべてパッケージディレクトリに配置されます 。 ルートフォルダーに残しておくことも、他の名前のディレクトリに置くこともできますが、一般的に受け入れられている規則に従うために、このように配置します。



実験を簡単にするために、 最初2番目のライブラリにはindex.jsに関数が1つだけ含まれ、各関数はモジュールに代わってウェルカムラインを返します。 最初の例では、 次のようになります。



 // packages/first/index.js const first = () => 'Hi from the first module'; module.exports = first;
      
      





appモジュールでは、コンソールのアプリからメッセージHiを表示するとともに、他の2つのパッケージからの挨拶を表示します。



 // packages/app/index.js const first = require('@monorepo/first'); const second = require('@monorepo/second'); const app = () => 'Hi from the app'; const main = () => { console.log(app()); console.log(first()); console.log(second()); }; main(); module.exports = { app, main };
      
      





1番目2番目アプリで使用できるように、それらを依存関係の依存関係として示します。



さらに、各ライブラリについて、パッケージのメイン名の前にある値に接頭辞@ monorepo /をローカルpackage.jsonに追加します。



 // packages/app/package.json { "name": "@monorepo/app", "version": "1.0.0", "main": "index.js", "license": "MIT", "dependencies": { "@monorepo/first": "^1.0.0", "@monorepo/second": "^1.0.0" } }
      
      





パッケージ名npm(@ monorepo /)の前に犬のアイコンが付いたプレフィックスが必要なのはなぜですか?
プレフィックスの追加はオプションですが、これ多くのモノリポジトリが準拠しているパッケージの命名規則まったく同じです: babel

素材uiangularなど。 実際、各ユーザーまたは組織はnpm Webサイトに独自のスコープを持っているため、 @ somescope / postfixを持つすべてのモジュールは、攻撃者ではなくsomescopeチームによって作成されることが保証されています。 さらに、すでに使用されているモジュール名を呼び出すことが可能になります。 たとえば、独自のutilsモジュールを取得して作成することはできません。そのようなライブラリは既に存在しているためです。 ただし、接尾辞@ myscopename /を追加すると、ブラックジャックと若い女性のユーティリティ@ myscopename / utils )を取得できます。



テストプロジェクトの実生活の類似物は、データ、検証ツール、分析、またはUIコンポーネントのセットを操作するためのさまざまなライブラリです。 Webアプリケーションとモバイルアプリケーション(たとえば、それぞれReactReact Nativeを使用)を開発することを想定しており、再利用されたロジックの一部がある場合は、後で他のプロジェクトで使用するために、個別のコンポーネントに配置する価値があります。 これにNode.jsのサーバーを追加すると、人生から非常に現実的なケースが得られます。



糸のワークスペース



本格的なモノ - リポジトリを作成する前の最後の仕上げは、リポジトリのルートにあるpackage.jsonの設計です。 workspacesプロパティに注意してください-「 packagesフォルダー内のすべてのサブキー」を意味する値packages / *を指定しました。 私たちの場合、これはappfirstsecondです。



 // package.json { "name": "monorepo", "version": "1.0.0", "main": "packages/app/index.js", "license": "MIT", "private": true, "workspaces": [ "packages/*" ] }
      
      





さらに、 「プライベート」:truepackage.jsonで指定する必要があります。 ワークスペースはプライベートプロジェクトでのみ使用できるためです。



すべてを離陸させるには、ルートディレクトリからyarnコマンド( yarn installまたはnpm installに類似)を実行します。 appモジュールに存在する依存関係はルートpackage.jsonの ワークスペースとして定義されているため、実際にはnpm-registryから何もダウンロードせず、単にパッケージをバインド(「リンク」)します。



 yarn
      
      





画像



これで、 nodeコマンドを実行できます。 packages / app / index.jsファイルからスクリプトを実行するルートディレクトリから。



 node .
      
      





画像



仕組みを見てみましょう。 yarnを呼び出すことによりnodes_modulespackagesフォルダー内のディレクトリへのシンボリックリンクを作成しました。



画像



依存関係のこの関係により、1つの大きな利点が得られました。1つ目と2つ目のモジュールを変更すると、 アプリは再構築せずにこれらのパッケージの現在のバージョンを受け取ります。 実際には、非常に便利です。 パッケージのローカル開発を行いながら、サードパーティの依存関係(最終的には依存関係になる)として定義します。



yarnワークスペースでの作業から得られる次の重要な利点は、サードパーティの依存関係を保存する組織です。



トップレベルでの依存関係の保存の詳細。
firstsecondlodashライブラリを使用したいとします。 対応するディレクトリからyarn add lodashコマンドを実行すると、ローカルpackage.jsonの更新が届きます。パッケージの現在のバージョンが依存関係に表示されます。

 "dependencies": { "lodash": "^4.17.11" }
      
      





lodashパッケージ自体については、物理的にライブラリはルートレベルのnode_modulesに一度インストールされます。

外部パッケージの必要なバージョン(この場合はlodash )が最初と2番目で異なる場合(たとえば、 最初に lodash v3.0.0 必要で、 2番目のv4.0.0 必要)、それより低いバージョン( 3.0.0 )のパッケージはルートnode_modulesに到達します 、および2番目のモジュールのlodashバージョンはローカルパッケージ/ second / node_modulesに保存されます

利点に加えて、このアプローチには小さな欠点があり、追加のフラグを使用してをバイパスできます。 このようなニュアンスの詳細については、 公式ドキュメントをご覧ください。



レルナを追加



lernaを使用する最初のステップは、パッケージをインストールすることです。 通常、グローバルインストール( yarn global add lernaまたはnpm i -g lerna )を実行しますが、このライブラリを使用するかどうか不明な場合は、 npxを使用して呼び出しを使用できます。



ルートディレクトリからlernaを初期化します。



 lerna init
      
      





画像



実際、1つのコマンドを使用して複数のアクションを一度に実行しました。gitリポジトリを作成し(以前に初期化されていなかった場合)、 lerna.jsonファイルを作成し、ルートpackage.jsonを更新しました。



新しく作成されたlerna.jsonファイルに 「npmClient」:「yarn」「useWorkspaces」:trueの 2行を追加します 。 最後の行は、すでにyarnワークスペースを使用しているため、 最初2番目へのシンボリックリンクを含むapp / node_modulesフォルダーを作成する必要がないことを示しています



 // lerna.json { "npmClient": "yarn", "packages": [ "packages/*" ], "version": "1.0.0", "useWorkspaces": true }
      
      





Lernaによるテスト



lernaでの作業の利便性を示すために、ライブラリのテストを追加します。

ルートディレクトリから、テスト用のパッケージjestをインストールします。 コマンドを実行します:



 yarn add -DW jest
      
      





-DWフラグが必要なのはなぜですか?
jestパッケージをdev依存関係としてインストールするために-D(-dev)フラグが必要です。-Wフラグ(-ignore-workspace-root-check)を使用すると、ルートレベル(必要な)でインストールできます。



次のステップは、1つのテストファイルをパッケージに追加することです。 この例の便宜上、すべてのテストを同様に見せます。 最初の例では、テストファイルは次のようになります。



 // packages/first/test.js const first = require('.'); describe('first', () => { it('should return correct message', () => { const result = first(); expect(result).toBe('Hi from the first module'); }); });
      
      





また各ライブラリのpackage.jsonでテストを実行するスクリプトを追加する必要があります。



 // packages/*/package.json ... "scripts": { "test": "../../node_modules/.bin/jest --colors" }, ...
      
      





最後の仕上げは、ルートpackage.jsonの更新です。 lerna run test --streamを呼び出すテストスクリプトを追加します。 lerna runに続くパラメーターは、 パッケージ/フォルダーから各パッケージで呼び出されるコマンドを定義し、 -streamフラグを使用すると、ターミナルで結果の出力を確認できます。



その結果、ルートディレクトリのpackage.jsonは次のようになります。



 // package.json { "name": "monorepo", "version": "1.0.0", "main": "packages/app/index.js", "license": "MIT", "private": true, "workspaces": [ "packages/*" ], "scripts": { "test": "lerna run test --stream" }, "devDependencies": { "jest": "^24.7.1", "lerna": "^3.13.2" } }
      
      





ここで、テストを実行するには、プロジェクトのルートからコマンドを実行するだけで十分です。



 yarn test
      
      





画像



Lernaを使用したバージョンアップグレード



lernaが品質に対処できる次の一般的なタスクは、パッケージのバージョンを更新することです。 テストを実装した後、ライブラリを1.0.0から2.0.0にアップグレードすることにしたと想像してください。 これを行うには、 「update:version」:「lerna version --no-push」という行をルートpackage.jsonの scriptsフィールドに追加してから、ルートディレクトリからyarn update:versionを実行します。 --no-pushフラグが追加され、バージョンの更新後に変更がリモートリポジトリに送信されないようにします。lernaはデフォルトで(このフラグなしで)行います。



その結果、ルートpackage.jsonは次のようになります。



 // package.json { "name": "monorepo", "version": "1.0.0", "main": "packages/app/index.js", "license": "MIT", "private": true, "workspaces": [ "packages/*" ], "scripts": { "test": "lerna run test --stream", "update:version": "lerna version --no-push" }, "devDependencies": { "jest": "^24.7.1", "lerna": "^3.13.2" } }
      
      





バージョン更新スクリプトを実行します。



 yarn update:version
      
      





次に、切り替えるバージョンを選択するよう求められます。



画像



Enterをクリックすると、バージョンが更新されたパッケージのリストが表示されます。



画像



yを入力して更新を確認すると、更新の成功に関するメッセージが表示されます。



画像



git statusコマンドを実行しようとすると、 コミットするものが何もないというメッセージが表示されます。 lernaバージョンは、パッケージバージョンを更新するだけでなく、新しいバージョン(この場合はv2.0.0)を示すgitコミットとタグを作成します。



lernaバージョンチームと連携する機能
ルートpackage.jsonの scriptsフィールドに「update: version」:「lerna version --no-push」の代わりに「version」:「lerna version --no-push」という行を追加すると、予期しない動作に遭遇する可能性が高くなります。赤いコンソール。 実際には、 npm-scriptsはデフォルトでパッケージバージョンを更新した直後にversionコマンド(予約済みスクリプト)を呼び出し、 lerna versionの再帰呼び出しにつながります。 この状況を回避するには、スクリプトで別の名前を付けるだけで十分です。たとえば、例で行ったようにupdate:versionのようにします。



おわりに



上記の例は、 lernayarnワークスペースに関連して持っているすべての機能の100分の1を示しています 。 残念ながら、これまでのところ、ロシア語でモノリポジトリを操作するための詳細な手順は見つかっていません。そのため、始められたと推測できます。



テストプロジェクトリポジトリにリンクします。



All Articles