第4回「Node.js入門」EJSライブラリでWebアプリケーションを作る node.js
こんにちは。今回は Node.js でEJSライブラリを使いフレームワークでWebアプリを作っていきたいと思ます。
始めに
今回、ブログを執筆させて頂くうえで、とても参考になるサイトがありました。 Node.jsのスクリプトの基本を覚えよう (libro様)おかげさまで、より深く理解でき、何も問題なくプログラムを動かせることができました。 |
※すごく丁寧で分かりやすいサイトですので、良かったら見てみてください。
※本サイトは、著者の自分が解りやすくまとめ、オリジナルをアレンジしたものであり、パクリにならないように気を付けます。
目次・「ejsライブラリ」フレームワークを使うメリット ・npmでEJSをインストールしよう ・テンプレートで使える特殊なタグ ・EJSによるテンプレートの表示 ・テンプレート部品を組み合わせる ・配列データを繰り返し出力する ・まとめ ・今回の記事を書くにあたって参考にしたサイト |
・「ejsライブラリ」フレームワークを使うメリット
ejsライブラリを使うメリットは、効率的にWebアプリケーションを作成できるからです。
・npmでEJSをインストールしよう
前回、HTMLファイルを読み込んで表示させる、ということを行いましたが、思ったより面倒くさいことがわかりました。ファイルを読み込むのに非同期メソッドを使わないといけないし、ちょっとしたデータをHTMLに受渡して表示させるのもいちいちreplaceでコードを置換したりしないといけない。もっと簡単な方法はないのか?と思ったことでしょう。 実は、あります。それは「テンプレートエンジン」を使うのです。Node.jsでは、さまざまなテンプレートエンジンが利用できます。もっとも一般的に用いられているのは「EJS」というものでしょう。 では、EJSをインストールしましょう。Node.jsには「npm」というパッケージ管理プログラムが用意されています。これを使うことで、コマンド一発で必要なライブラリをオンライン経由でダウンロードしインストールできます。 |
前述しましたが、ejsライブラリ(テンプレートエンジンの中の一つ)を使えば、便利に早く作成できるわけですね。
コマンドプロンプトやターミナルを起動し、以下のように実行してください。これでEJSが自動的にインストールされます。 npm install ejs この「npm」というパッケージ管理プログラムは、Node.jsを利用する場合には必須です。必要なものがあれば大抵はnpmでインストールをしますので、「npm install」はここで覚えておくようにしましょう。 なお、EJSそのものは、npmを使わなくとも入手できます。Githubで公開されており、そこからファイルをダウンロードできます。 |
インストールできましたでしょうか。
EJS自体は、全てのWebアプリケーションで使うわけではないので、オプション「-g」(グローバル)は必要なさそうですね。
・テンプレートで使える特殊なタグ
EJSでは、テンプレートとなるHTMLのコード内に、特殊なタグを使って必要な情報を埋め込むことができます。用意されているタグは以下の2つです。 <%= 値 %> 記述した値をその場に書き出します。スクリプト側で用意した変数などを表示するのに使います。HTMLタグなどが含まれていた場合、それらはエスケープ処理されます。 <%- 値 %> 同じように値をその場に書き出します。ただし、こちらはHTML関連のタグはエスケープ処理されず、そのまま書きだされます。 |
ふむふむ。なるほど!!
<% %> 内で、「=」はエスケープする。「-」はエスケープしないという事ですね。
エスケープとは✍🏻 入力された文字列に、特殊な文字列が入っていたら、その文字を他の文字に変換する事を言います。
これは、入力内容をデータベースに登録する際に、非常に役立つのでオススメの機能です。 |
<% スクリプト %> スクリプトを記述し、それをレンダリングする際に実行します。これは、HTMLに<script>タグで書かれているスクリプトとは違います。<script>タグはクライアント側(ブラウザ内)に送られ、そこで実行されますが、この<% %>で書かれたタグはサーバー側(Node.js内)で実行され、その結果がクライアントへと送られます。 これらのタグは、閉じる部分はすべて共通して%>となっていますが、これを-%>というように半角マイナスをつけて記述すると、値の出力後、改行するようになります。 |
<% スクリプト %>の中は、サーバー側で行われる処理を書きます
実際にこれらのタグをどう使いこなすかは、やってみないとわかりませんね。では、簡単なサンプルを作ってみましょう。下にリストを掲載しておきます。これを「hello.ejs」というファイル名で、Node.jsのスクリプトファイルと同じ場所に保存してください。 これが、EJSのテンプレートファイルです。テンプレートファイルは、通常、「.ejs」という拡張子で作成します。ここでは、HTMLの中に以下のようなタグを埋め込んであります。 <%=title %> <%-content %> これらは、それぞれtitle、contentという変数を出力していることになります。ということは、スクリプト側で、これらの変数を用意し、テンプレート側に渡すことができればいいわけですね。<%= %>と<%- %>は、テンプレートのもっとも基本となるものといってよいでしょう。(なお、contentの出力は<%=ではなく、<%-を使っています。これは、もう少し後になって理由がわかります) 「hello.ejs」と名前を付けて保存してください。 <!DOCTYPE html> <html lang="ja"> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <title><%=title %></title> <style> body { font-size:12pt; color:#006666; } h1 { font-size:18pt; background-color:#AAFFFF; } pre { background-color:#EEEEEE; } </style> </head> <body> <header> <h1 id="h1"><%=title %></h1> </header> <div role="main"> <p><%-content %></p> </div> </body> </html>
|
第3回「Node.js入門」htmlファイルを表示 ですと、「@title@」や「@content@」としていました。
今回は「ejs」フレームワークを使うことで、「<%=title %>」や「<%=content %>」に書き方が変わりました。
注意:ソースはコピペでOKですが、ファイルを保存するときは、必ず「UTF-8 BOM無し」で保存しましょう。これは世界基準です!
・EJSによるテンプレートの表示
「app.js」と名前を付けて、「hello.ejs」と同じ階層に保存してください。
var http = require('http'); var fs = require('fs'); var ejs = require('ejs'); var hello = fs.readFileSync('./hello.ejs', 'utf8'); var server = http.createServer(); server.on('request', doRequest); server.listen(1234); console.log('Server running!'); // リクエストの処理 function doRequest(req, res) { var hello2 = ejs.render(hello, { title:"タイトルです", content:"これはサンプルで作成したテンプレートです。", }); res.writeHead(200, {'Content-Type': 'text/html'}); res.write(hello2); res.end(); }
では、用意したテンプレートファイルを読み込んでWebページを表示させてみましょう。これには、いくつかの操作が必要となります。
1. ファイルの読み込み。EJS自体にはファイルを読み込む機能はありません。読み込みは、fsオブジェクトを利用することになります。(ただし、今回は非同期ではなく、同期メソッドを使って前回のreadFileよりシンプルなスクリプトにします) 2. 読み込んだテンプレートデータのレンダリング。これにより、テンプレート内にある<%= %>タグなどの特殊なタグが実際に出力されるテキストに変換されます。 3. 作成されたデータをレスポンスに書き出して完了です。 要するに、EJSというテンプレートエンジンが行なってくれるのは、2のレンダリング部分だけで、後は普通にNode.jsの機能を使って処理する必要がある、というわけですね。 |
「EJSというテンプレートエンジンが行なってくれるのは、2のレンダリング部分だけ」と書かれていますが
実際はすごい楽に記述できるようになってます。謙遜されてるのかな。
前回だと、「.replace()」関数を使って、文字を置き換えていましたが、ejsだと「.render()」メソッドを使えば、分かりやすい記述になります。次で「.render()」メソッドの具体的な説明をします。
では、先ほど作成したhello.ejsをレンダリングして表示するスクリプトを作成してみましょう。下にサンプルを掲載しておきますので、これを記述して動かしてみてください。タイトルやコンテンツの部分には、スクリプト側で用意しておいたテキストが嵌めこまれ表示されることがわかるでしょう。動作を確認したら、スクリプトのポイントをチェックしましょう。 ejsの読み込み var ejs = require('ejs'); 最初にEJSのライブラリを読み込みます。これはrequire関数で「ejs」を引数に指定します。ここで取得されたejsオブジェクトを使ってテンプレートのレンダリングなどを行います。 同期メソッドによるファイルの読み込み var hello = fs.readFileSync('./hello.ejs', 'utf8'); fsオブジェクトを使い、テンプレートファイルを読み込みます。ここではreadFileではなく、「readFileSync」というメソッドを使っています。基本的にはreadFileと同じですが、非同期ではなく、同期処理で読み込みます。つまり、このメソッドを呼び出すとファイルの読み込みを行い、それが完了してから次に進む、というわけです。 同期処理ですから、読み込み終わったら呼び出す「コールバック関数」はありません。終わったらそのまま続きのスクリプトを実行するのですからコールバックなんて必要ないですね。 「だけど、ファイルの読み込みは時間がかかることもあるから非同期にしないと他の処理が止まってしまうって……」と思った人。その通り、readFileSync実行中は他の処理があったとしても停止中です。が、これを呼び出している場所をよく見てください。http.createServerでサーバーを作る前にファイルの読み込みを済ませているのがわかるでしょう? テンプレートというのは、リクエストがある度に使うわけで、なら最初からグローバル変数に読み込んでおいて利用したほうが絶対に楽ちんですから。 |
今回は非同期処理で、HTMLファイルを読み込んでいますね。「読み込まれる処理が終わるまで次の処理へ行かないのでは?」と僕も思ったのですが、最初に、グローバル変数に入れてしまえば問題ないという事のようです。
テンプレートをレンダリングする var hello2 = ejs.render(hello, { title:"タイトルです", content:"これはサンプルで作成したテンプレートです。", }); テンプレートのレンダリングを行うのが、ejsオブジェクトの「render」メソッドです。これは、整理すると以下のようになります。 第1引数――レンダリングする対象データ(=読み込んだテンプレートの文字列)を指定します。 ポイントは第2引数です。先ほど、テンプレートにtitleとcontentという変数を出力するようにタグを用意したのを思い出してください。これらの変数が連想配列に用意されていることがわかるでしょう。このように、第2引数に変数などの値を用意してrenderすることで、テンプレート側にあるそれらの変数に値が代入されるのです。
ヘッダー情報にCintent-Type:text/hemlを設定する res.writeHead(200, {'Content-Type': 'text/html'}); 最後に忘れてはいけないのが、writeHeadによるヘッダーの出力です。Content-Typeに「text/html」を設定します。これにより、レスポンスに書き出される内容がHTMLであることがわかります。 |
「ejs」ライブラリを使うと、遥かにレンダリングが短くなります。
前述しましたが、前回だと、「.replace()」関数を使ってました。
この記述方法の方がはるかに楽だしオススメですね!
そして、これはお決まり
- 「writeHead」 は head 情報
- 「write」 は body 内の情報
- 「end」 で 終了
res | |
writeHead | ヘッダー情報 |
write | html情報 |
end | 完了 |
コマンドプロンプトで、ファイルを保存したフォルダに移動し、下記のコマンドを実行します。
node app.js
ブラウザのURLには「http://localhost:1234 」と入れて確認すると、
正常に、文字がレンダリングしました。
どうでしょう。ちゃんと動きましたでしょうか。
・テンプレート部品を組み合わせる
テンプレート部品を組み合わせる テンプレートの基本的な使い方はこれでわかりました。が、これだけではテンプレートとしての機能は十分ではありませんね。ページを表示するのに、テンプレートをレンダリングして書き出す。これだけです。 例えば、いくつものページが有るサイトでは、全体の構成を記したテンプレートを用意し、ここに必要に応じてコンテンツ用のテンプレートをはめ込んで表示させたりします(このlibroもそのような形で作られています)。こうした「全体のテンプレート内に、コンテンツのテンプレートを嵌めこみ表示する」といったことは行えるのでしょうか。やってみましょう。 ベースとなるテンプレートには、先ほど作成したhello.ejsをそのまま使うことにします。このテンプレートでは、コンテンツを表示する部分に<%- content %>というタグを用意しておきました。ということは、実際に表示する内容のテンプレートを用意しておき、それをここにはめ込んで出力すれば、コンテンツだけをいろいろと変更してページを作れるようになります。 |
本格的になってきましたね。やっぱり1ページずつファイルを分けたりするのって、プログラムを使う意味はないです。
せっかく、プログラムを使うなら、同じヘッター・フッター・サイドバーとかで、メインコンテンツのみ違う内容にしたいです。
そうする事で、制作する時間も、更新する手間も短くなります。
では、コンテンツ用のテンプレートとして、「content1.ejs」というファイルを作成しましょう。内容は下のリスト欄に掲載しておきます。作成後、Node.jsのスクリプトファイルと同じ場所に廃しておいてください。 <p>※サンプルで作ったコンテンツです。</p> <p>別ファイルとして用意したものを読み込んで使います。</p> <p><%= message %></p> このファイルでは、コンテンツとして表示する内容をHTMLで記述してあります。また、<%= message %>というようにテンプレート用のタグも用意しておきました。 このcontent1.ejsを、先ほどのhello.ejsの<%- content %>にはめ込んで表示させてみます。スクリプトを下に掲載しておきましたので書き換えて試してみてください。ここでは、以下の手順で表示を作成しています。 var http = require('http'); var fs = require('fs'); var ejs = require('ejs'); var hello = fs.readFileSync('./hello.ejs', 'utf8'); var content1 = fs.readFileSync('./content1.ejs', 'utf8'); var server = http.createServer(); server.on('request', doRequest); server.listen(1234); console.log('Server running!'); // リクエストの処理 function doRequest(req, res) { var hello2 = ejs.render(hello, { title: "タイトルです", content: ejs.render(content1,{ message:"テストメッセージ" }) }); res.writeHead(200, {'Content-Type': 'text/html'}); res.write(hello2); res.end(); } 1. サーバーを作成する前に、あらかじめ2つのテンプレートを変数に読み込んでおく。 2. まず、コンテンツ用のテンプレート(content1.ejs)をrenderでレンダリングする。 3. ページ全体のテンプレート(hello.ejs)をrenderでレンダリングする。この際、content1.ejsをレンダリングしたデータをオプションの値として渡す。 4. レンダリングされたデータを書き出す。 複数のテンプレートを組み合わせて使う場合の基本は、「中にあるものを先にレンダリングし、その結果をオプションに指定して外側のレンダリングを行う」ということです。 あるテンプレート内に別のテンプレートをはめ込む場合、「レンダリング済み」のデータを嵌めこむのが基本です。はめ込んだ後でレンダリングすれば……と思っていると、はめ込んだテンプレート内のタグがレンダリングされずに表示されてしまったりするので気をつけてください 。 |
レンダリングする仕組みで、「ejs.render()」メソッドをネスト(組み合わせ)していますね。
まだですが、取り替えるコンテンツを if文などで条件を付けたりして、いろんなコンテンツにしたら、更に複雑にプログラムが組めそうです!
コマンドプロンプトで下記のコマンドを実行します。
node sampleapp.js
ブラウザで「http://localhost:1234 」を確認すると
しっかりコンテンツの内容が、表示されています!!
・配列データを繰り返し出力する
EJSのテンプレートでは、<% %>タグを使ってJavaScriptのスクリプトを実行させることができます。これは、レンダリング時に実行される(つまりサーバー内で実行される)ため、ブラウザに実際に表示されるページには現れません。スクリプトの実行結果が表示されるのみです。
この<% %>によるスクリプトを作成する場合、注意すべき点がいくつかあります。まとめておきましょう。
1. <% %>内では、何かを書き出して表示することはできません。その場合は一度タグを抜け、<%= %>タグなどで値を出力する必要があります。<% %>タグの中で<%= %>タグを使うことはできません。 2. JavaScriptのスクリプトですが、一般的なJavaScriptの機能には利用できないものもあります。例えば、DateやMathなどのオブジェクトは使えますが、alertのようなブラウザ依存機能は使えません。またdocumentなどDOMを操作する機能も使えません。 3. スクリプトからレンダリング時に渡される変数などの値は、そのまま<% %>内で変数として使うことができます。 では、実際に簡単なサンプルを作ってみましょう。まず、content1.ejsの内容を下のリスト欄のように書換えてみてください。ここでは、dataの内容を取り出して表示させる処理を<% %>利用で作成しています。 <p>※サンプルで作ったコンテンツです。</p> <p>配列データを渡してリストにして表示します。</p> <p><ol> <% data.forEach(function(val){ %> <li><%= val %></li> <% }) %> </ol></p> /************************sampleapp.jsのコード***************************/ var http = require('http'); var fs = require('fs'); var ejs = require('ejs'); var hello = fs.readFileSync('./hello.ejs', 'utf8'); var content1 = fs.readFileSync('./content1.ejs', 'utf8'); var server = http.createServer(); server.on('request', doRequest); server.listen(1234); console.log('Server running!'); // リクエストの処理 function doRequest(req, res) { var hello2 = ejs.render(hello, { title: "タイトルです", content: ejs.render(content1, { data: [ "これは最初のデータです。", "次のデータだよ。", "一番最後のデータなのだ。" ] }) }); res.writeHead(200, {'Content-Type': 'text/html'}); res.write(hello2); res.end(); } |
ここは、大事だと本能が言っております!!
- <% %>内でスクリプトを書いた場合、一度<% %>タグを抜けてから出力する
- 全てのjavascrpitが使えるわけではない
- サーバーから渡された変数なら、そのまま扱える
ここでは、renderメソッドの引数に「data」という値を用意しています。これは、見ればわかるようにテキストの配列が設定されています。この配列の値を順に取り出して表示しよう、というわけです。出力されている部分を見ると、
<% data.forEach(function(val){ %> <li><%= val %></li> <% }) %> このようになっていますね。<% %>タグを使い、繰り返し処理を記述しています。「forEach」という見慣れないメソッドが使われていますが、これは配列(Arrayオブジェクト)にあるメソッドで、配列から要素を順に取り出して引数の関数を実行するものです。取り出された値は、引数の関数に引数として渡されます。働きがよくわからない人は、以下のように書換えて考えると良いでしょう。 <% for (var i = 0;i < data.length;i++){ %> <li><%= data[i] %></li> <% } %> 構文内の、値を書き出す部分は<%= %>タグになっています。<% %>を使うときには、このように「処理部分だけを<% %>内に書き、出力は<%= %>に書く」というように、処理と出力をきちんと切り分けて考える必要がある、ということを忘れないようにしましょう。 |
なかなかハイカラな方法を使っていますね!「forEach」
自分は、もちろん下の方法で配列を扱えっていますが、新しい事を覚えれて嬉しいです。
PHPだと、for(i=0;i<count(data);i++){} とやるのですが 、javascriptだと .length を使うのです。
コマンドプロンプトで下記のコマンドを実行します。
node sampleapp.js
「http://localhost:1234 」を確認すると
配列の中の値が、順番に表示されています。
どうでしょう。ちゃんと表示されましたでしょうか。
今回は以上です。お疲れさまでした。
・まとめ(飛ばしてもOKです)
いやー、本当に素晴らしいサイトに出会ったおかげで、さくさくできます^^
libro様には本当に感謝感激雨涙です!
実はわたくし、今回、JSファイルを、UTF-8以外で保存していて、そうとう動かないと悩みました。・・・初歩的な事なのですが><)
ただ、そこに気が付いてからはあっという間!!すぐ動きました。
できる人に教わるのが一番のはやみちなのかもしれません。
今日は土曜日なので、多摩川にサンドウィッチをもって、釣りに行こうと思います!!🐟🐟🐟
では、よい週末ライフを!
・今回の記事を書くにあたって参考にしたサイト
参考にさせて頂いたサイトの管理者様、今回もありがとうございました。
Comments
Hello, are there market stalls for food and fashion planned to open around and during the event? Cheers Annika
[…] 前前回に行ったEJSを使うのですね。 […]
[…] 前前前回にやった「EJS」も、フレームワークの一つでした。今回、勉強していくのは「Express」というフレームワークです。 […]