Vue公式のクイックスタートは何してるのか

# 概要
[Vue.jsの公式クイックスタート](https://ja.vuejs.org/guide/quick-start)にある以下コマンドについて、内部で何してるのかを各コマンドを実行しつつ、色々調べてみた。

```
npm create vue@latest
```

実行環境は以下Docker Imageで立ち上げたNode.jsコンテナ。
```Dockerfile
FROM node:18.18.0-bullseye-slim

USER node
WORKDIR /workspace
```

# npm createは何してるのか

vue@latestやコマンド実行時の挙動の前に、npm createについて確認する。

## npmとは

正式名称：Node Package Manager。
その名の通りNode.js上で参照する各種パッケージの依存関係やバージョンなどを管理するマネージャ。

[npm公式ドキュメント](https://docs.npmjs.com/about-npm)によるとソフトウェアレジストリと定義されている。
レジストリの解釈が少し難しいが、大まかにライブラリと同じものと見做してよさそう。

ライブラリ=モジュールの集合=再利用可能なプログラムの集まり、ということで、npmのおかげで用いることで集約された各モジュール（Node.js的に言うならパッケージ）を好きにローカル環境にもってきて実行することが出来る。

Node.jsとの関係性については以下の図が分かりやすかった。

参考：https://nodesource.com/blog/NodeJS-securing-your-applications-1
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614279/1aa8b703-cf80-1381-09e7-bc326a503b68.png)

## npm createとは

npm createというコマンド自体は存在せず、実体としてはnpm initの模様。

とりあえずhelpを見てみた。
```
node@a9076da33620:/workspace$ npm create --help
Create a package.json file
Usage:
npm init <package-spec> (same as `npx <package-spec>`)
npm init <@scope> (same as `npx <@scope>/create`)
Options:
[-y|--yes] [-f|--force] [--scope <@scope>]
[-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]]
[-ws|--workspaces] [--no-workspaces-update] [--include-workspace-root]
aliases: create, innit
Run "npm help init" for more info
```

（誤字ってる気がするが）aliases見るとnpm createとnpm initを同列に扱ってる節がある。
npm initのhelpも確認してみたが、全く同じだった。

```
node@a9076da33620:/workspace$ npm init --help
Create a package.json file
Usage:
npm init <package-spec> (same as `npx <package-spec>`)
npm init <@scope> (same as `npx <@scope>/create`)
Options:
[-y|--yes] [-f|--force] [--scope <@scope>]
[-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]]
[-ws|--workspaces] [--no-workspaces-update] [--include-workspace-root]
aliases: create, innit
Run "npm help init" for more info
```

### じゃあnpm initは何してるのか

[公式ドキュメント](https://docs.npmjs.com/cli/v10/commands/npm-init)によると、新規または既存のnpmパッケージをセットアップするコマンドとのこと。
引数（initializer）に指定した内容に応じて、対応付けられたnpm execコマンドが実行される。

要するに、以下のような対応関係でexecコマンドが実行される模様。
```
npm init <name>@<version> -> npm exec create-<name>@<version>
```

### npm execは何してるんだ

なんとなく引数のパッケージを実行するコマンドっぽいことは伝わってきたが、一応helpを見てみた。
```
node@a9076da33620:/workspace$ npm exec --help
Run a command from a local or remote npm package
Usage:
npm exec -- <pkg>[@<version>] [args...]
npm exec --package=<pkg>[@<version>] -- <cmd> [args...]
npm exec -c '<cmd> [args...]'
npm exec --package=foo -c '<cmd> [args...]'
Options:
[--package <package-spec> [--package <package-spec> ...]] [-c|--call <call>]
[-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]]
[-ws|--workspaces] [--include-workspace-root]
alias: x
Run "npm help exec" for more info
```

ローカルだけでなく、まだフェッチしてないnpmレジストリ上のリモートパッケージも指定できるみたい。

### つまるところ

以上を踏まえると、npm create vue@latestは最終的にnpm exec create-vue@latestとして実行される。
クイックスタートのドキュメント通り、最新のcreate-vueパッケージを実行していることが分かる。
```
npm create vue@latest
↓
npm init vue@latest
↓
npm exec create-vue@latest
```

## create-vueパッケージは何してるのか

先にまとめると、このパッケージが実施することは以下2点に集約される。
1. package.jsonの作成
1. 開発用パッケージ（viteなど）の設定ファイルの作成

実際にコマンドを叩いてみる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614279/036a3a97-2351-7d3b-0445-54345b9a2569.png)

対話形式で、各種開発に必要になるであろうパッケージを追加するかどうかのYes/Noの入力が求められる。

## create-vueで導入を問われるものについて

Add ○○？と問われるものについて簡単に見ていく。

### TypeScript

JavaScriptに型構造を持たせた言語。Node.js上で動かすアプリの場合、実行前にJavascriptにコンパイルされる。

### JSX

JavaScript XML。
ざっくりいうとjavascriptの変数に直接htmlタグ文字列を埋め込める。DOM生成関数をcallする必要がないためより可読性に長ける。どうやらReactの方でよく使われている模様。

### Vue Router

SPAにおけるURLと描画コンポーネントのルーティングを行う。

### Pinia

状態管理パッケージ。同様のツールとしてvuexなどがある。

### Vitest
単体テストツール。Jestとかと同じ部類に入る。ビルドツールであるviteとの親和性が高いらしい。

### ESLint
構文解析（リンティング）ツール。jsコードを静的解析してくれる

### Prettier
フォーマッター。js/ts以外にもhtmlとか色々対応してる。

## npm installについて

パッケージのインストールを行う。利用ケースとしては以下の3つに集約されそう。

1. パッケージの個別インストール
2. パッケージの一括インストール
3. 各versionを指定してのパッケージの一括インストール

それぞれ見ていく。

### パッケージの個別インストール

以下コマンド実行にて行う。
```
npm install <package-name>
```
挙動は以下の通り。
1. カレントディレクト内にnode_moduleディレクトリを作成（作成済みならパス）
2. 指定パッケージ（およびその依存パッケージ）をnpmレジストリから探してDLし、node_module配下に配置
3. インストールしたパッケージの名前とバージョンをpackage.jsonおよびpackage-lock.jsonに追記

ちなみに、インストール時の参照スコープとしてlocalとglobalが用意されており、以下のような使い分けになる。
- local
    - プロジェクト内のjsファイルにて、require文でパッケージを参照する
- global
    - CLI上でパッケージを直接実行する

コマンド実行時に **-gオプション** をつけるとglobal参照でインストールを行い、その場合は **/usr/local/lib/node_modules/** 配下にパッケージは配置される。（npm listで確認可能）

両方の用途で参照する場合は、どちらも実施する必要があるとのこと。Prettierなどのフォーマッターなどでない限り、基本的にはlocalのみでインストールになると思われる。

### パッケージの一括インストール

こちらはnpm installのみで実行する。

挙動は以下の通り。

1. カレントディレクトリ内にpackage.jsonがあるかを探す
2. 見つけたpackage.jsonに沿って、各パッケージをインストールする（以下個別インストール時の挙動と同じ）

### 各versionを指定してのパッケージの一括インストール

挙動は以下の通り。

1. カレントディレクトリ内にpackage.jsonがあるかを探す
2. カレントディレクトリ内にpackage-lock.jsonがあるかを探す
3. 見つけたpackage.jsonに沿って各パッケージをインストールする

package.jsonとpackage-lock.jsonが作成済みの場合に実行可能。
インストール対象パッケージのバージョンの再現性を担保するのが目的と思われるため、package.jsonやpackage-lock.jsonの更新は特に行われない。

## 個人的QA

create-vueパッケージや各種npmコマンドを調べる過程で気になった挙動について。

### Q. 何らかの不手際でpackage-lock.jsonのみ存在した場合はどうなるの？

A. package.jsonが無い旨のエラーが出力され、package-lock.jsonもそれに合わせて更新される（つまりまっさらになる）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614279/f29e4973-342c-1c87-9ca6-17f12784f82d.png)

package-lock.jsonだけでも一括インストールに必要な情報は足りてそうだが、上記処理から推測するに、あくまで参照としてはpackage.json → package-lock.jsonの参照順序になっている模様。

### Q. npm installでの一括インストール実行に必要なものはつまり何？

A. package.jsonのみ。~~package.jsonさえあれば要らない何も捨ててしまおう~~

逆にpackage.jsonしか存在しないディレクトリ下で実行しても、ちゃんとnode_moduleディレクトリが作成される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614279/53047976-2755-f08b-0eca-050746ce8d8d.png)

### Q. vue-createでyes/noを聞かれるパッケージって後で自分で入れたりできないの？

A. 入れることは可能。
  
ただし、--save-devオプションをつけて入れるような開発用パッケージ（prettierとか）の場合、別途設定ファイルを用意する必要があるが、それらはnpm install時に自動作成されず、都度手動で作成する必要がある。

プロジェクト作成時にvue-createのインタラクションにYesと回答したパッケージの設定ファイルはvue-createが自動作成してくれるので、よりスムーズに導入が可能となっている。

# 終わりに

Vue公式のクイックスタートで紹介されている手順について、その構成要素となる技術について一通り調べてみた。

vue-createで導入する開発用パッケージやテストツールについてはまだまだよくわかっていないため、Vueアプリの作成をやりつつ、気になったことからまた調べていきたい。