免責事項
この記事は初心者視点でザックリとした説明をしています。正確性に欠ける可能性がございますが、ご了承ください。「明らかに違うよ」ということがありましたら、ご指摘くださると幸いです。
環境
OS:最新版ではないMacOS
VirtualBox:5.2.26
Vagrant:2.2.6
Ubuntu:ubuntu/bionic64 v20181129.0.0
目次
- テンプレートエンジンとは
- アンケートをつくる
1. テンプレートエンジンとは
テンプレートエンジンはテンプレートと呼ばれる雛形とデータを合成し、HTML等の成果ドキュメントを出力するライブラリです。
Wikipediaにわかりやすい画像があったのでお借りしました。
(画像 by Dreftymac at English Wikipedia)
ようするに、HTMLなどのドキュメントを作るのを簡単にしてくれるらしいです。
今回はPugというNode.jsのテンプレートを使って簡単なアンケートを作ります。
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です。
<!DOCTYPE html><htmllang="ja"><head><metacharset="UTF-8"><title>会員登録ページ</title></head><body><h1>会員情報</h1><formmethod="post"action="/member/registry">メールアドレス: <inputtype="text"name="mail">名前: <inputtype="text"name="name"><inputtype="radio"name="性別"value="男"/>男
<inputtype="radio"name="性別"value="女"/>女
<buttontype="submit">登録</button></form></body></html>
見比べてみると、Pugは閉じタグが不要なため簡潔に表現することができます。
閉じタグがないため、改行やインデントなどで全体を構成していきます。
慣れるまで違和感がありますが、慣れてくると以下のようなメリットがあります。
・CSSと書き方の統一(classは. 、idは#)
・ファイル分割ができるため、管理がしやすい。
・繰り返しが楽につくれる
この他にもたくさんのメリットがあるので、Node.jsを使う方にはおすすめのテンプレートエンジンです。
2. アンケートをつくる
Pugは先ほど見た通り、
・要素名(h1やbuttonなど)の後に要素の値を記述します。
・属性(methodやtype)を書く場合は要素名のあとに () を書き、その中に属性を記述していきます。
・属性が2つ以上続く場合には半角スペースで区切ります。
・入れ子構造にする場合はインデントを使います。
というルールがあります。
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ファイルができていたら確認成功です。
<!DOCTYPE html><htmllang="ja"><head><metacharset="UTF-8"><title>アンケート</title></head><body><h1>どのスポーツがやりたいですか?</h1><formmethod="post"><span>名前:</span><inputtype="text"name="name"><span>年齢:</span><inputtype="text"name="age"><span>血液型:</span><selectname="blood"><optionvalue="A">A型</option><optionvalue="B">B型</option><optionvalue="O">C型</option><optionvalue="AB">D型</option></select><inputtype="radio"name="favoriteSport"><span></span><inputtype="radio"name="favoriteSport"><span></span><buttontype="submit">投稿</button></form></body></html>
次にPugファイルを自動的にhtmlに変換してくれて、URLによって内容を変えることができるようにNode.js(JavaScript)ファイルを作っていきます。
以下のようなファイルを作ってください。
'use strict';consthttp=require('http');constpug=require('pug');constserver=http.createServer((req,res)=>{console.info('['+newDate()+'] 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:'サッカー'}));}elseif(req.url==='/enquetes/tennis-basket'){res.write(pug.renderFile('./form.pug',{path:req.url,firstItem:'テニス',secondItem:'バスケ'}));}res.end();break;case'POST':letdata='';req.on('data',(chunk)=>{data=data+chunk;}).on('end',()=>{constdecodedData=decodeURIComponent(data);console.info('['+newDate()+'] 投稿: '+decodedData);res.write('<!DOCTYPE html><html lang="ja"><body><h1>'+decodedData+'が投稿されました</h1></body></html>');res.end();});break;default:break;}}).on('error',(e)=>{console.error('['+newDate()+'] Server Error',e);}).on('clientError',(e)=>{console.error('['+newDate()+'] Client Error',e);});constport=8000;server.listen(port,()=>{console.info('['+newDate()+'] Listening on '+port);});
解説
consthttp=require('http');constpug=require('pug');constserver=http.createServer((req,res)=>{console.info('['+newDate()+'] 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:'サッカー'}));}elseif(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 の場合、以下の画像のような表示になるかと思います。
続きの部分の説明になります。
case'POST':letdata='';req.on('data',(chunk)=>{data=data+chunk;}).on('end',()=>{constdecodedData=decodeURIComponent(data);console.info('['+newDate()+'] 投稿: '+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はコンソールで表示すると以下のような文字になります。
5行目からは'end'イベントがあった場合の処理が書かれています。
まず変数dataに代入されたバイト文字列はdecodeURIComponent(data);で、
デコードされて、バイト文字列が解除され、decodedData変数に代入されます。
その後、8行目で、res.writeでそのdecodedDataが表示されます。
10行目のres.end()で'end'イベントが終わります。
11行目以降のbreakやdefaultはswitch文の分岐処理です。
POSTメソッドの場合、ブラウザは以下のような表示になります。
POSTメソッドは、GETメソッドで取得したアンケートで、投稿ボタンを押すことを意味します。
}).on('error',(e)=>{console.error('['+newDate()+'] Server Error',e);}).on('clientError',(e)=>{console.error('['+newDate()+'] Client Error',e);});constport=8000;server.listen(port,()=>{console.info('['+newDate()+'] 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