💨

package.jsonのscriptsを深堀りしてみた。

2024/10/01に公開

はじめに

2024年現在、cssやjsを使う多くのプロジェクトでpackage.jsonを見ることになると思います。
サーバサイド主体のプログラマーでも全く知らないと環境構築できないため必須の知識となっています。

しかし、ほとんどの人はコピペでコマンドを動かしていて、npm run が何をやっているのか知らないのではないでしょうか?
深堀してみましょう。

scriptsはショートカット

package.json
{
    "private": true,
    "scripts": {
        "dev": "npm run development",
        "development": "mix",
        "watch": "mix watch",
        "watch-poll": "mix watch -- --watch-options-poll=1000",
        "hot": "mix watch --hot",
        "prod": "npm run production",
        "production": "mix --production",
        "build": "mix",
        "tsc": "tsc",
        "lint": "eslint .",
        "stylelint": "stylelint '**/*.scss'"
    },
    "devDependencies": {
        "@eslint/js": "^9.10.0",
        "axios": "^0.21",
        "eslint": "^9.10.0",
        "globals": "^15.9.0",
        "laravel-mix": "^6.0.6",
        "lodash": "^4.17.19",
        "postcss": "^8.1.14",
        "resolve-url-loader": "^5.0.0",
        "sass": "^1.78.0",
        "sass-loader": "^16.0.1",
        "stylelint": "^16.9.0",
        "stylelint-config-recess-order": "^5.1.0",
        "stylelint-config-standard": "^36.0.1",
        "stylelint-config-standard-scss": "^13.1.0",
        "ts-loader": "^9.5.1",
        "typescript": "^5.6.2",
        "typescript-eslint": "^8.5.0"
    }
}

まず、npm run ◯◯ の◯◯が"scripts": {}ブロックの中で定義されています。
ここに "dev" って書いてあるから npm run dev というコマンドが使えるわけです。
で、これはまた

"dev": "npm run development"

とあるので、これは"development": "mix"につながって、

npm run mix 

と同義です。

そんなことしてなんの意味があるのかというと、大抵のプロジェクトでnpm run devってあるので、よくわかってない人もカンで使えるようにするためです。

まあ、ここまでは知ってる人も結構いると思います。
なのでもっと掘り下げます。

scripts の右辺はどこからきた?

結論から言うと、node_modules/.bin の中にあるフォルダのスクリプトが実行されています。

じゃあ、上にあるnode_modules/ 直下のフォルダと何が違うのかというと、node_modules/.binに入っているのはプログラムの起点として実行可能なスクリプトで、それ以外のどこかから呼び出される部品がnode_modules/ 直下に入っています。

C/C++言語とかだとexeとdllの関係が近いと思います。

試しに以下のファイルをnode_modules/.binの下に作ってみましょう。

hello
#!/usr/bin/env node
"use strict"

console.log('Hello node_module!!');

1行目はただのコメントではなくて、シバンといって、どのエンジンで動かすスクリプトかを示すものです。#!/bin/bashならよく見ると思いますが、これはnodeを動かすための記述になります。
これを書かないと動きません。

で、"greet": "hello"をpackage.jsonに追加します。

package.json
{
    "private": true,
    "scripts": {
        "dev": "npm run development",
        "development": "mix",
        "watch": "mix watch",
        "watch-poll": "mix watch -- --watch-options-poll=1000",
        "hot": "mix watch --hot",
        "prod": "npm run production",
        "production": "mix --production",
        "build": "mix",
        "tsc": "tsc",
        "lint": "eslint .",
        "stylelint": "stylelint '**/*.scss'",
        "greet": "hello"
    },
    "devDependencies": {
        "@eslint/js": "^9.10.0",
        "axios": "^0.21",
        "eslint": "^9.10.0",
        "globals": "^15.9.0",
        "laravel-mix": "^6.0.6",
        "lodash": "^4.17.19",
        "postcss": "^8.1.14",
        "resolve-url-loader": "^5.0.0",
        "sass": "^1.78.0",
        "sass-loader": "^16.0.1",
        "stylelint": "^16.9.0",
        "stylelint-config-recess-order": "^5.1.0",
        "stylelint-config-standard": "^36.0.1",
        "stylelint-config-standard-scss": "^13.1.0",
        "ts-loader": "^9.5.1",
        "typescript": "^5.6.2",
        "typescript-eslint": "^8.5.0"
    }
}

それで、node_modules/.bin/hello に実行権限を与えます。

chmod +x node_modules/.bin/hello

ここまで準備できたら、npm run greet実行します。
以下のようにhelloに書いたconsole.logが動いたはずです。

npm run greet

> @ greet /Users/onewedge/project/src
> hello

Hello node_module!!

まとめ

いかがだったでしょうか?フロントで毎日npm run している人でも知らなかったのでは?

今回は仕組みを勉強するために直接触ってみましたが、実際にはnode_modulesの中に手動で何かを入れてはいけません。
そもそもnode_modulesフォルダはgitにコミットしないのが普通なので、そんなところに入れても更新したら消えます。

私がこれを知ろうと思ったのはBunという最近話題のコンパイラが気になってインストール時にうまく動かなったため、パスの関係を調べていたところ、ふと疑問に思ったからです。

みなさんも疑問をスルーせずに突き詰めると面白いことがわかるかもしれません。

株式会社ONE WEDGE

【Serverlessで世の中をもっと楽しく】 ONE WEDGEはServerlessシステム開発を中核技術としてWeb系システム開発、AWS/GCPを利用した業務システム・サービス開発、PWAを用いたモバイル開発、Alexaスキル開発など、元気と技術力を武器にお客様に真摯に向き合う価値創造企業です。
https://onewedge.co.jp

Discussion