Node.js + EJS + Express で Web アプリ入門

本記事は以下の書籍を参考にしています。

スポンサーリンク

対象者

  • Node.js でウェブアプリを作りたい人
  • EJS・Express・Express Generator がわからない人
  • 細かい仕様は後で調べるから、まずは動くソースコードが欲しい人
スポンサーリンク

Node.js とは

  • サーバーサイドで動く Javascript です。
  • Web サーバーとしての役割も持ちます。

サーバーサイドで動くと何が嬉しいの?

サーバーに保存したデータを利用して、動的な Web アプリケーション(Web ページ)が提供可能になります。
例えば下記のとおりです。

動的な Web アプリケーションサーバーに保存したデータ
チャット他の人がチャットに書き込んだ内容
商品のレコメンドユーザーごとの購入履歴
いいね数のカウントいいねの数

上記のサービスを静的な HTML だけで実装すると

サーバーに保存したデータが更新される度に、HTML の内容を手作業で更新しないといけません。更新者は過労で死にます。

上記のサービスをクライアントサイドで実装すると

全てのデータをそれぞれのクライアントに保存して貰う必要があります。知らない人のチャットの内容を自分のハードディスクに保存してくれるクライアントなんていません。

スポンサーリンク

【Node.js】Web アプリケーションを作成

Node.js のインストール

RHEL(CentOS), Mac OS でのインストール方法について紹介します。その他の Linux ディストリビューションでのインストールはここに載ってます。

RHEL (CentOS) に Node.js をインストールする場合

  1. Node.js v12 の nodesource リポジトリをインストールします。
    curl -sL https://rpm.nodesource.com/setup_12.x | sudo bash -

    setup_12.x の "12" の値を変更すると指定したバージョンをダウンロードできます。最新バージョンは下記の GitHub で 「Node.js Current」 と検索すれば出てきます。

    https://github.com/nodesource/distributions/blob/master/README.md

  2. Node.js をインストールします。
    sudo yum install -y nodejs
  3. Node.js がインストールできていることを確認
  4. node -v
    $ node -v
        v12.18.3

Mac OS に Node.js をインストールする場合

下記の記事が参考になります。

