2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

『自分用』テンプレートエンジンを使って簡単なアンケートをつくってみた

Last updated at Posted at 2019-11-08

##免責事項
この記事は初心者視点でザックリとした説明をしています。正確性に欠ける可能性がございますが、ご了承ください。「明らかに違うよ」ということがありましたら、ご指摘くださると幸いです。

##環境
OS:最新版ではないMacOS
VirtualBox:5.2.26
Vagrant:2.2.6
Ubuntu:ubuntu/bionic64 v20181129.0.0

##目次

  1. テンプレートエンジンとは
  2. アンケートをつくる

#1. テンプレートエンジンとは
テンプレートエンジンはテンプレートと呼ばれる雛形とデータを合成し、HTML等の成果ドキュメントを出力するライブラリです。

Wikipediaにわかりやすい画像があったのでお借りしました。
320px-TempEngGen015.svg.png
(画像 by Dreftymac at English Wikipedia)

ようするに、HTMLなどのドキュメントを作るのを簡単にしてくれるらしいです。

今回はPugというNode.jsのテンプレートを使って簡単なアンケートを作ります。
Pugは以下のように書きます。

Pug
doctype html
html(lang="ja")
  head
    meta(charset="UTF-8")
    title 会員登録ページ
  body
    h1 会員情報
    form(method="post" action="/member/registry")
    メールアドレス: <input type="text" name="mail">
      名前: <input type="text" name="name">
      input(type="radio" name="性別" value="男")
      span 男
      input(type="radio" name="性別" value="女")
      span 女
      button(type="submit") 登録

以下はHTMLです。

HTML
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>会員登録ページ</title>
</head>

<body>
<h1>会員情報</h1>
<form method="post" action="/member/registry">
  メールアドレス: <input type="text" name="mail">
  名前: <input type="text" name="name">
  <input type="radio" name="性別" value="男" /><input type="radio" name="性別" value="女" /><button type="submit">登録</button>
</form>
</body>

</html>

見比べてみると、Pugは閉じタグが不要なため簡潔に表現することができます。
閉じタグがないため、改行やインデントなどで全体を構成していきます。

