web-dev-qa-db-ja.com

Githubからのインストール時にNPMモジュールを自動的にビルドする

プロジェクトのlib/ dirをGitにチェックインすべきではないことを考えると、プロジェクトに含まれるファイルは(ビルドプロセスから)派生ファイルであるためです。プロジェクトのgithubからパッケージをインストールするとき(開発中など)、lib/ dirは存在しないため、パッケージのpackage.jsonmainフィールドが(たとえば)lib/index.js、これらのファイルはリポジトリ内に存在せず、したがってnode_modulesにインストールされたパッケージ内に存在するため、インポート時にパッケージをコンパイルできません。これは、パッケージを(リリース前と同じように)ビルドする必要があることを意味し、今回はlibディレクトリ(またはビルドプロセス中に生成される他のファイル)がモジュールのディレクトリに追加されるようにローカルでのみです。

package.jsonファイルのbuildフィールド内にscriptsスクリプトがあると仮定すると、パッケージは、次の状況でこれを自動的に実行するように構成できます。 githubからのみインストールされますか?そうでない場合、githubからインストールしたときにビルドされるようにするための最良のアプローチは何ですか?

prepublishprepublishOnly、およびprepareのライフサイクルフックがありますが、インストールのソースを区別する方法がないため、この問題に対する答えはありません。 。要するに、はい、インストール時にビルドすることはできますが、githubからのみインストール時にビルドすることはできません。 npmからインストールするときにビルドを強制する理由がないだけでなく、さらに重要なことに、開発の依存関係はインストールされません(たとえば、ビルドに不可欠なbabel)。

この問題に対処するための1つの戦略を知っています。

  • フォーク/ブランチレポ
  • ローカルに構築する
  • lib/ディレクトリを.gitignoreから削除してチェックインします。
  • フォーク/ブランチからモジュールをインストールします
  • PR /リベースの準備ができたら、lib/ dirを.gitignoreに追加し、gitからdirを削除します。

しかし、それは理想とはほど遠いものです。ただし、これはgithookで自動化できると思います。したがって、プロジェクトをマスターするためにプッシュするたびに、ビルドして別のブランチにプッシュします。

NPMのGithubには、解決策のない 未解決の問題 があります-ソリューションを必要とする多くの人々。この問題から、prepareを使用しても答えにならないことは明らかです。

私のユースケースは、他の多くのプロジェクトで使用されるモジュールを開発していることです。コードベースを更新するたびにリリースをNPMにプッシュすることなく、モジュールの最新バージョンを使用したい-準備ができたらリリースをプッシュしたくないが、libの最新バージョンを使用する必要があるGithubにあります。

注:また、この問題に関するNPMのサポートに連絡し、問題が発生した場合は回答を追加します。

36
Undistraction

編集:パッケージがgitリポジトリからインストールされているかどうかを検出する

私は質問を適切に理解していませんでした。以下は私が書いたものですが、少しトピックから外れています。とりあえず、リポジトリからインストールするときにbuild.jsonlyを実行する場合:

リポジトリ内のファイル:

 .gitignore
 .npmignore
 ThisIsNpmPackage
 build.js
 package.json

.gitginore

ThisIsNpmPackage

.npmignore

!ThisIsNpmPackage

Package.jsonで:

"scripts": {
    "install": "( [ ! -f ./ThisIsNpmPackage ] && [ ! -f ./AlreadyInstalled ] && echo \"\" > ./AlreadyInstalled && npm install . && node ./build.js ) || echo \"SKIP: NON GIT SOURCE\""
}

アイデアは、レポジトリでファイルThisIsNpmPackageを使用可能にすることですが、npmパッケージでは使用できません。

