node.jsでサーバーを立ててみる

#はじめに#
私の最初の投稿になります。
qiitaについても素人同然なので何かあれば教えていただけると幸いです。


これから何回かに分けてチャットウェブアプリを作っていき、その過程をメモとして残していこうと思います。（mac 環境）
今回は *node.js* を用いてサーバーを立ててみます。

#Node.jsのインストール#
まずnode.jsがインストールされているか確認をします。
node.jsのバージョンを確認します。
確認は

```terminal
$ node --version
v12.18.3
```

で確認。
node.jsが入っていない場合node.jsのインストールをおこなう。
node.jsのバージョン管理はnpm (Node Package Manager) か n を使って管理するとのことです。

今回nを使っていきたいのですが、nを入れるために。（ここら辺もいまいちわかっていないですが）
ともかく以下のコマンドで n をインストールします

```terminal
$ brew install node
$ npm install -g n
```

-g　オプションはグローバル環境で使えるようにするためにつけるようです。
n の簡単な使い方をまとめてみると

```terminal
$ n list         #インストール済みのバージョン一覧表示
node/8.2.1
node/12.18.3
$ n latest       #最新版をインストールする
$ n バージョン   #バージョンを指定してインストール
$ n            #何も指定しないとインストールされている中から選択する画面になる
```
といったところです。

#node.jsのパッケージ初期化#
まず以下のようにしてnode.jsのパッケージの初期化を行います。

```
$ npm init
```

これを行うと

```
package name: (training) 
version: (1.0.0)
description: 
entry point: (index.js) 
test command: 
git repository: 
keywords: 
author: 
license: (ISC) 
```

のよう入力を促してくるのでそれぞれ入力してエンターを押して進めていきます。
何も書かずにエンターすると（）のなかのものがデフォルトで入力されます。
今回はentry pointのjsファイルの名前をserver.jsにして進めています。

最後yで確定するとpackage.jsonが作られます

```pacage.json
{
  "name": "training",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

```

#node.jsのパッケージのインストール#
今回使っていくパッケージをインストールしていく
今回はExpressとsocket.ioを使用していくためこの二つを以下のようにしてインストールする

```terminal
$ npm install express --save
$ npm install socket.io --save
```
--saveはpackage.jsonのdependenciesに書き込むオプションであるのでpackage.jsonは
余談ーーー
ちなみに--save--devとするとdevDependenciesに書き込まれるらしいです。
この違いはgit clone した時などに必要な環境を整える時にインストールするかどうかを分けているらしいです。
ーーーーー

```package.json
{
  "name": "mychat",
  "version": "1.0.0",
  "description": "",
  "main": "server.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "express": "^4.17.1",
    "socket.io": "^2.3.0"
  }
}
```

となる。
またこれによってnode_modulesディレクトリとpackage-lock.jsonファイルが作られる。

#サーバーの起動#
早速起動していきます。
サーバーの起動を行うファイルserver.jsを作ります(npm initでentry pointで指定した名前で作る)

```
'use strict';

// モジュール
const express = require( 'express' );
const http = require( 'http' );
const socketIO = require( 'socket.io' );

// オブジェクト
const app = express();
const server = http.Server( app );
const io = socketIO( server );

// 定数
const PORT = process.env.PORT || 1337;

// サーバーの起動
server.listen(
    PORT,
    () =>
    {
        console.log( 'Server on port %d', PORT );
    } );

```

これについて簡単に説明していきます。
まず

```server.js
'use strict';
```

これは厳格（strict）モードとして実行することの宣言のようです。
つまりエラーなどの許容を厳格にして曖昧な表現を禁止したり動作の高速化、潜在的な問題をわかりやすくするなどあるようです。
次に

```server.js
const express = require( 'express' );
const http = require( 'http' );
const socketIO = require( 'socket.io' );
```

で使われているrequier()
これはモジュールを読み込むために使用するようです。
余談ーーー
htmlでモジュールを読み込む時は&lt;script&gt;タグで行うが、それができないサーバーなどでモジュールを読み込むために作られた仕様のようです。
ーーーーー

```server.js
const app = express();
const server = http.Server( app );
const io = socketIO( server );
```

１行目のexpress() はexpressモジュールの変数の初期化。
２行目の３行目はhttp.Server(app)はhttp.ServerインスタンスにexpressとsocketIOを両立させるために行なっているようです。（この辺りの根本はまだ理解に時間がかかりそうです）


```server.js
const PORT = process.env.PORT || 1337;
```

これはポート番号の指定している。
~~私がjs歴がほとんどないのでおそらくですが~~process.env.PORTは環境変数PORTを示していて、これをor演算を行なっていると考えると、もし環境変数PORTがfalseを示すものだった場合（None等）数値1337を変数PORTに代入しているのだと思います。
つまり環境変数として指定すればいつでもどのファイルとの統一を測れるのではないかと考えています。

```server.js
server.listen(
    PORT,
    () =>
    {
        console.log( 'Server on port %d', PORT );
    } );
```
server.listen(PORT、function)はサーバーを立ち上げる関数のようです（これは正しいかちょっと自信ないです。）
PORTはポート番号の指定をして、functionは立ち上げた時に働く関数を定義するようです。
今回関数はアロー関数式で定義しています。
（valiable）=>{function}
で記述できるようです。~~（アロー演算子はあまり使ったことがない）~~
ここの関数ではconsole.log()でコンソールに標準出力しているだけです。

余談ーーー
サーバーの起動はapp.listen(port)などいろんな方法があるようです。今回はexpressとsocket.ioを同じポートで待ち受けるためにこのような方法をとります。
ーーーーー

これでserver.jsの説明は以上です。
実際にサーバーを起動してみます。起動の仕方は