慣れるまで違和感がありますが、慣れてくると以下のようなメリットがあります。
・CSSと書き方の統一(classは. 、idは#)
・ファイル分割ができるため、管理がしやすい。
・繰り返しが楽につくれる

この他にもたくさんのメリットがあるので、Node.jsを使う方にはおすすめのテンプレートエンジンです。

#2. アンケートをつくる
Pugは先ほど見た通り、
・要素名(h1やbuttonなど)の後に要素の値を記述します。
・属性(methodやtype)を書く場合は要素名のあとに () を書き、その中に属性を記述していきます。
・属性が2つ以上続く場合には半角スペースで区切ります。
・入れ子構造にする場合はインデントを使います。
というルールがあります。

form.pug
doctype html
html(lang="ja")
  head
    meta(charset="UTF-8")
    title アンケート
  body
    h1 どのスポーツがやりたいですか?
    form(method="post" action=path)
      span 名前:
      input(type="text" name="name")
      span 年齢:
      input(type="text" name="age")
      span 血液型:
      select(name="blood")
        option(value="A") A型
        option(value="B") B型
        option(value="O") C型
        option(value="AB") D型
      input(type="radio" name="favoriteSport" value=firstItem)
      span #{firstItem}
      input(type="radio" name="favoriteSport" value=secondItem)
      span #{secondItem}
      button(type="submit") 投稿

以上の.pugファイルをつくり、ファイルが保存されているディレクトリに移動し、
コンソールで以下のようにコマンドを打ちコンパイルをしてみます。
今回は表示の確認のためにコンパイルするだけです。

$ pug form.pug --pretty

これでform.htmlファイルを作り出すことができます。
--prettyオプションは、htmlを綺麗な形で出力してくれます。
ディレクトリを見てみて、以下のようなhtmlファイルができていたら確認成功です。

form.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8">
    <title>アンケート</title>
  </head>
  <body>
    <h1>どのスポーツがやりたいですか?</h1>
    <form method="post"><span>名前:</span>
      <input type="text" name="name"><span>年齢:</span>
      <input type="text" name="age"><span>血液型:</span>
      <select name="blood">
        <option value="A">A型</option>
        <option value="B">B型</option>
        <option value="O">C型</option>
        <option value="AB">D型</option>
      </select>
      <input type="radio" name="favoriteSport"><span></span>
      <input type="radio" name="favoriteSport"><span></span>
      <button type="submit">投稿</button>
    </form>
  </body>
</html>

次にPugファイルを自動的にhtmlに変換してくれて、URLによって内容を変えることができるようにNode.js(JavaScript)ファイルを作っていきます。
以下のようなファイルを作ってください。

index.js
'use strict';
const http = require('http');
const pug = require('pug');
const server = http.createServer((req, res) => {
  console.info('[' + new Date() + '] Requested by ' + req.connection.remoteAddress);
  res.writeHead(200, {
    'Content-Type': 'text/html; charset=utf-8'
  });

  switch (req.method) {
    case 'GET':
     if (req.url === '/enquetes/base-soccer') {
      res.write(pug.renderFile('./form.pug', {
        path: req.url,
        firstItem: '野球',
        secondItem: 'サッカー'
     }));
      } else if (req.url === '/enquetes/tennis-basket') {
        res.write(pug.renderFile('./form.pug', {
          path: req.url,
          firstItem: 'テニス',
          secondItem: 'バスケ'
        }));
      }
      res.end();
      break;
    case 'POST':
      let data = '';
      req.on('data', (chunk) => {
        data = data + chunk;
      }).on('end', () => {
        const decodedData = decodeURIComponent(data);
        console.info('[' + new Date() + '] 投稿: ' + decodedData);
        res.write('<!DOCTYPE html><html lang="ja"><body><h1>' +
          decodedData + 'が投稿されました</h1></body></html>');
        res.end();
      });
      break;
    default:
      break;
  }
}).on('error', (e) => {
  console.error('[' + new Date() + '] Server Error', e);
}).on('clientError', (e) => {
  console.error('[' + new Date() + '] Client Error', e);
});
const port = 8000;
server.listen(port, () => {
  console.info('[' + new Date() + '] Listening on ' + port);
});

#####解説

const http = require('http');
const pug = require('pug');
const server = http.createServer((req, res) => {
  console.info('[' + new Date() + '] Requested by ' + req.connection.remoteAddress);
  res.writeHead(200, {
    'Content-Type': 'text/html; charset=utf-8'
  });

1行目でhttpモジュールをインストールしています。
2行目でpugモジュールをインストールしています。
3行目でhttpモジュールを使い、サーバーを作っています。
(req, res) => { は、サーバーが返すリクエストとレスポンスのオブジェクトです。
6行目のres.writeHead(200, {
'Content-Type': 'text/html; charset=utf-8'
});
は、
レスポンスとしてヘッダに「ステータスコードが200(リクエスト成功)である」こと、「ファイルがhtmlである」こと、「文字コードがutf-8である」ことを書き込んでいます。

  switch (req.method) {
    case 'GET':
     if (req.url === '/enquetes/base-soccer') {
      res.write(pug.renderFile('./form.pug', {
        path: req.url,
        firstItem: '野球',
        secondItem: 'サッカー'
     }));
      } else if (req.url === '/enquetes/tennis-basket') {
        res.write(pug.renderFile('./form.pug', {
          path: req.url,
          firstItem: 'テニス',
          secondItem: 'バスケ'
        }));
      }
      res.end();
      break;

1行目はswitch文の最初です。
2行目にはリクエストがGETである場合、
3行目にはurlが/enquetes/base-soccerである場合、
4行目のres.write()は()内の処理を直接ブラウザに表示します。
pug.renderFile('./form.pug'...は
上で説明した pug form.pugと同じ意味です。
5-7行目はpath: req.urlがurlが/enquetes/base-soccerであることを意味しており、urlが/enquetes/base-soccerである場合、firstItem: '野球', secondItem: 'サッカー'が
form.pugの以下の部分に当てはまるようになるということです。

input(type="radio" name="favoriteSport" value=firstItem)
      span #{firstItem} <= '野球が代入される'
      input(type="radio" name="favoriteSport" value=secondItem)
      span #{secondItem} <= 'サッカーが代入される'

GETメソッドでURLが/enquetes/base-soccer の場合、以下の画像のような表示になるかと思います。
スクリーンショット 2019-11-08 21.05.43.png

続きの部分の説明になります。

    case 'POST':
      let data = '';
      req.on('data', (chunk) => {
        data = data + chunk;
      }).on('end', () => {
        const decodedData = decodeURIComponent(data);
        console.info('[' + new Date() + '] 投稿: ' + decodedData);
        res.write('<!DOCTYPE html><html lang="ja"><body><h1>' +
          decodedData + 'が投稿されました</h1></body></html>');
        res.end();
      });
      break;
    default:
      break;

1行目はリクエストメソッドがPOSTである場合、
2行目は4行目で使用する変数dataを作成しています。
3-4行目は'data'イベントがあった場合の処理を表しており、
POSTで送られたデータがchunkにバイト文字として少しずつ代入され、data変数に代入されます。chunkはコンソールで表示すると以下のような文字になります。
スクリーンショット 2019-11-08 21.00.40.png
5行目からは'end'イベントがあった場合の処理が書かれています。
まず変数dataに代入されたバイト文字列はdecodeURIComponent(data);で、
デコードされて、バイト文字列が解除され、decodedData変数に代入されます。
その後、8行目で、res.writeでそのdecodedDataが表示されます。
10行目のres.end()で'end'イベントが終わります。
11行目以降のbreakやdefaultはswitch文の分岐処理です。

POSTメソッドの場合、ブラウザは以下のような表示になります。
POSTメソッドは、GETメソッドで取得したアンケートで、投稿ボタンを押すことを意味します。
スクリーンショット 2019-11-08 21.06.55.png

}).on('error', (e) => {
  console.error('[' + new Date() + '] Server Error', e);
}).on('clientError', (e) => {
  console.error('[' + new Date() + '] Client Error', e);
});
const port = 8000;
server.listen(port, () => {
  console.info('[' + new Date() + '] Listening on ' + port);
});

1行目から5行目はエラー処理です。
6行目から9行目はサーバーが待ち受ける設定になります。
ポート番号8000番で待ち受けることを意味します。

解説が終わったので、
ファイルを作ったディレクトリ上で、以下のコマンドを打ちサーバーを立ち上げ、ちゃんと表示されるか確認しましょう。

$ node index.js
> [Fri Nov 08 2019 20:26:25 GMT+0900 (GMT+09:00)] Listening on 8000

以上のような表示が出たら、ブラウザで
http://localhost:8000/enquetes/base-soccer

http://localhost:8000/enquetes/tennis-basket
にアクセスしてみましょう。
・アンケートが表示されたこと
・URLによってアンケートの表示が違うこと
が確認できたら成功です。

##参考
「N予備校 プログラミングコース」
https://www.nnn.ed.nico/
「HTMLタグリファレンス」
http://www.htmq.com/html/form.shtml
「PugでHTMLコーディングを効率化・メリットと使い方を知る」
https://tech.qookie.jp/posts/info-pug-feature/
「【Pug】ゴリラでもわかるJade改めPug入門」
https://blog.mismithportfolio.com/web/20160326pugbegin#d

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?