npm installとnpm ciの使い分け

npm インストールについてなんとなくnpm installを実行していたが、たまにpackage-lock.jsonが更新されてしまうことがあった。

## 登場人物
### npm
Node.jsのパッケージを管理するシステム

### install
npmが使えるインストールコマンド

### ci
npmが使えるインストールコマンド

### package.json
インストールするパッケージが記載している

### package-lock.json
インストールされているパッケージが記載している



## 組み合わせ

### npm install
package.jsonとpackage-lock.jsonを見て依存関係を解決してインストール
node_modulesフォルダ作成 npm x install = package-lock.json

環境構築時や追加インストール時に利用。

### npm ci
package.json の依存関係の解決を行わない。
package-lock.json を見て依存パッケージをダウンロードし node_modules の洗い替えを行う。

CI実行、git clone後にはこちらを使った方が良い。

## 事例

### 開発環境を複製
Aさんが構築した開発環境のdockerの関連ファイルが共有されている。
ソースコードはgit管理されている。

Bさんが開発環境を構築する為、gitのソースコードをローカル環境にCloneしました。
そのあと、Bさんの環境にdocker関連ファイルを配置して、dockerを起動。
コンテナ起動後にnpm installを実施して、node_modulesフォルダ作成しました。
この時に、package-lock.jsonが更新されていました。
更新されたpackage-lock.jsonをgitにマージ。
マージしたブランチをサーバーにデプロイするとエラーが発生しました。

### デプロイ時のエラー

```shell
found 96 vulnerabilities (2 low, 83 moderate, 9 high, 2 critical)
  run `npm audit fix` to fix them, or `npm audit` for details
-----npmビルドの開始------

> app@0.1.0 dev /var/www/frontend/releases/xxxxxxxxxx
> vue-cli-service build --mode development


-  Building for development...
 ERROR  Failed to compile with 1 error5:26:11 PM

 error  in src/main.ts:13:1

TS2769: No overload matches this call.
  Overload 1 of 2, '(plugin: Plugin<[opts: InstallOptions]>, opts: InstallOptions): App<Element>', gave the following error.
    Argument of type '{ locale: { name: string; el: { colorpicker: { confirm: string; clear: string; }; datepicker: { now: string; today: string; cancel: string; clear: string; confirm: string; selectDate: string; selectTime: string; ... 22 more ...; months: { ...; }; }; ... 10 more ...; popconfirm: { ...; }; }; }; }' is not assignable to parameter of type 'InstallOptions'.
      Type '{ locale: { name: string; el: { colorpicker: { confirm: string; clear: string; }; datepicker: { now: string; today: string; cancel: string; clear: string; confirm: string; selectDate: string; selectTime: string; ... 22 more ...; months: { ...; }; }; ... 10 more ...; popconfirm: { ...; }; }; }; }' is missing the following properties from type 'InstallOptions': size, zIndex
  Overload 2 of 2, '(plugin: Plugin<[opts: InstallOptions]>, options: [opts: InstallOptions]): App<Element>', gave the following error.
    Argument of type '{ locale: { name: string; el: { colorpicker: { confirm: string; clear: string; }; datepicker: { now: string; today: string; cancel: string; clear: string; confirm: string; selectDate: string; selectTime: string; ... 22 more ...; months: { ...; }; }; ... 10 more ...; popconfirm: { ...; }; }; }; }' is not assignable to parameter of type '[opts: InstallOptions]'.
      Object literal may only specify known properties, and 'locale' does not exist in type '[opts: InstallOptions]'.
    11 | const app = createApp(App)
    12 | app.use(router)
  > 13 | app.use(ElementPlus, { locale })
       | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    14 | app.use(VuePapaParse)
    15 | app.mount('#app')
    16 |

 ERROR  Build failed with errors.
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! app@0.1.0 dev: `vue-cli-service build --mode development`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the app@0.1.0 dev script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /home/ec2user/.npm/_logs/2024-01-01T08_16_11_120Z-debug.log

```


デバッグログファイルのの中身

```shell
0 info it worked if it ends with ok
1 verbose cli [
1 verbose cli   '/home/ec2user/.nvm/versions/node/v14.21.3/bin/node',
1 verbose cli   '/home/ec2user/.nvm/versions/node/v14.21.3/bin/npm',
1 verbose cli   'run',
1 verbose cli   'dev'
1 verbose cli ]
2 info using npm@6.14.18
3 info using node@v14.21.3
4 verbose run-script [ 'predev', 'dev', 'postdev' ]
5 info lifecycle app@0.1.0~predev: app@0.1.0
6 info lifecycle app@0.1.0~dev: app@0.1.0
7 verbose lifecycle app@0.1.0~dev: unsafe-perm in lifecycle true
8 verbose lifecycle app@0.1.0~dev: PATH: /home/ec2user/.nvm/versions/node/v14.21.3/lib/node_modules/npm/node_modules/npm-lifecycle/node-gyp-bin:/var/www/frontend/releases/xxxxxxxxxx/node_modules/.bin:/home/ec2user/.nvm/versions/node/
v14.21.3/bin:/usr/local/bin:/usr/bin
9 verbose lifecycle app@0.1.0~dev: CWD: /var/www/frontend/releases/xxxxxxxxxx
10 silly lifecycle app@0.1.0~dev: Args: [ '-c', 'vue-cli-service build --mode development' ]
11 silly lifecycle app@0.1.0~dev: Returned: code: 1  signal: null
12 info lifecycle app@0.1.0~dev: Failed to exec dev script
13 verbose stack Error: app@0.1.0 dev: `vue-cli-service build --mode development`
13 verbose stack Exit status 1
13 verbose stack     at EventEmitter.<anonymous> (/home/ec2user/.nvm/versions/node/v14.21.3/lib/node_modules/npm/node_modules/npm-lifecycle/index.js:332:16)
13 verbose stack     at EventEmitter.emit (events.js:400:28)
13 verbose stack     at ChildProcess.<anonymous> (/home/ec2user/.nvm/versions/node/v14.21.3/lib/node_modules/npm/node_modules/npm-lifecycle/lib/spawn.js:55:14)
13 verbose stack     at ChildProcess.emit (events.js:400:28)
13 verbose stack     at maybeClose (internal/child_process.js:1088:16)
13 verbose stack     at Process.ChildProcess._handle.onexit (internal/child_process.js:296:5)
14 verbose pkgid app@0.1.0
15 verbose cwd /var/www/frontend/releases/xxxxxxxxxx
16 verbose Linux 4.14.281-212.502.amzn2.x86_64
17 verbose argv "/home/ec2user/.nvm/versions/node/v14.21.3/bin/node" "/home/ec2user/.nvm/versions/node/v14.21.3/bin/npm" "run" "dev"
18 verbose node v14.21.3
19 verbose npm  v6.14.18
20 error code ELIFECYCLE
21 error errno 1
22 error app@0.1.0 dev: `vue-cli-service build --mode development`
22 error Exit status 1
23 error Failed at the app@0.1.0 dev script.
23 error This is probably not a problem with npm. There is likely additional logging output above.
24 verbose exit [ 1, true ]
```

## 検証
開発環境構築時（git clone後）にnpm installとnpm ciを比較

### npm install

```shell
npm install
```

```shell
% git status
On branch master
Your branch is up to date with 'origin/master'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   package-lock.json
```

package-lock.jsonが更新されている。

### npm ci

```shell
npm ci
```

```shell
% git staus
git: 'staus' is not a git command. See 'git --help'.

The most similar command is
	status
```

更新なし

### 結果

npm installを実行するとpackage-lock.jsonが更新されて、
npm ciの場合は更新されない。