インストールフックは、ThisIsNpmPackageが存在するかどうかを確認するための単なるスクリプトです。はいの場合、npm install .を実行します(これにより、devDependenciesが確保されます。ファイルAlreadyInstalledが生成され、無限ループが防止されます(npm installは再帰的にインストールフックを呼び出します)

公開するときは、git Pushnpm publishを行います
npmパブリッシュはCIツールを介して自動化できることに注意してください-githooks

ファイルThisIsNpmPackageを使用したこの小さなハックにより、ソース検出が利用可能になります。

npm install dumb-packageの呼び出し結果:

「スキップ:非GITソース」

npm install https://github.com/styczynski/dumb-packageの実行

ファイルが作成されます

問題

ここで直面している主な問題は次のとおりです。

  • npm publish ...を毎回行う必要があります

    小さなバグを修正してからリポジトリにプッシュしてnpmに公開するのを忘れるのが苦痛な場合があります。約5つのスタンドアロンサブプロジェクトがモジュールに分割されているマイクロサービスベースのプロジェクトで作業していたときに、問題を見つけて修正し、必要なすべての場所で公開するのを忘れてしまい、本当に面倒でした。

  • libをレポジトリにプッシュしたくない

  • リベースとマージはさらに面倒です。

  • .gitgnoreの混乱なし

    ヘック、私はあなたがレポの中に含めなければならない厄介なファイルを持っているが、それらを決して変更しないか、時には削除する必要があるとき、その問題を知っていますか?それはただの病気です。

編集:npmフック

@Roy Tinkerが述べたように、インストール時にパッケージがコマンドを実行する機能が存在します。
npmフックを使用して実現できます。

"install": "npm run build"

そして、以下を実行します。

npm install https://github.com/<user>/<package>

編集:
コメントからのOP質問:

しかし、これはnpmからモジュールをダウンロードするすべての人にインストールを実行しますか?これは、npmからモジュールをダウンロードする人にはdev依存関係がインストールされないことを考えると、非常に問題です。アプリのビルドに使用されるライブラリ-babelなどはインストールされません。

注:しかし、パッケージの特定のバージョンが必要な場合(production/dev)dev依存関係の有無にかかわらず、次の方法でインストールできます。

npm install --only=dev

--only = {prod [uction] | dev [elopment]}引数により、NODE_ENVに関係なく、devDependenciesのみまたはnon-devDependenciesのみがインストールされます。

私の意見では、より良い解決策は以下を使用することです。

npm install <git remote url>

そして、package.json内で以下を指定します。

"scripts": {
    "prepare": "npm run build"
}

インストールされるパッケージに準備スクリプトが含まれている場合、パッケージがパッケージ化およびインストールされる前に、その依存関係とdevDependenciesがインストールされ、準備スクリプトが実行されます。

例:

npm install git+https://[email protected]/npm/npm.git

そこのnpmドキュメントを読んでください: npm install

編集:プロキシモジュール(高度な手法)

それは一種の悪い習慣ですが、知っておくと良いでしょう。

時々(Electron frameworkの場合、さまざまな条件に応じて他の外部パッケージまたはリソース/モジュールをインストールする必要があります)。

これらの場合、プロキシアイデアが使用されます。

  • インストーラーのように動作し、必要に応じてすべてをインストールするモジュールを作成します

あなたの場合prepare scriptで十分ですが、時々役に立つかもしれないので、このオプションは残しておきます。

アイデアは、モジュールを記述し、install kookを記述することです

"scripts": {
    "install": "<do the install>"
}

このシナリオでは、そこに配置できます。

npm install . && npm run build

とにかくすべてのdevDependenciesをインストールします(前述の準備ケースのように)が、それはちょっとしたハッキン​​グです。

本当のハッキングを行いたい場合:

 "scripts": {
    "install": "curl -L -J -O \"<some_url>\""
 }

-nixコマンドcurlを使用して手動でファイルをダウンロードします

それは避けるべきですが、各プラットフォーム用の巨大なバイナリファイルがあるモジュールの場合のオプションであり、それらをすべてインストールしたくありません。

バイナリをコンパイルしたElectronの場合のように(それぞれ別のプラットフォーム用)

だから、人々はinstall packageinstall package-linuxなどではなくpackage-windowを作ってほしい。

そのため、package.jsonでカスタムinstallスクリプトを提供します

{
  ...
  "scripts": {
     "install": "node ./install_platform_dep.js"
  }
}

その後、moduleをインストールすると、install_platform_dep.jsスクリプトが実行されます。 install_platform_dep.jsの中に配置します:

// For Windows...
if(process.platform === 'win32') {
    // Trigger Windows module installation
    exec('npm install fancy-module-windows', (err, stdout, stderr) => {
         // Some error handling...
    }
} else if ... // Process other OS'es

そして、これは純粋に手動の方法ですべてをインストールします。

注:もう一度このアプローチはプラットフォーム依存のモジュールで使用でき、それを使用する場合はおそらくコードの設計上の問題です。

CI上に構築

私の頭に浮かぶのは、私が実際に長い間使用していたソリューションです(CIサービスを使用した自動構築)。

CIサービスの主な目的は、ブランチにプッシュするとき、またはリポジトリで他のアクションを実行するときにコードをtest/build/publishすることです。

アイデアは、設定ファイル(travis.ymlまたは。gitlab-ci.ymlなど)を提供し、ツールが世話をすることです。残りの。

あなたが本当にプロジェクトにライブラリを含めたくない場合は、CIがすべてを行うことを信頼してください:

  • Githookはコミット時にビルドをトリガーします(ブランチなどで-構成の問題です)
  • CIはファイルをビルドし、テストフェーズに渡し、公開します

今、私は自分のプロジェクトで(趣味の一部として)Webページを作成しているGitlabに取り組んでいます。プロジェクトをビルドするGitlab構成は次のようになります。

image: tetraweb/php

cache:
  untracked: true
  paths:
    - public_html/
    - node_modules/

before_script:
  - apt-get update

stages:
  - build
  - test
  - deploy

build_product:
  stage: build
  script:
    - npm run test

build_product:
  stage: build
  script:
    - npm run build

deploy_product:
  stage: deploy
  script:
    - npm run deploy

メインブランチにマージすると、次のイベントが発生します。

  • CIはbuildステージを実行します
  • ビルドが成功すると、testステージが起動します
  • testフェーズに問題がなければ、最終的にステージdeployがトリガーされます

スクリプトは、実行されるUNIXコマンドのリストです。

Configで任意のDockerイメージを指定できるため、実際にはいくつかの(またはインストールされていない)ツールがインストールされている任意のUnixバージョンを使用します。

パッケージがあります deploy-to-git 目的のリポジトリブランチにアーティファクトをデプロイします。

または、ここ(Travis CIの場合)にアーティファクトをリポジトリに公開する構成の一部:

travis-publish-to-git

(自分で使用しました)

その後、もちろん、CIを実行できます:

npm publish .

CIはUnixコマンドを実行するので、次のことができます(少なくともCIプロバイダーの束):

  • タグを公開します(タグをリリースしますか?)
  • すべてのREADMEとどこでもプロジェクトのバージョンを更新するトリガースクリプト
  • すべてのフェーズが成功した場合に通知を送信します

では私は何をすべきか:
私はコミットし、プッシュし、ツールが私が望む他のすべてを行うようにします。
その間、私は他の変更を行い、1〜10分後に更新レポートをメールで受け取ります。

そこには多くのCIプロバイダーがあります:

ここに、他のプロジェクトの別の例を添付します(。travis.yml):

language: generic
install:
    - npm install
script:
    - chmod u+x ./utest.sh 
    - chmod u+x ./self_test/autodetection_cli/someprogram.sh
    - cd self_test && bash ../utest.sh --ttools stime --tno-spinner

CIを設定してパッケージをプッシュおよび公開する場合、ehを心配することなく、常にコードの最新バージョンを使用するようにしてください。このコマンドも実行する必要があります。 。問題。

CIプロバイダーのいずれかを選択することをお勧めします。
最高のものは何百もの能力を提供します!

パブリッシュ、テスト、ビルドの各段階を自動的に行うことに慣れると、人生を楽しむのにどのように役立つかがわかります!
次に、自動スクリプトを使用して別のプロジェクトを開始するには、構成をコピーするだけです!

概要

私の意見ではnpm prepare scriptはオプションです。
他の人も試してみることもできます。

説明されている各方法には欠点があり、達成したい内容に応じて使用できます。
いくつかの選択肢を提供したいのですが、それらのいくつかがあなたの問題に合うことを願っています!

16

Package.jsonファイルのスクリプトフィールド内にbuildスクリプトがあると仮定すると、この状況でこれを自動的に実行するようにパッケージを構成できますか?

はい。あなたがする必要がある2つのことがあります:

  1. システムがnpmまたはyarnを使用してGitHubからパッケージをインストールしていることを確認してください。このパッケージが別のパッケージの依存関係である場合、package.jsonのバージョン番号の代わりにGitHub URLを使用できます。それ以外の場合、次のコマンドが機能します。

    npm install https://github.com/YourUser/your-package
    

    特定のタグまたはブランチの後にいる場合は、/tags/v1.0.0などをURLの末尾に追加できます。

  2. モジュールのpackage.jsonscriptsに次を追加します。

    "install": "npm run build"
    

installは、モジュールのインストール後にパッケージマネージャーが実行するフックです。 (preinstallおよびpostinstallも-ドキュメントを参照)。

ドキュメント: https://docs.npmjs.com/misc/scripts

3
Roy Tinker

編集2

それは素晴らしい質問です。信頼できる解決策が認められていないのは残念ですが、以下はうまくいくようです。

.buildmeマーカーファイルを作成し、gitにコミットします。

package.json

  "files": ["lib"],
  "scripts": {
    "build": "echo DO WHAT YOU NEED TO BUILD",
    "prepack": "[ ! -f .buildme ] || npm run build",
    "preinstall": "[ ! -f .buildme ] || npm run build"
  },

ここで注意すべき点があります。

  1. 特別な.buildmeマーカーファイルは、"files"キーを使用するか、.npmignoreを介してnpmパッケージから除外する必要があります。

  2. パブリッシュするとprepackフックが実行されます(prepublishOnlyも機能する可能性がありますが、prepacknpm packを使用すると正しいtarballが生成されるのは素晴らしいことです)。

  3. Npmからインストールする場合、preinstallは実行されますが、.buildmeがないため、何も実行されません([ ! -f .buildme ]句のおかげ)。

  4. Githubからインストールする場合、.buildmeは存在します。 npm6では、prepackフックがビルドを実行し(そして.buildmeなしでパッケージを生成します)、preinstallは何もしません。 yarn 1.12では、preinstallがビルドを行います。

  5. Githubから更新されたバージョンをインストールすると、preinstallが再度実行され、再度ビルドされます。

注:githubからインストールする場合、ビルドが機能するために十分なパッケージのdevDependenciesが既にインストールされているかどうかは、インストールする人次第です。 (このソリューションはdevDependenciesの自動インストールを試みません。)

それでおしまい。 npm 6とyarn 1.12のさまざまな組み合わせで動作するようです。

2
DS.

prepareは正しい方法です

ソースファイルを含むリポジトリがあるが、それを使用するために「ビルド」ステップが必要な場合、prepareはすべての場合に必要なことを正確に行います(npm 4以降)。

prepare:パッケージをパックして公開する前に、引数なしでローカルのnpm installで、およびgit依存関係をインストールするときに両方を実行します。

ビルドの依存関係をdevDependenciesに入れることもでき、prepareが実行される前にインストールされます。

このメソッドを使用する私のパッケージの です。


.gitignoreの問題

このオプションには、多くの人を惹きつける問題が1つあります。依存関係を準備するとき、NpmとYarnはpackage.jsonfilesセクションにリストされているファイルをonlyで保持します。

filesがデフォルトでインクルードされるすべてのファイルになります であり、完了したと思うかもしれません。簡単に見逃されるのは、.npmignoremostlyfilesディレクティブandをオーバーライドすることです。.npmignoreが存在しない場合は、.gitignoreが代わりに使用されます。

したがって、健全な人物のように.gitignoreにビルドファイルをリストしている場合、filesにビルドファイルをリストしないでください。また、.npmignoreファイルを使用しないでくださいprepareseembroken

filesを修正してビルドされたファイルのみを含めるか、空の.npmignoreを追加すれば、すべて完了です。

2