npmスクリプトとpackage.jsonの説明
npmとは何ですか?
npmは、js開発者がコードの共有と再利用を容易にするために、フロントエンド開発者に広く利用されているパッケージ管理ツールです。繰り返し使えるフレームワークのコードはパッケージまたはモジュールと呼ばれ、パッケージはその中にあるいくつかのフォルダとpackage.jsonファイルで構成されています。
1. npmスクリプトとは何ですか?
vueプロジェクトやreactプロジェクトなど、node.jsのプロジェクトを作成すると、プロジェクトはpackage.jsonという記述ファイルを生成します。
例えば、npmではscriptsフィールドを使用して、package.jsonファイルにスクリプトコマンドを定義することができます。
{
//...
"scripts": {
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
"start": "npm run dev",
"e2e": "node test/e2e/runner.js",
"test": "npm run e2e",
"lint": "eslint --ext .js,.vue src test/e2e/specs",
"build": "node build/build.js"
},
}
上記のコードは、package.jsonファイルの断片で、scriptsフィールドはオブジェクトです。scriptsフィールドはオブジェクトで、その属性がスクリプトに対応する。例えば、ビルドコマンドに対応するスクリプトは、node build.js です。
このスクリプトは、コマンドラインでnpm runコマンドを使用することで実行できる。
$ npm run build
実行することに相当する。
$ node build/build.js
同様に、上記のスクリプトでは、npm run test は npm run e2e 、これは node test/e2/runner.js と等価である
package.jsonで定義されたこれらのスクリプトをnpm scriptsと呼ぶ。あるプロジェクトに関連するスクリプトを一箇所に集中させることができます。異なるプロジェクトのスクリプトコマンドでも、同じ機能であれば、同じ外部インターフェイスを持つことができます。例えば、プロジェクトのテスト方法を知る必要がない場合、npm run devを実行するだけでよい。
現在のプロジェクトのすべての npm スクリプトコマンドを表示するには、引数なしで npm run コマンドを使用します。
$ npm run
2. npmの原則
npmスクリプトの原理は非常にシンプルである。npm runを実行すると、自動的にシェルスクリプトが作成され、指定されたスクリプトコマンドをシェル内部で実行する。つまり、npmスクリプトに書けるのは、シェル(通常はbash)で実行可能なコマンドのみである。
特に、npm runは、カレントディレクトリのnode_modules/.binサブディレクトリをPATH変数に追加し、実行後にPATH変数を元の状態に戻すというものです。また、カレントディレクトリの node_modules/.bin サブディレクトリにあるすべてのスクリプトは、パスを追加する代わりにスクリプト名で直接呼び出せるようになります。例えば、現在のプロジェクトに Mocha が依存関係としてある場合、mocha test と書くだけでよいのです。
"test": "mocha test"
のように書くのではなく、以下のようにします。
"test": ". /node_modules/.bin/mocha test"
npmスクリプトの要件はシェルで実行できることのみなので、Nodeスクリプトである必要はなく、どんな実行ファイルでも書くことができます。npmスクリプトには終了コードがあり、それもシェルスクリプトの規則に従ったものです。終了コードが0でない場合、npmはスクリプトの実行に失敗したものと見なします。
3. ワイルドカード
npmスクリプトはシェルスクリプトなので、シェルワイルドカードを使用することができます。
"lint": "jshint *.js"
"lint": "jshint **/*.js"
上記のコードで、*は任意のファイル名、**は任意のサブディレクトリの階層を意味します。元のコマンドにワイルドカードを渡し、シェルによってエスケープされないようにするには、*記号をエスケープします。
"test": "tap test/\*.js"
4. パラメータの受け渡し
npmスクリプトにパラメータを渡す(--マーク)。
"lint": "jshint **.js"
上記のnpm run lintコマンドに引数を渡すには、以下のように記述する必要があります。
$ npm run lint -- --reporter checkstyle > checkstyle.xml
また、package.jsonの中に再びコマンドを記述することもできます。
"lint": "jshint **.js",
"lint:checkstyle": "npm run lint -- --reporter checkstyle > checkstyle.xml"
5. 実行順序
npmスクリプト内で実行されるタスクが複数ある場合、その実行順序を指定する必要があります。並列実行(同時並行実行)の場合は、&記法が使えます。
$ npm run script1.js & npm run script2.js
リレー実行(前のタスクが成功した場合のみ次のタスクが実行できる)の場合は、&&記法が使える。
$ npm run script1.js && npm run script2.js
6. 既定値
一般に、npmスクリプトはユーザーによって提供されます。しかし、npmは2つのスクリプトのデフォルト値を提供します。つまり、この2つのスクリプトは定義することなく、直接使用することができます。
"start": "node server.js".
"install": "node-gyp rebuild"
上記のコードでは、server.js スクリプトがプロジェクトルートにある場合、npm run start のデフォルト値は node server.js となり、binding.gyp ファイルがプロジェクトルートにある場合、npm run install のデフォルト値は node-gyp rebuild となっています。
7.フック
npmスクリプトは、preとpostの2つのフックを持ちます。例えば、build scriptコマンドのフックは、prebuildとpostbuildです。
"prebuild": "echo I run before the build script",
"build": "cross-env NODE_ENV=production webpack",
"postbuild": "echo I run after the build script"
ユーザーがnpm run buildを実行すると、以下の順序で自動的に実行されます。
npm run prebuild && npm run build && npm run postbuild
つまり、いくつかの準備と後始末は、この2つのフックの内部で行うことができるのです。以下はその例である。
"clean": "rimraf . /dist && mkdir dist",
"prebuild": "npm run clean",
"build": "cross-env NODE_ENV=production webpack"
デフォルトでは、npmはこれらのフックを以下のように提供しています。
prepublish, postpublish
preinstall, postinstall
preuninstall, postuninstall
preversion, postversion
pretest, posttest
prestop, poststop
prestart, poststart
prerestart, postrestart
カスタムスクリプトコマンドには、プリフックとポストフックを追加することもできます。例えば、スクリプトコマンドである myscript も premyscript と postmyscript フックを持ちます。ただし、pre と post のダブルは無効で、たとえば、prepretest と postosttest は無効です。
npmは、pretest, test, posttestなど、現在実行中のスクリプトコマンドを返すnpm_lifecycle_event変数を提供します。そのため、この変数を利用して、同じスクリプトファイル内で異なるnpm scriptsコマンドのコードを記述することができます。次の例で考えてみましょう。
const TARGET = process.env.npm_lifecycle_event;
if (TARGET === 'test') {
console.log(`Running the test task!`);
}
if (TARGET === 'pretest') {
console.log(`Running the pretest task!`);
}
if (TARGET === 'posttest') {
console.log(`Running the posttest task!`);
}
prepublishフックは、npm publishコマンドの前に実行されるだけでなく、npm install(引数なし)コマンドの前にも実行されることに注意してください。この動作はユーザーを混乱させたので、npm 4ではprepublishと同じ動作をする新しいフックprepareが導入され、npm 5からはprepublishはnpm publishコマンドの前にのみ実行されるようになりました。
8. 省略可能な形式
4つの一般的なnpmスクリプトには、短縮形があります。
npm start は npm run start の短縮形 npm stop は npm run stop の短縮形 npm test は npm run test の短縮形 npm restart は npm run stop && npm run restart && npm run start npm restart は複合コマンドで、実際には stop, restart, start という三つのスクリプトコマンド を実行する。具体的な実行順序は以下の通りです。
prerestart prestop stop poststop restart prestart start poststart postrestart
9. 変数
npmスクリプトの非常に強力な機能の1つは、npmの内部変数を使用する機能です。
まず、npm_package_という接頭辞をつけると、npmスクリプトはpackage.jsonの中のフィールドを取得することができる。例えば、以下のようなpackage.jsonがあります。
{
"name": "foo",
"version": "1.2.5",
"scripts": {
"view": "node view.js"
}
}
すると、変数 npm_package_name は foo を返し、変数 npm_package_version は 1.2.5 を返します。
// view.js
console.log(process.env.npm_package_name); // foo
console.log(process.env.npm_package_version); // 1.2.5
上記のコードでは、環境変数process.envオブジェクトを通してpackage.jsonフィールドの値を取得しています。bashスクリプトであれば
$npm_package_name
と
$npm_package_version
両方の値と結婚した。
npm_package_ 接頭辞は、package.json フィールドのネストにも対応しています。
"repository": {
"type": "git",
"url": "xxx"
},
scripts: {
"view": "echo $npm_package_repository_type"
}
上記コードのリポジトリフィールドのtype属性は、npm_package_repository_typeで取得することができます。
別の例を示します。
"scripts": {
"install": "foo.js"
}
上記のコードでは、変数 npm_package_scripts_install の値が foo.js と等しくなっています。
そして、npmスクリプトは、npm config get xxxコマンドで返される値であるnpm設定変数を、npm_config_という接頭辞を通して取得することも可能です。例えば、現在のモジュールのリリースタグは npm_config_tag で取得することができます。
"view": "echo $npm_config_tag",
package.json内のconfigオブジェクトは、環境変数で上書きすることができることに注意してください。
{
"name" : "foo",
"config" : { "port" : "8080" },
"scripts" : { "start" : "node server.js" }
}
上記のコードでは、npm_package_config_port変数が8080を返しています。この値は、以下のメソッドでオーバーライドすることができます。
$ npm config set foo:port 80
最後に、envコマンドですべての環境変数を一覧表示します。
"env": "env"
10. 一般的なスクリプト例
// Delete the directory
"clean": "rimraf dist/*",
// Build an HTTP service locally
"serve": "http-server -p 9090 dist/",
// Open a browser
"open:dev": "opener http://localhost:9090",
// Real-time refresh
"liveload": "live-reload --port 9091 dist/",
// Build the HTML file
"build:html": "jade index.jade > dist/index.html",
// Re-execute the build whenever the CSS file has changed
"watch:css": "watch 'npm run build:css' assets/styles/",
// re-run the build whenever there are changes to the HTML file
"watch:html": "watch 'npm run build:html' assets/html",
// Deploy to Amazon S3
"deploy:prod": "s3-cli sync . /dist/ s3://example-com/prod-site/",
// build favicon
"build:favicon": "node scripts/favicon.js",
11, package.json その他の設定項目説明
依存関係やdevDependenciesに関するいくつかの注意点について。
npm で依存関係をインストールする場合、-save でインストールされた依存関係は、dependencies モジュールに書き込まれます。
save-dev でインストールされた依存関係は devDependencies モジュールに書き込まれます。何も書き込まれない場合、それらはデフォルトで dependencies にインストールされます。
例えば、glup や webpack など、開発環境でしか使わないビルドツールは、単純に devDependencies に書き込まれます。
いずれの環境でも、設定ファイルにprocess.env.NODE_ENV = 'development'、process.env.NODE_ENV = 'production' を指定して、開発環境か本番環境かを指定します。
12. package.json の bin 属性
package.jsonのbinは、コマンド名とローカルファイルとの対応付けです。グローバルインストールの場合は、グローバルなbinにマッピングされ、インストール後は、任意の場所でターミナルを開いてコマンドラインを使ってファイルを実行します。
ローカルインストールであれば、このプロジェクトの ./node_modules/.bin フォルダにファイルをマッピングし、インストール後にこのプロジェクトディレクトリのコマンドラインからファイルを実行します。
例
新しいフォルダを作成し、ターミナルを開いてそのフォルダに移動し、npm init -yのコマンドでpackage.jsonファイルを作成します。次に、package.jsonファイルと同じディレクトリにindex.jsファイルを新規に作成し、テストデータを追加します。なお、index.jsファイルのヘッダには、#! /usr/bin/env node ノード。package.jsonにbin属性を追加し、コマンド名とindex.jsの対応関係を設定します。ターミナルのカレントディレクトリにnpm install -gとグローバルインストールし、パソコンの任意のフォルダでターミナルを開き、package.jsonのbinに設定されたコマンドを実行すると、index.jsのコードが実行されます。以下は、その図です。
一方、グローバルbinフォルダを開くと、binの下に先ほど追加したグローバルコマンドtan-temp-binがあります。
一般的なvue、vue-cli、create-react-appなどのように、コマンドはbin属性でグローバルにマッピングされます。
要約すると
上記はnpmスクリプトとpackage.jsonの小さな紹介です、私はそれがあなたの助けになることを願って、もし何か質問があれば、私にメッセージを与えてください、私は時間内にあなたに返信されます。もし何か質問があれば、私にメッセージを残してください、私はあなたに迅速に返信します。また、スクリプトハウスのウェブサイトを応援していただき、ありがとうございました! この記事はあなたに役立つと思う場合は、再現することを歓迎し、ソースを指定してください、ありがとうございました!
関連
-
InstallShield でホスト名から IP アドレスを取得するコード
-
スクリプトとは何かを簡単に説明します。
-
[解決済み】 mean() 警告:引数が数値または論理でない:NAを返す
-
[解決済み】ウィンドウ階層にないビューを持つUIViewControllerでUIViewControllerを表示しようとする
-
[解決済み】git pullしようとするとエラー: .git/FETCH_HEAD を開けない: パーミッションが拒否される
-
[解決済み】エラー「C++はメソッド定義中のすべての宣言に型指定子を必要とする」。
-
[解決済み】main関数で "control reaches end of non-void function "という警告が出るのはなぜ?
-
[解決済み】Javascript Uncaught TypeError: 未定義のプロパティ'0'を読み取れない
-
[解決済み】TypeError: 'float'オブジェクトがsubscriptableでない
-
python startup prompt IDLEのサブプロセスが接続できない問題が発生しました。
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】gitが「変更をコミットするか、マージする前に隠してください」と言うのを解決するにはどうしたらいいですか?
-
[解決済み】C#コンパイラーエラー。"すべてのコードパスが値を返すわけではない"
-
[解決済み】CSV入力で1行目の列数が不正になるエラー
-
[解決済み】imdb.load_data()関数の「allow_pickle=Falseのときにオブジェクト配列を読み込むことができない」を修正するには?
-
[解決済み】Objective-Cで「認識できないセレクタがインスタンスに送信されました」エラー
-
[解決済み】非静的メンバ関数の無効な使用 【重複あり
-
[解決済み】なぜクラスの再定義エラーが発生するのでしょうか?
-
[解決済み] org.glassfish.jersey.servlet.ServletContainer ClassNotFoundException
-
[解決済み】演算子のオーバーロード時のエラー(非静的メンバ関数でなければならない)
-
[解決済み】「Fatal error: Unexpectedly found nil while unwrapping an Optional value "とはどういう意味ですか?