サイトアイコンmaita tomoya dev io

npm

フロントエンド基礎

npm

npmとは

npmは Node Package Manager の略で、JavaScriptのパッケージ(ライブラリやツール)を管理するためのツール。

「パッケージ」とは、誰かが作って公開してくれたコードの集まり。例えば「日付のフォーマットを簡単にする関数」「HTTPリクエストを簡単に送る関数」などが1つのパッケージとして公開されている。

npmは3つの側面を持っている:

側面説明
コマンドラインツールターミナルでnpm install等のコマンドを実行する
レジストリパッケージが公開されているオンラインのデータベース
Webサイトパッケージの検索・ドキュメント閲覧ができるサイト

npmレジストリには200万以上のパッケージが公開されており、世界最大のソフトウェアレジストリとなっている。

なぜnpmが必要なのか

車輪の再発明を避ける

「日付をYYYY-MM-DD形式に変換する」「バリデーションを行う」など、多くの開発者が必要とする機能を毎回自分で書くのは非効率。npmを使えば、既に十分にテストされた高品質なパッケージをインストールするだけで使える。

チーム開発での環境統一

package.jsonというファイルに「どのパッケージのどのバージョンを使っているか」を記録するため、チーム全員が同じ環境で開発できる。

npm installを実行するだけで、必要なパッケージが全て自動的にインストールされる

エコシステムの力

1つのパッケージが別のパッケージに依存し、さらに別のパッケージに依存する...という形で、巨大なエコシステムが形成されている。この依存関係をnpmが自動的に管理してくれる。

Node.jsとnpmの関係

Node.jsはJavaScriptをブラウザの外(サーバーやローカルPC)で実行するための実行環境。

npmはNode.jsをインストールすると一緒に付いてくるパッケージマネージャ。

Node.jsをインストール → npmも自動でインストールされる
# バージョンの確認
node -v   # Node.jsのバージョン(例: v20.11.0)
npm -v    # npmのバージョン(例: 10.2.4)

Node.jsのインストールは公式サイト(https://nodejs.org/)から。LTS(Long Term Support)版を選ぶのが推奨。

package.json

package.jsonはプロジェクトの設定ファイル。プロジェクトの名前、バージョン、使用するパッケージなどが記録されている。全てのNode.jsプロジェクトの根幹となるファイル。

作成方法

# 対話形式で作成(いくつかの質問に答える)
npm init

# 全てデフォルト値で作成(素早く始めたい場合)
npm init -y

構造の詳細

{
  "name": "my-project",
  "version": "1.0.0",
  "description": "プロジェクトの説明",
  "main": "index.js",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview",
    "lint": "eslint . --fix",
    "format": "prettier --write .",
    "test": "vitest"
  },
  "keywords": ["web", "app"],
  "author": "Your Name",
  "license": "MIT",
  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  },
  "devDependencies": {
    "vite": "^5.0.0",
    "eslint": "^8.56.0",
    "prettier": "^3.2.0",
    "vitest": "^1.2.0"
  }
}

各フィールドの解説

フィールド必須説明
nameはいプロジェクト名(小文字、ハイフン区切り推奨)
versionはいプロジェクトのバージョン
descriptionいいえプロジェクトの説明
mainいいえエントリーポイント(パッケージとして公開する場合)
scriptsいいえカスタムコマンドの定義(後述)
keywordsいいえnpm検索用のキーワード
authorいいえ作者名
licenseいいえライセンス
dependenciesいいえ本番環境で必要なパッケージ
devDependenciesいいえ開発時のみ必要なパッケージ
enginesいいえ必要なNode.jsやnpmのバージョン
privateいいえtrueにするとnpm publishを防止

npmの基本コマンド

コマンド一覧表

