「npx create-next-app」って何をしているの？


## はじめに

最近、Next.jsでの開発を進めていて、いつも使っている 「**`npx create-next-app` って何してるんだ？**」という疑問が頭をよぎりました。

よく、ふとした瞬間に、「これって本当に理解して使ってる？」と自問自答することってありますよね。特に、誰かに説明しようとすると、理解を曖昧にしているせいで思った以上に言葉に詰まることが多いです。

例えば、公式ドキュメントの「Installation」を参照してプロジェクトをセットアップする際に、手順をコピー＆ペーストして「動いたからOK」としてしまうことが多いかと思います。実は私もそんなタイプです😅

この記事では、Next.jsでプロジェクトを作る過程で、「なぜそうなるのか」を掘り下げながら、より深く理解していくことを目指します。

## Next.jsプロジェクトの作成

では、Next.jsのプロジェクトを作成していきます。
まずはいつも通り、[Next.js 公式ドキュメント](https://nextjs.org/docs/getting-started/installation) に記載されているまま進めていこうと思います。

1. Node.jsをインストールする

    現在は **Node.js 18.17 or later.** と書いてあるので、[Node.jsのダウンロードページ](https://nodejs.org/en/download) から v18.17以降 の Node.js をインストールします。

2. Next.jsのプロジェクトを作成する

    以下のコマンドを実行してNext.jsのプロジェクトを作成します。

    ```bash
    npx create-next-app@latest
    ```

3. 開発サーバーを起動します。

    以下のコマンドを実行して、開発サーバーを起動します。

    ```bash
    cd my-app
    npm run dev
    ```

ここまでが、Next.jsのプロジェクトを作成し、Next.jsアプリケーションを起動する手順となります。

初めてNext.jsのプロジェクトを作成する方やnpmを使用する方にとっては、これらの説明の中で、以下のような疑問が出てくるかと思います。

1. Next.js に Node.js が必要な理由は？
2. `npx` とは何か？
3. `npx create-next-app` で何が行われているのか？
4. `npm run dev` で何が行われているのか？

私自身、基礎を疎かにしがちな人間なので、何度も「あれ、これ前も調べたよね？」という状況になってしまうことがあります。そんな経験を活かして、今回はこれらの疑問について自身も学習しながら解説していきたいと思います。

## 疑問1. Next.js に Node.jsが必要な理由は？

『Node.jsとは何者なのか？』という説明を始めると、それだけで記事一本書けてしまう程のボリュームになってしまうので、本記事ではNode.jsは以下の役割をするツールだと思ってください。

### 役割1. JavaScriptをサーバーサイドで実行するためのランタイム

Next.jsは **Node.js上で動作するフレームワーク** です。
そのため、Next.jsのアプリを実行するためには、Node.jsが必須となります。

これだけではイメージが湧きにくいかもしれませんので、図で表現してみます。ここでは、ローカルPCからWebサーバー上にデプロイされたNext.jsアプリケーションにリクエストを送信するまでの流れを図解します。

<img width="600" alt="JavaScriptをサーバーサイドで実行するためのランタイム_01" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/c04dd199-b576-ac02-64f7-b177bca46fa6.png">

1. 「ローカルPC」からリクエストが「Webサーバー」へ送信されます。これは一般的なクライアントとサーバー間の通信です。
2. 「Webサーバー」上の「Next.jsアプリケーション」がそのリクエストを受け取ります。Next.jsはNode.jsを使用してWebサーバー機能を提供します。
3. Next.jsアプリケーションはNode.jsランタイム上で動作しており、リクエストを処理することができます。この段階で、サーバーサイドレンダリングやAPIの呼び出しなどが行われます。
4. 「Next.jsアプリケーション」がリクエストを処理し、「ローカルPC」にレスポンスのHTMLを返します。このHTMLはNext.jsによって生成され、必要に応じてプリレンダリングされたページや動的に生成されたページを含むことができます。

このことから「Next.jsアプリケーション」は **Node.jsランタイム上** で動作していることがわかります。

Node.jsは一般的に **サーバーサイド** でJavaScriptを実行するランタイム環境として知られていますが、この説明ではインターネット越しの **リモートサーバーで実行される** というイメージが強調されがちです。しかし、ローカルPCにNode.jsをインストールし、Next.jsの開発サーバーを立ち上げて、Node.jsランタイム上でNext.jsアプリケーションを実行することも可能ですので、**ローカルサイドでもNode.jsは使用される** というイメージで理解していただければと思います。

<img width="600" alt="JavaScriptをサーバーサイドで実行するためのランタイム_02" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/33c38062-6ee0-2a90-8add-5fc5ead4bc96.png">

現在、Node.jsはサーバーサイドのアプリケーション開発だけでなく、**フロントエンドの開発ツール** としても広く使われています。

### 役割2. Node.jsのパッケージを使用するためのもの

Node.jsは、サーバーサイドでJavaScriptを実行するランタイム環境として知られていますが、それだけでなく、**npm** というパッケージマネージャーも提供しています。（Node.jsをインストールすると、npmも一緒にインストールされます）

Node.jsのパッケージとは、「TypeScript」や「Prettier」などのツールやライブラリのことを指します。これらを使用するためには、Node.jsをインストールする際に同梱される **npm** を利用してパッケージをインストールする必要があります。

Node.jsのパッケージは **npmレジストリ** で公開されており、npmコマンドを使用してインストールできます。

https://www.npmjs.com/package/prettier

https://www.npmjs.com/package/typescript

例えば、TypeScriptを使用するためには、以下のコマンドを実行してTypeScriptをインストールします。

```bash
npm install -g typescript
```

<img width="600" alt="npmレジストリ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/28ae43b8-34ae-dd14-6ed1-93b5c07249c1.png">

Next.jsのプロジェクトを作成する際にも、Node.jsのパッケージである `create-next-app` を使用して、Next.jsのプロジェクトを作成しています。
`create-next-app` も以下のnpmレジストリで公開されており、npmコマンドを使用してインストールすることができます。

https://www.npmjs.com/package/create-next-app

## 疑問2. npxとは？

次に `npx` について説明していきます。

### コマンドはどのように実行されているのか？

まずは `node index.js` のように「nodeコマンド」を実行する方法を改めて確認しましょう。

『そんなの知ってるよ！』と思う方もいるかもしれませんが、改めて確認したいと思います。

まず、コマンドを実行するためには **コマンドラインツール** を使用します。
コマンドラインツールのありかは、以下のコマンドで確認できます。

```bash
$ echo $PATH | tr ':' '\n'
・・・
/usr/local/bin
・・・
```

一般的なコマンドラインツールは `/usr/local/bin` に配置されており、ここに配置することでコマンドが実行できるようになります。このパスはデフォルトで設定されているパスとなります。

Unix系のオペレーティングシステム（macOSやLinuxなど）では、多くのコマンドラインツールやプログラムが `/usr/local/bin` ディレクトリにインストールされます。

実際に node のパスを確認すると、以下のようになります。

```bash
$ which node
/usr/local/bin/node
```

`node index.js` を実行すると、以下のような実行フローになります。

<img width="600" alt="コマンドを実行するには？_01" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/7420a5ac-ec18-61dc-ef0b-fe0ee5af6aa2.png">

### npmとは何か？

npm は Node.js インストール時に `/usr/local/bin` にインストールされるので、「npmコマンド」を実行できます。

```bash
$ which npm
/usr/local/bin/npm
```

しかし、`/usr/local/bin/npm` は、シンボリックリンクが設定されたエイリアスファイルになっています。

<img width="600" alt="npmとは？_02" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/5a518209-4dce-c88e-5a86-a546a88290e3.png">

Node.jsのパッケージは通常 `/usr/local/lib/node_modules` にインストールされます。そのため、グローバルにコマンドを実行するためには、`/usr/local/bin` にシンボリックリンクを設定することが一般的です。このシンボリックリンクは、`/usr/local/lib/node_modules` の実行可能ファイルを刺しています。

npmのシンボリックリンクを確認すると、以下のようになっています。

```bash
$ ls -l $(which npm)
lrwxr-xr-x  1 root  wheel  38  5 11 14:33 /usr/local/bin/npm -> ../lib/node_modules/npm/bin/npm-cli.js
```

これは、`/usr/local/bin/npm` が `/usr/local/lib/node_modules/npm/bin/npm-cli.js` へのシンボリックリンクであることを示しています。

そのため、npmコマンドを実行すると、`/usr/local/lib/node_modules/npm/bin/npm-cli.js` のJavaScriptプログラムを実行していることがわかります。

<img width="800" alt="npmとは？_01" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/b971c8d7-d055-2ea2-fb04-49df23cc7d67.png">

### Node.jsパッケージをインストールして使用する

Node.jsのパッケージをインストールする際には、「npm」を使用します。

```bash
npm install -g {パッケージ名}
```

このコマンドでパッケージをグローバルにインストールすると、システム全体で使用できるようになります。たとえば、TypeScriptをグローバルにインストールすると、どのディレクトリにいてもTypeScriptコマンドを実行できるようになります。

```bash
npm install -g typescript
cd {任意のディレクトリ}
tsc init       ← カレントディレクトリがどこでも実行できる
```

グローバルにインストールされたパッケージは、実行可能ファイルが `/usr/local/bin/` に配置されるため、どこからでもコマンドを実行できます。

```bash
$ which tsc
/usr/local/bin/tsc
```

<img width="600" alt="Node.jsパッケージのインストール_01" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/01e6910c-78c6-5627-1b7f-67e6500dea31.png">

なぜ `typescript 〜` ではなく `tsc 〜` で実行するのかというと、これはnpmパッケージの`package.json`ファイル内の **binプロパティ** によるものです。このプロパティを利用して、 **パッケージ名とは異なるコマンド名を指定できます。**
TypeScriptの場合、binプロパティに `tsc` が設定されているため、`tsc 〜`で実行することができます。

```json
{
    "name": "typescript",
    ・・・
    "bin": {
        "tsc": "./bin/tsc"
    },
    ・・・
}
```

Node.jsのパッケージは通常 `/usr/local/lib/node_modules` にインストールされますので、TypeScriptも `/usr/local/lib/node_modules/typescript/bin/tsc` にインストールされることになります。

```bash
$ ls -l $(which tsc)
lrwxr-xr-x  1 root  wheel  38  5 11 15:25 /usr/local/bin/tsc -> ../lib/node_modules/typescript/bin/tsc
```

この出力結果は、`/usr/local/bin/tsc` が `/usr/local/lib/node_modules/typescript/bin/tsc` へのシンボリックリンクであることを示しています。これにより、`tsc`コマンドをどこからでも実行できるようになっています。

グローバルにインストールされているパッケージの一覧を見てみましょう。以下のコマンドを使用すると、`/usr/local/lib/node_modules` にインストールされたNode.jsのパッケージを確認できます。

```bash
$ npm -g list
/usr/local/lib
・・・・
├── npm@10.5.2
└── typescript@5.4.5
```

### npxとは何か？

ようやく、npxについての説明となります。

npmはパッケージを管理するためのツールで、**インストールしたパッケージを管理** します。一方で、npxはパッケージを **インストールせずに実行** するためのツールです。これにより、一時的なパッケージの実行や、プロジェクト固有のパッケージの実行が可能になります。

npxのパスを確認すると、以下のようになっています。

```bash
$ ls -l $(which npx)
lrwxr-xr-x  1 root  wheel  38  5 11 14:33 /usr/local/bin/npx -> ../lib/node_modules/npm/bin/npx-cli.js
```

この出力から、`/usr/local/bin/npx` は `/usr/local/lib/node_modules/npm/bin/npx-cli.js` へのシンボリックリンクであることがわかります。つまり、npxは **npmに付属しているツール** ということになります。

## 疑問3. `npx create-next-app` で何が行われているのか？

「create-next-app」は、Next.jsのプロジェクトを作成するためのパッケージです。このパッケージをグローバルにインストールして使用することもできますが、npxを使用することで、インストールせずに直接実行することが可能です。

npxの動作を理解するためには、実際にコマンドを実行してみるのが最も分かりやすいと思いますので、以下のコマンドを試してみます。

```bash
npx create-next-app@latest
```

このコマンドを実行すると、Next.jsのプロジェクトが作成されます。具体的には、以下の処理が行われています。

1. まず、カレントディレクトリのnpmプロジェクトに **create-next-app** というパッケージがインストールされているかを確認します。

    <img width="600" alt="Node.jsが必要な理由_01" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/d1d94657-fe8b-e1b8-e31c-d902f9129e50.png">

2. もしインストールされていなければ、npmレジストリから **create-next-app** パッケージをダウンロードし、**一時的にインストール** します。

    <img width="600" alt="Node.jsが必要な理由_02" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/24c5bcf3-9eba-8adb-73f2-aa95d1e274b2.png">

   npmレジストリからnpxでパッケージを使用した場合、`/Users/{ユーザ名}/.npm/_npx` に「一時ディレクトリ」が作成され、その配下に「node_modules」が作成されます。ここにパッケージが一時的にインストールされ、使用されます。

3. パッケージがインストールされたら、**create-next-app** を実行し、Next.jsのプロジェクトが作成されます。

    <img width="400" alt="Node.jsが必要な理由_03" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/66019b93-77bb-ff68-3102-81adaa24a1a0.png">

このプロセスにより、**グローバルにパッケージをインストールせずにパッケージを実行することができる** のがnpxの特徴です。

## 疑問4. `npm run dev` とは何をしているのか？

`npm run {スクリプト名}` は、`package.json` の **scripts** セクションに記述されたスクリプトを実行するコマンドです。例えば、Next.jsプロジェクトの `package.json` で **dev** というスクリプトが `next dev` というコマンドを実行するように定義されています。

<img width="400" alt="npm_run_devとは_02" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/c5eedf69-308d-a45b-2fca-f3b68376b7fb.png">

このため、**dev**スクリプト は実質的に `next dev` を実行します。

<img width="600" alt="npm_run_devとは_01" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/0513a7b1-98b9-06d0-a292-f185b81971f6.png">

`next dev` コマンドを使用すると、Next.jsの開発サーバーが起動します。ただし、「nextパッケージ」はNext.jsプロジェクトの「node_modules」に配置されているため、**カレントディレクトリがNext.jsプロジェクト内である場合のみ** 使用できます。

プロジェクト固有のパッケージを使用したい場合は `npx` を利用します。この場合、`npx next dev` と実行することで、プロジェクト内で使用可能な `next` パッケージ使用し、`npm run dev` と同様の動作を行うことができます。

## まとめ

今回は、Next.jsプロジェクト作成の裏側で行われていることを学びながら解説しました。以前はこの辺りの知識が曖昧で、不明確な説明をしてしまうことがありましたが、今回の学習を記事にまとめたことで、より詳細で正確な説明ができるようになったと思います。

基本的なコマンド実行の仕組みやnpmの仕組みを理解することで、今後の開発での問題解決や応用に役立つため、他の技術に対しても同じアプローチで、基礎からしっかりと学習を進めることが重要だと感じました。