```terminal
$node server.js
Server on port 1337
```

で行う。
止める時はCtrl+Cで止める。

#公開フォルダ・ファイルの作成と指定#
公開フォルダは実際に公開する公開ファイルを置いておくディレクトリのようです。

```terminal
$ mkdir public 
```
これは説明しなくてもいいかと思いますが、publicディレクトリを作っています。
そしてpublicディレクトリの中に実際に表示するindex.htmlファイルを以下のように記述します。

```public/index.html
<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8" />
    <title>My Chat</title>
</head>
<body>
    <h1>My Chat</h1>
</body>
</html>
```
htmlについては別にまとめるつもりなのでそちらを参照
続いて公開フォルダを指定します。
server.jsのサーバーの起動の前に

```server.js
app.use(express.static(__dirname+'/public'));
```
express.static関数に公開ディレクトリのパスを渡してあげて指定するようです。~~ここはまた今度調べます~~

#サーバーにアクセス#
実際にサーバーを起動してみてからブラウザの検索画面に"localhost:1337"を入力してアクセスする。
うまくindex.htmlが出てくれば成功です。

#クライアントから接続要求と、接続時の処理の作成#
~~この辺りの通信あたりは苦手意識があって忘れてるところも多いので今後勉強していきますので今回は簡単に流します……ごめんなさい~~
publicディレクトリのなかにクライアントから呼び出すjsファイルclient.jsを作る。

```public/client.js
// クライアントからサーバーへの接続要求
const socket = io.connect();

// 接続時の処理
// ・サーバーとクライアントの接続が確立すると、
// 　サーバー側で、'connection'イベント
// 　クライアント側で、'connect'イベントが発生する
socket.on(
    'connect',
    () =>
    {
        console.log( 'connect' );
    } );
```

呼び出された時に実行する関数をアロー関数で定義していると思います。
そしてhtmlファイルのbodyの末尾に以下を記述します

```public/index.html
<script src="/socket.io/socket.io.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="client.js"></script>
```

そして最後にserver.jsの公開フォルダの指定の上に

```server.js
// 接続時の処理
// ・サーバーとクライアントの接続が確立すると、
// 　サーバー側で、'connection'イベント
// 　クライアント側で、'connect'イベントが発生する
io.on(
    'connection',
    ( socket ) =>
    {
        console.log( 'connection' );
    } );
```

を記述する。
これでもう一度サーバーを立ててブラウザから"localhost:1337"にアクセスすると、ブラウザの検証のコンソールとサーバーのコンソールにそれぞれ指定した標準出力が表示されれば成功となります。

#サーバーとクライアントの切断処理の作成#
クライアントが切断されるとサーバーでは'disconnect'イベントが発生するためその処理を作成する。
書くのが'connection'イベントの関数の中に書きます。

```server.js
.
.
.
    socket.on('disconnect',()=>{
        console.log('disconnect')
    });
.
.
.
```

socket変数はいまいち理解できてませんが、'connection'で紐付けした関係に関わる情報にアクセスするためのクラスオブジェクト見たいなものなのかなと勝手に考えてます。
これでサーバー立ち上げてブラウザから接続、切断を行うと以下のようにターミナルに表示されます。

```terminal
bash-3.2$ node server.js
Server on port 1337
connection 
disconnection
```
#今日のまとめ#
server.jsを色々書き加えたのでここまでの更新状況を置いておきます。

```server.js
'use strict';

// モジュール
const express = require( 'express' );
const http = require( 'http' );
const socketIO = require( 'socket.io' );

// オブジェクト
const app = express();
const server = http.Server( app );
const io = socketIO( server );

// 定数
const PORT = process.env.PORT || 1337;

// 接続時の処理
// ・サーバーとクライアントの接続が確立すると、
// 　サーバー側で、'connection'イベント
// 　クライアント側で、'connect'イベントが発生する
io.on(
    'connection',
    ( socket ) =>
    {
        console.log( 'connection' );

        //切断処理
        socket.on('disconnect',()=>{
            console.log('disconnect')
        });
    } );

// 公開フォルダの指定
app.use( express.static( __dirname + '/public' ) );

// サーバーの起動
server.listen(
    PORT,
    () =>
    {
        console.log( 'Server on port %d', PORT );
    } );

```

#終わりに#
今回はチャットウェブアプリを作る前段階としてnode.jsでサーバーを立ててみました。
前にPHPを使ってサーバーを立ててみた時はapacheなど書くことが多く難しい、苦手、といった意識があったのですがnode.jsを使った時は意外と簡単に立てられたのが意外でした。
でもサーバー周りはなかなか理解が追いついてなかったり忘れてたりするのでこれを機に進めながら勉強し直していきたいと考えています。


##[参考]##
https://www.hiramine.com/programming/chat_nodejs_socketio/01_connect.html [クライアントとサーバーの接続時の処理を作る]
https://techacademy.jp/magazine/16151 [初期化処理を行う！npm initの使い方【初心者向け】]
https://qiita.com/heyheyww/items/092fcbc490a249a2d05c [npm install の --save-dev って何？]
https://qiita.com/havveFn/items/c5beda8572aa8c1e6be6 [npm install時に「--save」オプションはいらない]
https://qiita.com/miri4ech/items/ffcebaf593f5baa1c112 [【JavasScript】use strictとは]
https://qiita.com/uryyyyyyy/items/b10b012703b5396ded5a [require()とは何か？何が便利なのか]
https://teratail.com/questions/8894 node.jsでrequire('http');する理由
https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q14142502624 知恵袋
https://nodejs.org/api/net.html#net_server_listen_port_host_backlog_callback Node.js v14.10.1 Documentation
https://expressjs.com/ja/starter/static-files.html Express での静的ファイルの提供