コマンド説明
npm initpackage.jsonを作成npm init -y
npm installpackage.jsonの依存関係を全てインストールnpm installnpm iと省略可)
npm install パッケージ名パッケージをインストールnpm install axios
npm install -D パッケージ名開発用パッケージをインストールnpm install -D vitest
npm uninstall パッケージ名パッケージを削除npm uninstall axios
npm updateパッケージを更新npm update
npm run スクリプト名カスタムスクリプトを実行npm run dev
npm testテストを実行npm testnpm tと省略可)
npm startアプリを起動npm start
npm listインストール済みパッケージを一覧表示npm list --depth=0
npm outdated更新可能なパッケージを表示npm outdated
npm auditセキュリティの脆弱性をチェックnpm audit
npm cache clean --forcenpmのキャッシュを削除npm cache clean --force
npm config listnpmの設定を表示npm config list
npm info パッケージ名パッケージの詳細情報を表示npm info react

インストールの実例

# パッケージのインストール(dependenciesに追加)
npm install react react-dom

# 開発用パッケージのインストール(devDependenciesに追加)
npm install -D typescript @types/react eslint prettier

# 特定のバージョンをインストール
npm install react@18.2.0

# package.jsonの全依存関係をインストール(プロジェクトを初めてセットアップするとき)
npm install

dependencies vs devDependencies

種類追加方法用途
dependenciesnpm install本番環境で動作に必要なパッケージreact, axios, express
devDependenciesnpm install -D開発時のみ必要なパッケージvitest, eslint, typescript

判断基準

「このパッケージがなくても、ビルド後のアプリは動くか?」と考える。

  • 動かないdependencies(react, express, axiosなど)
  • 動くdevDependencies(eslint, prettier, typescriptなど)
# dependencies(本番で必要)
npm install react           # UIライブラリ
npm install axios           # HTTPクライアント
npm install express         # Webフレームワーク
npm install zod             # バリデーション

# devDependencies(開発時のみ)
npm install -D typescript   # 型チェック(ビルド時に変換される)
npm install -D eslint       # コードの静的解析
npm install -D prettier     # コードフォーマット
npm install -D vitest       # テストフレームワーク
npm install -D @types/react # 型定義ファイル

注意: TypeScriptはdevDependenciesに入れる。なぜなら、TypeScriptのコードはビルド時にJavaScriptに変換されるため、本番環境ではTypeScript自体は不要だから。

package-lock.json

package-lock.jsonは、インストールされた全パッケージの正確なバージョンを記録するファイル。npm installを実行すると自動的に生成・更新される。

なぜ必要か

package.jsonには"react": "^18.2.0"のように範囲指定でバージョンが書かれている。この場合、18.2.0以上18.x.xの範囲の最新バージョンがインストールされる。

問題は、開発者Aがnpm installした時と、開発者Bがnpm installした時で、インストールされるバージョンが異なる可能性があること。

package-lock.jsonがあれば、全員が全く同じバージョンのパッケージをインストールできる。

開発者A: npm install → react 18.2.0がインストール、package-lock.jsonに記録
(2週間後にreact 18.2.1がリリース)
開発者B: npm install → package-lock.jsonがあるので、react 18.2.0がインストールされる

コミットすべきか

必ずGitにコミットする。 package-lock.jsonはプロジェクトに不可欠なファイル。

package.json        → コミットする
package-lock.json   → コミットする
node_modules/       → コミットしない(.gitignoreに追加)

npm ciコマンド

CI/CD環境(GitHub Actions等)では、npm installの代わりにnpm ciを使うのが推奨される。

# npm install: package-lock.jsonを「参考に」インストール(更新される場合がある)
npm install

# npm ci: package-lock.jsonに「厳密に従って」インストール(より確実)
npm ci

npm ciの特徴:

  • package-lock.jsonと完全に一致するバージョンをインストール
  • node_modulesを一旦削除してからクリーンインストール
  • package-lock.jsonを変更しない
  • npm installより高速

node_modules

node_modulesは、インストールされた全パッケージのソースコードが格納されるディレクトリ。

.gitignoreに入れる理由

  1. 巨大になる: 小さなプロジェクトでも数百MB、大きなプロジェクトでは1GB以上になることがある
  2. 復元可能: npm installを実行すればpackage.jsonpackage-lock.jsonから完全に復元できる
  3. OS依存: パッケージの一部はOS固有のバイナリを含むため、異なるOSでは再インストールが必要