MacにNode.jsをインストール - Qiita
MacにNode.jsの環境を構築するメモ。その前に※以下の方法もオススメです!MacにNode.jsをインストール(anyenv + nodenv編)上記の場合はプロジェクト毎(フォルダ毎…

Node.js をインストールしたので、早速 Web アプリケーションを作ってみます。

Hello World を表示

定番の Hello World から作成します。

  1. Node.js のプログラムを作成します。
    vim hello.js
  2. const http = require('http');
    
    const server =  http.createServer((req,res)=>{
            res.writeHead(200,{'Content-Type':'text/html'});
            res.write("Hello World");//表示するHTMLを指定
            res.end();
    });
    server.listen(3000);
  3. hello.js をウェブサーバーとして起動します
  4. node hello.js
  5. ウェブブラウザで http://localhost:3000/ にアクセスします

無事に Hello World が表示されました。

パスごとに異なる HTML ファイルを表示

次にパスごとに異なる html ファイルを読み込んで表示してみます。

  1. Switch 文を利用してパスごとに異なる html ファイルを表示する Node.js のプログラムを作成します。
  2. vim path.js
    const http = require('http');
    const fs = require('fs');
    const url = require('url')
    
    const server =  http.createServer((req,res)=>{
        var path = url.parse(req.url).pathname
        switch (path){ //パスごとに読み取るファイルを変更
            case '/':
                fs.readFile('./index.html','UTF-8',(err,data)=>{
                    res.writeHead(200,{'Content-Type':'text/html'});
                    res.write(data); //読み取ったHTMLをレスポンスで使用
                    res.end();
                });
                break;
    
            case '/other.html':
                fs.readFile('./other.html','UTF-8',(err,data)=>{
                    res.writeHead(200,{'Content-Type':'text/html'});
                    res.write(data); //読み取ったHTMLをレスポンスで使用
                    res.end();
                });
                break;
        }
    
    });
    
    server.listen(3000);
  3. '/' パスで使用する index.html を作成します。
  4. vim index.html
    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>title</title>
    </head>
    <body>
        Hello World
    </body>
    </html>
  5. '/other.html' パスで使用する other.html を作成します。
  6. vim other.html
    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>title</title>
    </head>
    <body>
        other page
    </body>
    </html>
  7. path.js をウェブサーバーとして起動します
  8. node path.js
  9. ウェブブラウザで http://localhost:3000/, http://localhost:3000/other.html にアクセスします

ちゃんと '/' パスと '/other.html' パスで異なる HTML ファイルを読み込んでいることがわかります。

【Express】 Web アプリケーションフレームワーク

Node.js のコードをもっと短く方法ねーのかよ!って思った方。あります!

Express という Web アプリケーションレームワークを使います。

Webアプリケーションフレームワークって何?

フレームワークとは、雛形の集まりです。つまり Web アプリケーションフレームワークは Web アプリケーションを作る時に使用する基本機能の雛形の集まりです。

よく利用する機能を毎回実装することは面倒なので、雛形として事前に用意してくれているのが Express です。この雛形を使えば数行のコードで必要な機能を実装できます。

Express でパスごとに異なる HTML ファイルを表示

まずは Express をインストールします。先程 Node.js をインストールした際に、npm と呼ばれる Node.js 用のパッケージ管理ソフトも一緒にインストールされていますので、こちらを利用して Express をインストールします。

  1. まずは初期化をします。(モジュールのための仮想環境を作ってます。)
  2. npm init -y
  3. 次に npm を使用して Express をインストールします。
  4. npm install express

    WARN が出ますが、気にしなくてOKです。(気になる方はここ)

  5. Express を使用して Node.js のプログラムを作成します。
  6. vim express.js

    Express は require('express') で Express モジュールを作成するだけで使えます。

    const express = require('express')
    const app = express()
    
    app.get('/', (req, res) => {
    res.sendFile(__dirname + '/index.html');
    });
    
    app.get('/other.html', (req, res) => {
    res.sendFile(__dirname + '/other.html');
    });
    
    app.listen(3000);
  7. express.js をウェブサーバーとして起動します
  8. node express.js
  9. ウェブブラウザで http://localhost:3000/, http://localhost:3000/other.html にアクセスします

Express を利用しない場合と比較して Express を利用するとかなりソースコードが短くなったことがわかります。

【EJS】テンプレートエンジン

今までの方法は、予め作成した静的な HTML を表示しているだけです。これだけなら Node.js を利用してサーバーサイドで処理する必要がありません。ここからは、EJS を利用してサーバーサイドで動的に HTML ファイルを生成します。

動的に HTML を生成するにはテンプレートを利用します。テンプレートは下記の2つから構成されます。

  • HTML の雛形
  • HTML に埋め込んだ変数

テンプレートの変数に値を埋め込んで、動的に HTML を生成することをレンダリングと呼びます。EJS はテンプレートをレンダリングするためのテンプレートエンジンです。

EJS を利用していいねボタンを実装

  1. npm を使用して EJS をインストール
  2. npm install ejs
  3. EJS と Express を利用していいねボタンを実装
    1. テンプレートを作成
    2. Express でテンプレートファイル(.ejs)を使用する場合 views ディレクトリ配下に置くことになっています。

      mkdir views
      vim ./views/like.ejs
      <!DOCTYPE html>
      <html>
      <head>
          <meta charset="UTF-8">
          <title>title</title>
      </head>
      <body>
          <form action="/" method="post" >
              <input type="submit" value="いいね"> <%= like%>
          </form>
      </body>
      </html>
      

      EJS のテンプレートファイルはほとんど HTML の書き方と同じですね。
      埋め込みを受け付ける変数は<%= "変数名"%>と記載します。

    3. テンプレートを元に HTML を生成するプログラムを作成・表示
    4. いいね数の保存先は data.txt とします。本格的にデータを管理する場合はデータベース(MySQL,PostgreSQLなど)を利用すればいいかと思います。

      vim like.js
      const ejs = require('ejs');
      const fs = require('fs');
      const express = require('express')
      const app = express()
      var like;
      
      try { //いいねデータがあれば読み込み。なければいいねが0
          like = fs.readFileSync('./data.txt','UTF-8');
      } catch(err){
          like = 0;
      }
      
      app.engine('ejs',ejs.renderFile);
      
      app.get('/', (req, res) => {
          res.render('./like.ejs',{like:like});
      }); 
      
      app.post('/', (req, res) => { //いいねボタンをクリックした時
          like++;
          fs.writeFileSync('./data.txt',String(like));
          res.render('./like.ejs',{like:like});
      }); 
      
      app.listen(3000);

      テンプレートに埋め込んだ変数"like"に対して res.render() でレンダリングしています。

  4. like.js をウェブサーバーとして起動します
  5. node like.js
  6. ウェブブラウザで http://localhost:3000/ にアクセスします

いいねボタンと現在のいいね数が表示されました。

いいねボタンをクリックするといいね数が増えていきます。また、別のクライアントからアクセスしても、いいね数は 0 に戻りません。これはサーバーサイドで保存した「いいね数」をレンダリングしているためです。

【Express Generator】Express のスケルトンを作成

.ejs や .js ファイルのスケルトン(雛形)が最初からあればなぁ〜〜〜。って思った方。あります!

Express Generator を使用すれば、Express のスケルトンが自動生成されますので、index.ejs や index.js に追記することで簡単に Web アプリケーションを作ることができます。

Express Generator で Web アプリケーションを立ち上げる

  1. Express Generator をインストール
  2. sudo npm install -g express-generator
  3. Web アプリケーションのスケルトンを作成
  4. 今回はアプリケーション名を myapp とします。

    express -e myapp
  5. Express Generator が定義したモジュール(package.json 参照)をインストール
  6. cd ./myapp
    npm install
  7. bin/www をウェブサーバーとして起動します
  8. Express Generator では index.js の代わりに bin/www をウェブサーバーとして立ち上げます。
    node bin/www
  9. ウェブブラウザで http://localhost:3000/ にアクセスします

Express Generator で生成した各ディレクトリの説明

Express Generator で生成した Web アプリケーションにパスを追加する

Express Generator で生成した Web アプリケーションに先程のいいねボタンを表示するパスを追加してみます。

  1. 「views」ディレクトリに like.ejs ファイルを置きます。
  2. cp ../views/like.ejs ./views/like.ejs
    また、元の like.ejs ファイルから少し修正する必要があります。下記に修正箇所を赤線マーカーで示します。
    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>title</title>
    </head>
    <body>
        <form action="/like" method="post" >
            <input type="submit" value="いいね"> <%= like%>
        </form>
    </body>
    </html>
    
  3. 「routes」ディレクトリに like.js ファイルを置きます。
  4. cp ../like.js ./routes/like.js
    また、元の like.js ファイルから少し修正する必要があります。下記に修正箇所を赤線マーカーで示します。
    vim routes/like.js
    const ejs = require('ejs');
    const fs = require('fs');
    const express = require('express')
    
    var app = express.Router();
    var like;
    
    try { //いいねデータがあれば読み込み。なければいいねが0
    like = fs.readFileSync('./data.txt','UTF-8');
    } catch(err){
    like = 0;
    }
    
    app.get('/', (req, res) => {
    res.render('./like.ejs',{like:like});
    });
    
    app.post('/', (req, res) => { //いいねボタンをクリックした時
    like++;
    
    fs.writeFileSync('./data.txt',String(like));
    res.render('./like.ejs',{like:like});
    });
    
    module.exports = app;
  5. app.js ファイルに下記の赤線マーカーの箇所を追加します
  6. var createError = require('http-errors');
    var express = require('express');
    var path = require('path');
    var cookieParser = require('cookie-parser');
    var logger = require('morgan');
    
    var indexRouter = require('./routes/index');
    var usersRouter = require('./routes/users');
    var likeRouter = require('./routes/like');
    
    var app = express();
    
    // view engine setup
    app.set('views', path.join(__dirname, 'views'));
    app.set('view engine', 'ejs');
    
    app.use(logger('dev'));
    app.use(express.json());
    app.use(express.urlencoded({ extended: false }));
    app.use(cookieParser());
    app.use(express.static(path.join(__dirname, 'public')));
    
    app.use('/', indexRouter);
    app.use('/users', usersRouter);
    app.use('/like', likeRouter);
    
    // catch 404 and forward to error handler
    app.use(function(req, res, next) {
    next(createError(404));
    });
    
    // error handler
    app.use(function(err, req, res, next) {
    
    // set locals, only providing error in development
    res.locals.message = err.message;
    res.locals.error = req.app.get('env') === 'development' ? err : {};
    
    // render the error page
    res.status(err.status || 500);
    res.render('error');
    });
    
    module.exports = app;
  7. bin/www をウェブサーバーとして起動します
  8. node bin/www
  9. ウェブブラウザで http://localhost:3000/like にアクセスします

無事 "/like" パスにて先程作成したいいねボタンにアクセスできたことがわかります。

最後に

これまで、以下のことを説明しました。

この記事が 1 人でも多くの人の Node.js の理解の手助けになればいいなと思います。



■関連記事