# .gitignoreに追加
echo "node_modules/" >> .gitignore

なぜ巨大になるのか

パッケージAがパッケージBに依存し、パッケージBがパッケージCとDに依存し...という依存の連鎖により、インストールされるパッケージが雪だるま式に増える。

あなたが入れたパッケージ: 5個
↓
それらが依存するパッケージ: 50個
↓
さらにその依存: 500個
↓
node_modulesの中: 555個のパッケージ

これは開発者コミュニティで有名な「heaviest objects in the universe(宇宙で最も重い物体)」というミーム(インターネット上で広まったジョーク)のネタにもなるほど。node_modulesの肥大化はJavaScriptエコシステムの特徴的な課題として広く認知されている。

npx

npxnpm exec の省略形で、パッケージをインストールせずに一時的に実行するコマンド。npm 5.2以降に付属している。

使い所

# プロジェクトの初期化(一度だけ使うツール)
npx create-react-app my-app
npx create-vite my-app
npx create-next-app my-app

# ローカルにインストールされたパッケージの実行
npx eslint .
npx prettier --write .
npx vitest

# 一時的な実行(インストールしない)
npx cowsay "Hello"    # 遊び用のコマンド(一度だけ実行)

npmとの違い

# npm: パッケージをインストールする
npm install -g create-vite   # グローバルにインストール
create-vite my-app            # 実行

# npx: インストールせずに実行(推奨)
npx create-vite my-app        # 一時的にダウンロードして実行

npxの利点:

  • 常に最新バージョンが使われる
  • グローバル環境を汚さない
  • ディスク容量を節約できる

セマンティックバージョニング

npmのパッケージはセマンティックバージョニング(SemVer)というルールに従ってバージョンを管理する。

バージョン番号の構造

MAJOR.MINOR.PATCH
例: 18.2.1

MAJOR: 破壊的変更(既存のコードが動かなくなる可能性がある)
MINOR: 後方互換性のある機能追加
PATCH: 後方互換性のあるバグ修正

バージョン指定記号

記号意味インストールされる範囲
なし完全一致18.2.118.2.1のみ
^MINOR/PATCHの更新を許可^18.2.118.2.1 以上 19.0.0 未満
~PATCHの更新のみ許可~18.2.118.2.1 以上 18.3.0 未満
>=指定以上>=18.0.018.0.0以上の全て
*全バージョン*全て
latest最新版latest最新リリース

使い分けの指針

{
  "dependencies": {
    "react": "^18.2.0", // ^(キャレット): 最も一般的。npmデフォルト
    "express": "~4.18.0", // ~(チルダ): パッチのみ更新。慎重に使いたい場合
    "lodash": "4.17.21" // 固定: 絶対にバージョンを変えたくない場合
  }
}

実務では^(キャレット)がデフォルト。 npm installで追加すると自動的に^が付く。

スクリプト(npm scripts)

package.jsonscriptsフィールドにカスタムコマンドを定義し、npm runで実行できる。

基本的な使い方

{
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview",
    "lint": "eslint . --fix",
    "format": "prettier --write .",
    "test": "vitest",
    "test:coverage": "vitest --coverage",
    "type-check": "tsc --noEmit",
    "prepare": "husky"
  }
}
# 実行方法
npm run dev          # 開発サーバーを起動
npm run build        # 本番用ビルド
npm run lint         # コードの静的解析 + 自動修正
npm run format       # コードフォーマット
npm test             # テスト実行(npm run testの省略形)
npm run test:coverage # テストカバレッジ付きで実行

特別なスクリプト名

以下のスクリプト名はnpm runなしで実行できる。

スクリプト名実行方法用途
startnpm startアプリの起動
testnpm testテストの実行
prepare自動実行インストール後に自動実行
preinstall自動実行インストール前に自動実行
postinstall自動実行インストール後に自動実行

pre / postフック

スクリプト名の前にprepostを付けると、メインのスクリプトの前後に自動実行される。

{
  "scripts": {
    "prebuild": "echo 'ビルド前の処理'",
    "build": "vite build",
    "postbuild": "echo 'ビルド後の処理'"
  }
}
npm run build
# 1. prebuildが実行される
# 2. buildが実行される
# 3. postbuildが実行される

スクリプトの連結

{
  "scripts": {
    "check": "npm run lint && npm run type-check && npm test",
    "ci": "npm ci && npm run check && npm run build"
  }
}
  • &&: 前のコマンドが成功した場合のみ次を実行
  • ||: 前のコマンドが失敗した場合に次を実行
  • ;: 前のコマンドの成否に関わらず次を実行

グローバルインストール vs ローカルインストール

種類コマンドインストール先用途
ローカル(推奨)npm install パッケージ名./node_modulesプロジェクト固有
グローバルnpm install -g パッケージ名システム全体コマンドラインツール

ローカルインストールが推奨される理由

  1. プロジェクトごとにバージョンを変えられる: プロジェクトAではv1、プロジェクトBではv2を使うことが可能
  2. 依存関係が明示される: package.jsonに記録されるため、他の開発者も同じ環境を再現できる
  3. バージョン競合を避けられる: グローバルに入れると、全プロジェクトで同じバージョンを強制されてしまう
# ローカルインストール(推奨)
npm install eslint
npx eslint .        # npxでローカルのパッケージを実行

# グローバルインストール(限定的に使う)
npm install -g npm   # npm自体の更新
npm install -g vercel # デプロイツール等、プロジェクトに依存しないCLIツール

グローバルインストールが適している場合

  • npm自体の更新(npm install -g npm
  • プロジェクトに依存しないCLIツール(vercel, netlify-cli等)
  • 頻繁に使うスキャフォールディングツール(ただしnpxを使う方が推奨)

npm vs yarn vs pnpm

JavaScriptのパッケージマネージャは3つある。

特徴npmyarnpnpm
開発元npm Inc(GitHub社)Facebook(Meta)コミュニティ
付属Node.jsに標準付属別途インストール別途インストール
ロックファイルpackage-lock.jsonyarn.lockpnpm-lock.yaml
速度普通速い最速
ディスク使用量多い多い少ない(ハードリンク)
Workspaces対応対応対応
Plug'n'Play非対応対応(yarn berry)非対応
厳格さ緩い緩い厳格(幽霊依存を防止)
学習コスト低い(標準)低いやや高い

コマンドの対応表

操作npmyarnpnpm
インストールnpm installyarnpnpm install
パッケージ追加npm install pkgyarn add pkgpnpm add pkg
開発用パッケージ追加npm install -D pkgyarn add -D pkgpnpm add -D pkg
パッケージ削除npm uninstall pkgyarn remove pkgpnpm remove pkg
スクリプト実行npm run devyarn devpnpm dev
グローバル追加npm install -g pkgyarn global add pkgpnpm add -g pkg

どれを選ぶべきか

  • npm: 初心者はまずこれで学ぶ。Node.js標準で追加インストール不要
  • yarn: Facebookが開発。大規模プロジェクトでの実績が豊富
  • pnpm: ディスク効率が良く、厳格な依存関係管理。モノレポに強い

プロジェクトに参加する際は、そのプロジェクトが使っているパッケージマネージャに合わせる。ロックファイルの種類で判断できる。

package-lock.json → npm
yarn.lock         → yarn
pnpm-lock.yaml    → pnpm

セキュリティ

npm audit

プロジェクトの依存パッケージに既知の脆弱性がないかチェックするコマンド。

# 脆弱性のチェック
npm audit

# 出力例:
# found 3 vulnerabilities (1 low, 1 moderate, 1 high)
#   info  - https://github.com/advisories/GHSA-xxxx
#   moderate - パッケージ名@バージョン
#   high - パッケージ名@バージョン

# 自動修正を試みる
npm audit fix

# 破壊的変更を伴う修正も含める(注意して使う)
npm audit fix --force

セキュリティのベストプラクティス

  1. 定期的にnpm auditを実行する: CI/CDパイプラインに組み込むのが理想
  2. 不要なパッケージは削除する: 使っていないパッケージは脆弱性のリスクを不必要に増やす
  3. パッケージの人気度と信頼性を確認する: ダウンロード数、GitHubのスター数、最終更新日を確認
  4. ロックファイルをコミットする: 想定外のバージョンがインストールされるのを防ぐ
  5. Dependabot / Renovateを活用する: GitHubのDependabotは脆弱性を検知してPRを自動作成してくれる

怪しいパッケージの見分け方

# パッケージの情報を確認
npm info パッケージ名

# 確認すべきポイント:
# - 最終更新日(長期間更新がないものは注意)
# - 週間ダウンロード数(少なすぎるものは注意)
# - ライセンス(商用利用可能か)
# - 依存パッケージの数(多すぎるものは注意)

.npmrc

.npmrcはnpmの設定ファイル。プロジェクトルートに配置する。

# レジストリの設定(プライベートレジストリを使う場合)
registry=https://registry.npmjs.org/

# パッケージのインストール時にpackage-lock.jsonを常に生成
package-lock=true

# npm installの進行状況表示を抑制
progress=false

# エンジンの不一致を厳格にチェック
engine-strict=true

# Node.jsのバージョン指定(チーム全員が同じバージョンを使うよう強制)
# package.jsonのenginesフィールドと併用

package.jsonでのengines指定:

{
  "engines": {
    "node": ">=18.0.0",
    "npm": ">=9.0.0"
  }
}

実務でよく使うパッケージ10選

フロントエンド

パッケージ説明インストール
reactUIライブラリnpm install react react-dom
nextReact用フルスタックフレームワークnpx create-next-app
axiosHTTPクライアントnpm install axios
zodスキーマバリデーションnpm install zod
date-fns日付操作ライブラリnpm install date-fns

開発ツール

パッケージ説明インストール
typescript型付きJavaScriptnpm install -D typescript
eslintコードの静的解析npm install -D eslint
prettierコードフォーマッターnpm install -D prettier
vitestテストフレームワークnpm install -D vitest
huskyGitフック管理npm install -D husky

各パッケージの簡単な使用例

# Axiosの例
npm install axios
import axios from 'axios'

const fetchUsers = async () => {
  try {
    const response = await axios.get('https://api.example.com/users')
    return response.data
  } catch (error) {
    console.error('エラー:', error.message)
  }
}
# Zodの例
npm install zod
import { z } from 'zod'

// スキーマの定義
const userSchema = z.object({
  name: z.string().min(1, '名前は必須です'),
  email: z.string().email('メールアドレスが無効です'),
  age: z.number().min(0).max(150),
})

// バリデーション
try {
  const user = userSchema.parse({
    name: '太郎',
    email: 'taro@example.com',
    age: 25,
  })
  console.log('有効なデータ:', user)
} catch (error) {
  console.error('バリデーションエラー:', error.errors)
}
# date-fnsの例
npm install date-fns
import { format, addDays, differenceInDays } from 'date-fns'
import { ja } from 'date-fns/locale'

const now = new Date()
console.log(format(now, 'yyyy年MM月dd日(E)', { locale: ja }))
// 例: 2026年3月28日(土)

const nextWeek = addDays(now, 7)
console.log(differenceInDays(nextWeek, now)) // 7

npmのよくあるトラブルと対処法

1. npm installが失敗する

# キャッシュをクリアしてやり直す
npm cache clean --force
rm -rf node_modules
rm package-lock.json
npm install

2. permission denied(権限エラー)

# グローバルインストールで権限エラーが出る場合
# NG: sudo npm install -g package(sudoは使わない)

# OK: npmのデフォルトディレクトリを変更
mkdir ~/.npm-global
npm config set prefix '~/.npm-global'
# シェルの設定ファイル(.zshrc等)にPATHを追加
# export PATH=~/.npm-global/bin:$PATH

3. peer dependency警告

# 警告例: npm WARN peer dep required react@^17.0.0

# 対処: 互換性のあるバージョンをインストール
npm install react@17
# または: 警告を無視して強制インストール(注意して使う)
npm install --legacy-peer-deps

4. node_modulesが壊れた

# 完全にリセット
rm -rf node_modules
rm package-lock.json
npm install

参考リンク