Lesson 3
画面を作ってみる
目次
Lesson 3
Chapter 1
EJSのインストール
前回のLesson2では、Node.jsを使ってWebページに文字を表示させました。
今はまだシンプルな画面しか作成できていませんが、応用すればメールやショッピングサイト、SNSといった複雑なWebアプリケーションも作成可能です。
ここからのLessonでは、テンプレートエンジン「EJS」とフレームワーク「Express」を使って、文字と画像が表示される簡単なWebアプリケーションを作成しましょう。
EJSのインストール
まずはEJSをインストールしましょう。
Lesson1-4「EJSとは」で述べたように、EJSはNode.jsのパッケージとして提供されています。以下の通り、npmを使ってインストールしてください。
ターミナル
npm install ejs
npm init
を行ったばかりの状態では、「package.json」には何のパッケージ情報も記述されていません。
今回EJSのパッケージをインストールしたことで、「package.json」のdependencies
以下にejs
の表記が追加されているはずです。
また、同時に作業ディレクトリ直下に「node_module」ディレクトリと「package-lock.json」ファイルが作成されています。
このうち「node_module」ディレクトリには実際にインストールしたパッケージ(依存関係を含む)が、「package-lock.json」にはその具体的なバージョン情報が保存されています。
実行後のディレクトリ構成
practice
├─ node_modules/ //新規作成される
├─ hello.js
├─ main.js
├─ package-lock.json //新規作成される
└─ package.json
上記のフォルダ構成になっていれば完了です。
環境構築
上記の構成はLesson2から続いています。新しく作業を始めたい方は任意のディレクトリ直下で「npm init」を入力し、package.jsonファイルを作成してください。

Lesson 3
Chapter 2
Expressのインストール
Expressのインストール
続いて、フレームワークである「Express」をインストールします。ExpressもNode.jsのパッケージとして提供されており、npm install
でインストール可能です。
ターミナル
npm install express
EJSと合わせて2種類のパッケージをインストールしました。「package.json」を確認し、dependencies
以下に両パッケージの名前が記述されていれば完了です。
{
"name": "new_project",
"version": "1.0.0",
"description": "New Project",
"main": "main.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Tarou node",
"license": "MIT",
"dependencies": {
"ejs": "^3.1.8", //バージョンが異なる場合があります。
"express": "^4.18.1" //バージョンが異なる場合があります。
}
}
EJSとExpressのバージョンについて
本教材が依拠しているのは上記のバージョンです。皆さんの実行環境によっては、教材と同じ記法が使えない場合もあります。その際はお手数ですが、バージョンを下げる、公式ドキュメントを参考に読み進めるなどの対応を講じてください。
サンプルページの作成
ここでは、異なる大きさの文字列を表示するWebページを作成します。 Node.jsで特定の処理を実行し、その結果を返すというアプリケーションの基本動作を学びましょう。
まずは、ディレクトリ直下に「index.ejs」「man.js」のファイルを作成します。以下と同じ構成であることを確認しましょう。
フォルダ構成
practice
├─ node_modules/
├─ hello.js
├─ index.ejs
├─ main.js
├─ package-lock.json
└─ package.json
「index.ejs」を以下の通り編集してください。ここで記述した内容がWebページに表示されます。
index.ejs
<!DOCTYPE html>
<html lang="ja">
<head>
<meta http-equiv="content-type"
content="text/html; charset=UTF-8">
<title>Index</title>
</head>
<body>
<header>
<h1>Hello World!</h1>
</header>
<div role="main">
<p>これからEJSを使ってこのWebページを作成していきます。</p>
</div>
</body>
</html>
見ての通り、上記自体はHTMLのコードに過ぎません。したがって、style
タグを使えば文字の太さや色を編集することも可能です。
次に、「main.js」を以下のように編集してください。
main.js
const http = require('http');
const fs = require('fs');
const ejs = require('ejs');
const index_page = fs.readFileSync('./index.ejs', 'utf8');
var server = http.createServer(getFromClient);
server.listen(3000);
console.log('Standby.');
function getFromClient(request, response) {
var content = ejs.render(index_page);
response.writeHead(200, {'Content-Type': 'text/html'});
response.write(content);
response.end();
}
コードの説明は後述します。編集が完了したらターミナルで以下のコマンドを入力し、「main.js」を実行しましょう。
ターミナル
node main.js
実行後、ターミナル上に「Standby.」の文字が表示されていれば準備完了です。
ブラウザでlocalhost:3000
を開いてください。
ターミナル
> node main.js
Standby.
作成したWebページ
上記のようなページが表示されていれば成功です。それでは、サンプルコードの具体的な記述内容を見ていきましょう。
サンプルコードの内容
ターミナル
const http = require('http');
const fs = require('fs');
const ejs = require('ejs');
require()
については、Lesson2-5「Hello Worldをブラウザに表示する」で説明しました。
ここでは「http」に加えて、Node.js公式のモジュールである「fs」、および「EJS」を読み込んでいます。
fsモジュールとは
fsモジュールはファイルの新規作成や読み込み、書き込みなどファイルの操作に関する機能を備えたモジュールです。
main.js
const index_page = fs.readFileSync('./index.ejs', 'utf8');
上記では、早速fsモジュールの機能を利用しています。
readFileSync
メソッドにより、引数に指定したファイルを文字列として読み込んでいます。第2引数にutf8
とあるのは、使用される文字コードがUTF-8であるためです。
main.js
var server = http.createServer(getFromClient);
Lesson2-5に登場したcreateServer
メソッドと同じです。
引数に指定した関数getFromClient
については後述します。
main.js
server.listen(3000);
こちらもLesson2-5で使用したものと同一です。サーバーのポート番号として3000を指定しています。
main.js
console.log('Standby.');
サーバー立ち上げやlisten
メソッドなどが完了した際にメッセージを表示します。
main.js
function getFromClient(request, response) {
var content = ejs.render(index_page);
response.writeHead(200, {'Content-Type': 'text/html'});
response.write(content);
response.end();
}
レンダリング処理
最後に、説明を保留にしていたgetFromClient
関数の解説です。
この関数の内部では、EJSのrender
メソッドが使用されています。render
メソッドはEJSのテンプレートファイル(ここでは「index.ejs」)をHTMLに変換し、HTMLコードを生成しています。
レンダリングの必要性
「index.ejs」の中身はHTMLファイルそのものであるため、わざわざレンダリング処理を行う必要はありません。 ただし、EJSの使い方を分かりやすく学ぶため、今回はあえて記述しています。
response.writeHead
、response.write
、
response.end
はHTMLファイルの返却をブラウザに伝える処理です。。
ここまでmain.jsの解説を行いました。大まかな流れを振り返りましょう。
- EJSなどの必要なモジュールを読み込む。
- 表示したいテンプレートファイル(今回は「index.ejs」)を
readFile
やreadFileSync
メソッドで読み込む。 render
メソッドで表示させたいHTMLコードを生成する。- 生成されたHTMLを出力する。

Lesson 3
Chapter 3
サンプルページを実装
ここまで、EJSとExpressのインストール方法を解説しました。
環境構築を終えたところで、両パッケージを使ったサンプルページの実装に移りましょう。
プロジェクトの作成
実装の下準備として、npmプロジェクトの初期化を行います。
まずはプロジェクト用に新規のディレクトリを作成してください。以下はコマンドライン上で操作する場合の例です。
~/Documents/workspace
$ mkdir sample
$ cd sample-project
以降、この「sample-project」をディレクトリ名として解説していきます。
npmプロジェクトの初期化
続いて、プロジェクトの初期化を行いましょう。
プロジェクトの初期化には、npm init
コマンドで「package.json」を作成する必要があります。覚えていない方はLesson2-4「パッケージのインストール」を復習してください。
作成したディレクトリ(例では「sample-project」)配下で以下を実行します。
~/Documents/workspace/sample-project
$ npm init
npmのオプション
npm init -y
とオプションを入れることで、質問をスキップして自動でpackage.jsonを作成してくれます。
ライブラリのインストール
それではExpressとEJSのインストールを行っていきましょう。
先ほど作ったディレクトリ配下で下記のコマンドを実行します。
~/Documents/workspace/sample-project
$ npm install express ejs
二つのパッケージがインストールされているか、「package.json」を開いて確認しましょう。正しくインストールされていれば、dependencies
以下にパッケージ名とバージョンが記載されています。
package.json
{
"name": "sample",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"ejs": "^3.1.8",
"express": "^4.18.2"
}
}
appディレクトリの作成
機能ごとにコードを整理するため、「app」という名前のディレクトリをプロジェクト直下に作成しましょう。
~/Documents/workspace/sample-project
$ mkdir app
作成後、以下のディレクトリ構成であることを確認してください。
~/Documents/workspace/sample-project
サンプルページの実装
それでは、サンプルページの実装を行なっていきましょう。
「app」ディレクトリ配下に2つのファイルと1つのディレクトリを作ってください。以下はコマンドラインでの操作例です。
~/Documents/workspace/sample-project/app
touch index.js
mkdir views
cd views
touch index.ejs
正しく作成できていれば、「app」配下のディレクトリ構成は以下のようになっています。
~/Documents/workspace/sample-project
expressの初期設定
Expressの初期設定として、「index.js」を編集します。
index.js
const express = require('express')
const app = express()
app.get('/', (req, res, next) => {
res.send('hello express')
})
app.listen(3000, () => {
console.log('Server started on port 3000')
})
上記では、require
を使ってExpressを読み込んでいます。require
は主にライブラリからモジュールを読み込むための構文です。
Expressを実行すると、定数app
にExpressの情報を格納したオブジェクトが格納されます。
app.get
では、第1引数で指定したパスにリクエストが届くと、第2引数の関数を実行するように設定しています。
app.listen
はローカルサーバーを立てています。引数で指定した「ポート番号:3000」にアクセスするとレスポンスを返す仕組みです。
ローカルサーバーとは
自身のPC内に立てられた、外部のネットワークに接続されていないサーバーのこと。
ローカルサーバーにアクセスしてみる
それではファイルを実行しましょう。
~/Documents/workspace/sample-project/app
$ node app/index.js
ブラウザで「localhost:3000」にアクセスしてください。
上記の画像のように表示がされたら成功です。
続いて、ExpressをEJSと繋げるための設定を行います。「index.js」を以下のように編集してください。
index.js
const express = require('express')
const path = require('path')
const app = express()
app.set('views', path.join(__dirname, 'views'))
app.set('view engine', 'ejs')
app.get('/', (req, res, next) => {
res.render('index.ejs')
})
app.listen(3000, () => {
console.log('Server started on port 3000')
})
EJSの初期設定
続いて、EJSの初期設定として「index.ejs」を編集します。
index.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>sample-project</title>
</head>
<body>
<h1>Hello Ejs</h1>
</body>
</html>
再びブラウザから「localhost:3000」にアクセスしてください。画像のように表示されたら成功です。
正しく表示されない場合、一旦サーバーを停止させ、「index.js」を実行し直してみてください。
まとめ
以上でサンプルページの実装は終了です。
最初からコードの細部を理解する必要はありません。まずはディレクトリ構成や各ファイルの役割など、アプリケーションの全体像を掴むようにしてください。
次のXhapterでは、変数を使って動的なデータを画面に描画します。少しずつステップアップできるように頑張りましょう。

Lesson 3
Chapter 4
変数を扱う ()
Chapter3では、Node.jsのフレームワーク「Express」とテンプレートエンジン「EJS」を組み合わせ、静的なWebページを実装しました。
とはいえ、まだHTMLを直接Webページにレンダリングしただけであり、EJSの機能は活かし切れていません。EJSの強みは、サーバー側のレスポンスに応じて、レンダリングする内容を自在に変更できる点にあります。
そこで今回は、変数を用いた動的なWebサイトの表示に挑戦してみましょう。
EJSで変数を使ってみる
EJSで変数を扱う方法については、Lesson1-4「EJSとは」で簡単に紹介しました。忘れてしまっていても問題ありません。実装しながら復習しましょう。
変数定義
早速ファイルを編集していきます。「index.ejs」を以下のように編集してください。
index.ejs
...省略
<body>
<h1></h1>
</body>
...省略
編集後、コマンドラインから「index.js」を起動してください。
/sample-project
$ node app/index.js
ブラウザからlocalhost:3000にアクセスすると、以下のように表示されているはずです。
あらためて「index.ejs」の内容を確認してみましょう。
EJSでは、タグを用いることでJavaScriptの式を直接記述できます。また、JavaScriptの変数を展開するときは
を用います。
今回の例では、変数title
に代入された文字列がh1
タグの中で展開、Webページに出力されました。
以上がEJSにおける変数の基本的な使い方です。
レスポンスの受け取り
先ほどの例は、テンプレートの中で変数の値を取得するケースです。一方、サーバーからのレスポンスとして変数を受け取ることもできます。
実践してみましょう。「index.js」と「index.ejs」ファイルを以下の通り編集してください。
index.js
...省略
app.get('/', (req, res, next) => {
res.render('index.ejs', { title: 'Hello Ejs サーバーからのレスポンス' })
})
...省略
index.ejs
...省略
<body>
<h1></h1>
</body>
...省略
編集後、Node.jsでサーバーを立ち上げます。先ほどのサーバーが起動したままの場合は、ctrl + c
でサーバーを止めてから再起動してください。
/sample-project
$ node app/index.js
以下と同じ画面が表示されたら成功です。
render
メソッドの使い方については、次のChapter5で詳しく解説します。ここでは、サーバーから変数を受け取れるという点を気に留めておきましょう。
確認:EJSでの変数の扱い方
EJSではや
などの特殊なタグを用いて変数やJavaScript式を扱えます。
を使うことでサーバーからのレスポンスを受け取ることも可能です。
ループで配列の要素を表示する
応用編として、今度は複数のデータを展開してみましょう。
たとえば、li
タグを用いてリスト形式で出力するなど、複数の要素を一括して扱いたい場合があります。そんな時はJavaScriptの「配列」を使うと便利です。
配列であれば要素全体をひとつの変数で管理できます。先ほどの例と同じく、個々の要素はタグで表示可能です。
早速ファイルを編集していきましょう。
index.js
...省略
app.get('/', (req, res, next) => {
res.render('index.ejs', { title: '' })
})
...省略
index.ejs
...省略
<body>
<>
<li></li>
</body>
...省略
今までと同様に、コマンドラインからNode.jsでサーバーを起動します。
/sample-project
$ node app/index.js
画像のように表示されたら成功です。
上記の例では、文字列の配列としてtodos
が使われています。
その直後に各要素を出力していますが、注目すべきはforEach
メソッドです。
forEach
は配列の要素をひとつずつ受け取り、引数に指定した関数の処理を実行します。今回は要素をli
タグに展開する関数を渡したため、画像のように一覧で表示されました。
条件分岐する
EJSではif
を用いた条件分岐も可能です。サーバーから渡された値を参照し、場合に応じて処理を振り分けます。
早速ファイルを編集していきましょう。
index.js
...省略
app.get('/', (req, res, next) => {
res.render('index.ejs', { need: 'おにぎり' })
})
...省略
index.ejs
...省略
<body>
<h1>Todo</h1>
<div>
<p>>/p>
<p></p>
<p></p>
</div>
</body>
...省略
編集後、コマンドラインからNode.jsでサーバーを起動します。
/sample-project
$ node app/index.js
画像の通り表示されたら成功です。値や条件を変更し、何度か挙動を確認してみましょう。
この他にもEJSには様々な記述方法がありますが、どれも直感的で分かりやすいものです。公式サイトのドキュメントに目を通し、ある程度慣れておくといいでしょう。
まとめ
今回はEJSで変数を扱う方法を学びました。EJSを導入すると、このようにJavaScriptの延長線上でHTMLを処理できるようになります。
少しずつ、Webアプリケーション開発に必要なスキルが身についてきました。次のChapterでは、Expressのrender
メソッドについて詳しく見ていきます。

Lesson 3
Chapter 5
変数を扱う(render)
前回のChapterでは、EJSによる変数の扱いについて学習しました。その中でも少し触れましたが、変数はテンプレート内で宣言・代入できるほか、サーバー側のレスポンスとして受け取ることも可能です。
今回は、Expreesのrender
メソッドを使用し、クライアントであるEJSに変数を渡す方法について学習しましょう。
EJSに動的な値を渡す
以下が元となるファイル内容です。変数todo
がテンプレートファイル内で指定されているため、このままでは静的なページしか表示できません。
index.ejs
...省略
<body>
<h1>Todo</h1>
<div>
<p>今日やること:</p>
<p>期限:</p>
</div>
</body>
...省略
そこでExpressのrender
メソッドを修正し、サーバーから変数の値を受け取るように変更しましょう。
renderの使用
それでは具体的に書き換えていきます。テンプレートファイル「index.ejs」内で行っていた変数todo
は削除し、受け取った変数を出力する処理のみ記述します。
index.ejs
...省略
<body>
<h1>Todo</h1>
<div>
<p>今日やること:</p>
<p>期限:</p>
</div>
</body>
...省略
一方、サーバー側である「index.js」は以下の通り書き換えます。
index.js
const express = require('express')
// 追加
const ejs = require('ejs')
const path = require('path')
const app = express()
app.set('views', path.join(__dirname, 'views'))
app.set('view engine', 'ejs')
// ----- 追加・変更 -----
const todo = { title: 'おにぎりを買う', timeLimit: '今日' }
app.get('/', (req, res, next) => {
res.render('index.ejs', { todo: todo })
})
// ---------------------
app.listen(3000, () => {
console.log('Server started on port 3000')
})
成功すれば、画像の通り表示されるはずです。
「index.js」の内容を振り返りましょう。render
メソッドは第1引数に読み込むテンプレートを、第2引数に渡したいデータを指定できます。
今回の例では、第2引数に渡す値としてtitle
の文字列を指定しました。後は先ほど同様に、EJSのタグによって変数が展開される仕組みです。
render
メソッドを介してテンプレートファイルの外からデータを渡せるようになりました。これで動的なWebページが生成できるようになります。
まとめ
Expressのrender
メソッドを用いると、レスポンスとして変数の値を渡すことが可能です。
テンプレートエンジンで扱う変数をサーバー側で生成することで、動的なWebページを構築できます。
基本的にはテンプレート内で変数を宣言せず、このようにサーバー側から受け取るようにしましょう。サーバー側でデータを一元管理することで、保守性の高い設計が実現できます。

Lesson 3
Chapter 6
ルーティングの実装
ここまでのChapterでは、Webページの描画処理(レンダリング)を中心に解説してきました。
ここで実際のWebアプリケーションを考えてみましょう。ユーザーはひとつのURLだけにアクセスするわけではありません。
同じECサイトでも、商品を検索したい時と購入したい時とではリクエストが異なるはずです。サーバーはユーザーの要求に応じて、適切なレスポンスを返す必要があります。
そこで今回のChapterでは、Expressを用いたルーティングの基本を学びましょう。ルーティングの実装そのものは簡単ですが、アプリケーション設計の土台となる大切な箇所です。仕組みを十分に理解した上で進むようにしてください。
ルーティングとは
そもそもWebアプリケーションにおけるルーティングとは、クライアントのリクエストに応じて、サーバー側で処理を切り替えることを指します。
冒頭に挙げた例でいえば、商品の検索時は検索ページ用、購入時は購入ページ用のHTMLを返す必要があるでしょう。
また、クライアントの要求はWebページの表示に留まりません。商品の在庫を更新したい場合など、内部でデータベースとの接続を促すようなリクエストも送信されます。
こうした無数のリクエストを適切に振り分けることが、ルーティングの担う役割です。
Webアプリケーションにおけるルーティングのイメージ
サンプルアプリケーションの作成
さっそくルーティングの実践に移りましょう。今回は簡単なTodoアプリを想定し、一覧ページと詳細ページで表示を切り替えてみます。
プロジェクトの初期設定
まずは任意のディレクトリへ移動し、プロジェクトを新規作成します(ここでは「sample-app」とします)。
npm init
によるプロジェクトの初期化と、npm install
によるExpress・EJSのインストールを行ってください。
コマンドラインからは以下の操作で行えます。
コマンドライン(Windows / Mac / Linux)
$ mkdir sample-app
$ cd sample-app
$ npm init -y
$ npm install express ejs
作成された「package.json」を開き、dependencies
に「Express」と「EJS」のバージョンが記載されていることを確認してください。
続いて「sample-app」直下に「app.js」を作成し、以下のコードを記述します。
app.js
const express = require('express')
const app = express()
app.get('/', (req, res) => {
res.send('Hello world!!')
})
app.listen(3000, (req, res) => {
console.log('Starting server on PORT: 3000')
})
それではサーバーを起動しましょう。「sample-app」配下で以下のコマンドを実行します。
ターミナル
$ node app.js
立ち上がったら「http://localhost:3000」にブラウザからアクセスしましょう。以下の画面が表示されたら成功です。
ルーティングの実装
土台となるアプリケーションの作成ができました。それでは、本題であるルーティングの実装に移りましょう。
ルーティングといっても、最初のひとつはすでに実装してあります。
app.js
app.get('/', (req, res) => {
res.send('Hello world!!')
})
Expressのget
メソッドは、対応するHTTPリクエスト(GET)を処理するものです。他にpost
やput
やdelete
といったメソッドがあり、それぞれHTTPリクエストの種別(POST・PUT・DELETE)に対応しています。
引数にも注目しましょう。get
の第1引数はエンドポイントを表しています。エンドポイントとは、「https://ドメイン名/~」における「~」の部分です。
今回の場合、「http://localhost:3000/」にリクエストすると第2引数のコールバック関数が働き、「Hello world!!」をレスポンスとして返します。
Todoリストのルーティング
それでは、ここに別のルーティングを追加してみましょう。
今回は簡単なTodoリストを想定し、指定のURLにアクセスするとTodoの一覧を返すようなルーティングを実装します。Todoの一覧は「EJS」を使って表示させます。
プロジェクト直下に「views」ディレクトリを作成し、その配下に「index.ejs」ファイルを配置してください。
現在のディレクトリ構成
以下の通り「app.js」を編集し、EJSを参照できるようにします。
app.js
const express = require('express')
const path = require('path')
const app = express()
app.set('views', path.join(__dirname, 'views'))
app.set('view engine', 'ejs')
const todos = ['おにぎりを買う', 'お茶を買う', '散歩に行く']
app.get('/todos', (req, res) => {
res.render('index.ejs', { todos: todos })
})
app.listen(3000, (req, res) => {
console.log('Starting server on PORT: 3000')
})
上記の箇所では、新たに/todos
パスのルーティングを作成しています。レスポンスとして「index.ejs」の内容を描画し、その際に配列todos
を渡す流れです。
描画内容である「index.ejs」も編集しましょう。
index.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<h1>Todo一覧</h1>
<ul>
{ %>
<li></li>
</ul>
</body>
</html>
上記では、Expressで起動したサーバーから配列todos
を受け取り、一覧で表示します。要素の表示には、Chapter4で紹介したforEachを用いています。
ここまでの記述が完了したら、ブラウザから「http://localhost:3000/todos」にアクセスしてみましょう。以下の通り表示されたら成功です。
動的なルーティング
先ほど実装したのは、リクエストURLがつねに固定である場合のルーティングでした。一方で、リクエストURLが変化する場合も考えられます。
たとえば、Todoリストの詳細ページを考えてみましょう。詳細ページはTodoの内容(おにぎりを買う、散歩に行く…)によって異なります。Todoが増える度に/onigiri
や/sanpo
などとルーティングを増やしていたのでは切りがありません。
このような場合、エンドポイントを固定する方法は非現実的です。解決策として、動的なエンドポイントを実装してみましょう。
「app.js」を開き、app.listen
メソッドの上に次の記述を追加します。
app.js
...省略
app.get('/todos/:id', (req, res) => {
const id = req.params.id
const todo = {
id: id,
title: todos[id - 1],
}
res.render('detail.ejs', { todo: todo })
})
...省略
動的なエンドポイントを受け取るには、コールバック関数の第1引数を使用します。この引数にはリクエスト情報が格納されており、エンドポイントの:
の後に続く入力を受け取ることが可能です。。
今回の例では、配列todos
のインデックスとしてidを取得し、対応する要素を返却するようにしています。
それでは詳細を受け取るテンプレートも作成していきましょう。「views」配下に「detail.ejs」ファイルを用意してください。
detail.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<h1>Todo詳細</h1>
<p>id: </p>
<p>タイトル: </p>
</body>
</html>
ブラウザから「http://localhost:3000/todos/1」にアクセスしてみましょう。以下の通り表示されたら成功です。
Todo詳細
まとめ
今回はルーティングについて解説しました。一見すると複雑なルーティングですが、仕組みが分かれば難しいことはありません。
フレームワークとしてExpressを用いると、最小限の記述で安全なルーティングが実現可能です。
今回は「GET」リクエストのみ扱いましたが、後のLessonでは「POST」など他のリクエストのルーティングも実装します。複雑な動的ルーティングに関しても、その際に学び直すことにしましょう。

Lesson 3
Chapter 7
fsモジュールで静的ファイルを提供する
今回は、fs
モジュールを使った静的ファイルの扱い方を学びましょう。
ここでの「静的ファイル」とは、Webアプリケーションが処理するコンテンツのうち、リクエスト時に内容が生成・更新されないものを指します。具体的には、画像やCSS、JavaScriptなど、主にデザインやレイアウトの目的で使用されるファイルです。
fsモジュールとは
fsモジュールは、Node.jsでファイルを操作するための公式モジュールです。具体的には、ファイルの読み書きや新規作成、削除などが行えます。
一般的なフロントエンドの実装でファイルを操作する機会は少ないかもしれません。一方、サーバーサイドの実装では静的ファイルを扱う機会が多くあります。
基本的なファイル操作であれば、fsモジュールをインポートするだけで十分に事足ります。後述するように、同期・非同期処理のそれぞれに対応できる点も特徴です。
fsモジュールを使用する
それでは実践に移りましょう。前回のChapterで使用したプロジェクトを引き続き使用します。
最初に、fsモジュールで読み書きするためのテキストファイルを準備してください。
プロジェクト直下に「public」というディレクトリを作成し、その配下に「sample.txt」というファイルを追加します。
「sample.txt」には適当な文字列(例「サンプルテキストだよ」)を記述しましょう。
以下はコマンドラインで作成する場合の例です。
~/sample-app(Windows)
$ mkdir public
$ cd public
$ New-item sample.txt
$ echo "サンプルテキストだよ" > sample.txt
~/sample-app(Mac / Linux)
$ mkdir public
$ cd public
$ touch sample.txt
$ echo "サンプルテキストだよ" > sample.txt
現在のディレクトリ構成
ファイルの読み込み
静的ファイルを読み込むには、fs.readFile
メソッドを使用します。形式は以下の通りです。
ファイルの読み込み
fs.readFile('ファイルパス', '文字コード', コールバック関数)
それでは、「app.js」に記述していきましょう。/todos
に対してリクエストがあると、sample.txt
の内容をコンソールに表示させるようにします。
第3引数であるコールバック関数に着目してください。引数のdata
を介してファイルの内容を取得し、console.log
で出力しています。
app.js
const express = require('express')
const path = require('path')
// 追記
const fs = require('fs')
const app = express()
app.set('views', path.join(__dirname, 'views'))
app.set('view engine', 'ejs')
const todos = ['おにぎりを買う', 'お茶を買う', '散歩に行く']
app.get('/todos', (req, res) => {
// 追記
fs.readFile('./public/sample.txt', 'utf-8', (err, data) => {
console.log(data)
})
res.render('index.ejs', { todos: todos })
})
app.get('/todos/:id', (req, res) => {
const id = req.params.id - 1
const todo = {
id: id + 1,
title: todos[id],
}
res.render('detail.ejs', { todo: todo })
})
app.listen(3000, (req, res) => {
console.log('Starting server on PORT: 3000')
})
編集が完了したら、コマンドライン上でnode app.js
を入力しサーバーを起動しましょう。
ブラウザから「http://localhost:3000/todos/」にアクセスします。コマンドライン上に画像のような文字列が表示されたら、静的ファイルの読み込みは成功です。
コンソール
ファイルの書き込み
今度はファイルの書き込みを実践しましょう。こちらはappendFile
メソッドを使用します。呼び出しの形式は以下の通りです。
ファイルの書き込み
fs.appendFile('相対パス', '文字コード', コールバック関数)
appendFile
メソッドを使うと、ファイルが存在しない場合に作成まで行なってくれます。
また、第3引数にコールバック関数を渡し、エラー処理を行うことも可能です。今回は特に追加の処理を必要としないため、第3引数は指定しません。
以下の通り「app.js」を更新します。
index.html
...省略
app.get('/todos/:id', (req, res) => {
const id = req.params.id - 1
const todo = {
id: id + 1,
title: todos[id],
}
// 追記
fs.appendFile(
'./public/detail.txt',
`id: ${todo.id} タイトル: ${todo.title}\n`
)
res.render('detail.ejs', { todo: todo })
})
...省略
試しに「http://localhost:3000/todos/1」に何回かアクセスしてみましょう。「detail.txt」に改行区切りでテキストが追加されていきます。
「detail.txt」を開き、アクセスした回数分の項目が書き込まれていれば成功です。
detail.txt
id: 1 タイトル: おにぎりを買う
id: 1 タイトル: おにぎりを買う
id: 1 タイトル: おにぎりを買う
readFileSyncとreadFileの違い
今回はreadFile
やappendFile
メソッドを用いてファイルの読み書きを実装しました。ところで、fsモジュールにはよく似た名前のreadFileSync
やappendFileSync
メソッドが存在します。
どちらもファイルの読み書きを行う点では同じです。しかし、末尾にSync
が付いたメソッドは「同期処理」で実行される点が異なります。
以下の表は非同期処理・同期処理の対応関係をまとめたものです。
メソッドの機能 | 非同期処理 | 同期処理 |
---|---|---|
ファイルの読み取り | readFile | readFileSync |
ファイルの書き込み | appendFile | appendFileSync |
「同期」や「非同期」と聞いて、思わず身構えた方も多いでしょう。二つのメソッドは具体的にどのような形で処理を実行するのでしょうか。
ここからは、JavaScriptの同期・非同期処理について見ていきます。
同期処理・非同期処理の違い
結論から述べると、同期処理と非同期処理には以下の違いがあります。
説明 | |
---|---|
同期処理 | プログラムの順序に従って処理が実行される。 |
非同期処理 | ある処理の終了を待たず、プログラムの次の処理が実行される。 |
上記のうち、直感的に分かりやすいのは同期処理です。通常のプログラミングにおいて、関数はソースコードに書かれた順に呼び出されます。func1
の処理が完全に終わらない限り、次に記述されたfunc2
が呼び出されることは決してありません。
しかし、非同期処理の場合は違います。func1
の終了を待たずに次のfunc2
が実行されるため、ソースコードの記述順と処理が終わる順序は必ずしも一致しません。
一見して分かるように、非同期処理は取り扱いが大変です。処理終了のタイミングが未定であるため、エラー処理にも特別な構文を必要とします。
Promiseによるエラー処理
Lesson6-3「Promiseによるエラーハンドリング」では、Promise文を使ったエラーハンドリングについて詳しく学びます。
にもかかわらず、JavaScriptに非同期処理の仕組みが実装されているのは、それが時間のかかる処理に適しているためです。
Webアプリケーションでは、HTTP通信やファイルの読み書きなど、高負荷の処理を実装することが多くあります。そんなとき、通常の同期処理だと高負荷の処理を行っている間は別の処理が呼び出せません。結果として、プログラム全体の進行を止める可能性があります。
その点、非同期処理であれば、ある処理に時間がかかっていたとしても後続の処理を呼び出せます。擬似的な並列処理が可能となり、プログラム全体の進行を妨げません。
JavaScriptの非同期処理は、初心者がつまづきやすいポイントです。今すべてを理解する必要はありませんが、実践を通して把握に努めてください。。
まとめ
今回は静的ファイルを操作するためのfsモジュールを解説しました。
readFile
とappendFile
はファイルの基本操作であるため、ここで使いこなせるようにしておきましょう。
話の本筋ではありませんが、同期処理・非同期処理の違いに関してもよく学び直すようにしてください。
次のChapterでは、引き続きfsモジュールを使用し、サーバーから画像を提供する仕組みを実装します。

Lesson 3
Chapter 8
アセットの提供
前回のChapterでは、fsモジュールによる静的ファイルの取り扱いについて学びました。
fsモジュールで操作できるのは、何もテキストファイルだけではありません。画像も静的ファイルである以上、fsモジュールで操作することが可能です。
今回のChapterでは、同じfs.readFile
メソッドによる画像の読み込み方法を学びます。
fs.readFileで画像を提供する
既出ですが、ファイルを読み込むためのfs.readFile
は、以下の形式で呼び出します。
fs.readFile
fs.readFile('ファイルの相対パス', コールバック関数)
第1引数にはテキストファイルだけでなく、画像ファイルのパスも指定できます。第2引数のコールバック関数を通してエラー処理を行える点も変わりません。
それでは早速コードを書いていきましょう。
ルーティングの実装
まずは画像を提供するためのルーティングをサーバー側に実装します。以下の通り、動的なエンドポイントとして/image/:id
を設定しましょう。
app.js
app.get('/image/:id', (req, res) => {
// 処理
})
画像ファイルの準備
続いて、提供する画像ファイルを準備しましょう。
「public」ディレクトリ直下に「images」ディレクトリを作成し、その配下に画像ファイルを3枚用意します。
画像素材の選定
画像はPNG形式であれば何でも構いません。適当な画像ファイルが手元にないときは、無料素材サイトなどを利用しましょう。
それぞれ以下の名前で「images」配下に保存してください。
- onigiri.png
- tea.png
- sanpo.png
以下のディレクトリ構成となっていれば準備完了です。
画像をレスポンスとして返却する
それでは、画像をExpressサーバーから返していきましょう。
以下の通り「app.js」を編集します。コマンドライン上でnode app.js
と入力し、サーバーを立ち上げてください。
app.js
...省略
app.get('/image/:id', (req, res) => {
const id = req.params.id
let path = './public/images/'
if (Number(id) === 1) {
path += 'onigiri.png'
} else if (Number(id) === 2) {
path += 'tea.png'
} else {
path += 'sanpo.png'
}
fs.readFile(path, (err, data) => {
res.type('png')
res.send(data)
})
})
...省略
それでは「http://localhost:3000/image/1」にアクセスしてみましょう。「onigiri.png」に設定した画像が表示されたら成功です。
続けて「http://localhost:3000/image/2」「http://localhost:3000/image/3」にアクセスし、画像の変化を確認してください。
ここでは、本章のChapter6で紹介した動的ルートマッチングを使用しています。エンドポイントに含まれる:id
の値を参照し、対応する画像をレスポンスとして返却する仕組みです。
ポイントとして、URLパラメーターはすべて文字列(String)で送信されます。:id
の値を取り出すためには数字(Number)に変換しなければなりません。
また、レスポンスを返却する前にres.type
メソッドを呼び出し、画像形式(ここではPNG)を指定する必要があります。
まとめ
今回はアセット(画像)の提供を行いました。fs.readFile
を使用することで、テキストだけでなく画像ファイルも操作できます。
画像をレスポンスとして返却する場合は、必ずファイル形式を指定するようにしてください。
次のChapterでは、Lessonの締めくくりとしてコードを共通化する方法について学びます。

Lesson 3
Chapter 9
部品の共通化
Lesson3では、ExpressとEJSによるWebページ作成の基本を解説してきました。
各パッケージの導入に始まり、ページの描画やルーティング、ファイル操作などを幅広く学べたことでしょう。
Lessonの最後となる今回は、共通パーツの切り分け方法について学習します。
開発の効率を進める上で、コードの共通化はとても重要です。ソースコードの記述量を減らせれば、エンジニアにかかる負担も減ります。プログラムの見通しが改善され、不用意なバグを避けることにもつながるでしょう。
開発の規模が大きくなればなるほど、この共通化のノウハウが求められるようになります。ぜひ学び始めの段階から意識するようにしてください。
部品を共通化するための準備
ここまでの実装ではコード全体の記述量が少なく、あまり共通化の恩恵を得ることができません。
そこで事前準備として、切り出すための部品を増やすことから始めましょう。
現状の実装では、全体ページとして「index.ejs」、詳細ページとして「detail.ejs」が作成されています。この二つのファイルにheader
とfooter
タグを追記してください。
index.ejs
...省略
<body>
<header>
<h1>Todoリスト</h1>
</header>
<main>
<h2>一覧</h2>
<ul>
{ %>
<li></li>
</ul>
</main>
<footer>フッター</footer>
</body>
...省略
detail.ejs
...省略
<body>
<header>
<h1>Todoリスト</h1>
</header>
<main>
<h2>詳細</h2>
<p>id: </p>
<p>タイトル: </p>
</main>
<footer>フッター</footer>
</body>
...省略
headerもfooterも簡易的な内容ですが、学習目的としては十分です。ブラウザから「http://localhost/todos」にアクアスし、実際に適用されているか確認してみましょう。
http://localhost:3000/todos
http://localhost:3000/todos/1
ディレクトリの作成
続いて、共通部品を置くためのディレクトリを作成します。
プロジェクト内の「views」配下に「_share」ディレクトリを作成しましょう。部品のディレクトリであることを示すため「_
」を先頭につけています。
ファイルの作成
あわせて、共通化するファイルを先に作成しておきましょう。「_share」配下に以下の4ファイルを作成してください。
- head.ejs
- header.ejs
- pageTitle.ejs
- footer.ejs
views
以上で事前準備は完了です。ここから共通パーツを抜き出していきましょう。
EJSのテンプレートを共通化する
EJSのテンプレートのうち、共通化できる部品を別ファイルに抜き出します。
Lesson1-4「EJSとは」でも少し触れましたが、EJSのinclude
関数を用いるとファイル間での呼び出しが可能です。
このinclude
を活用し、4つの共通部品を抜き出していきましょう。
共通化:headタグ
各ページのheadタグは同一の構成になることが多く、真っ先に共通化が検討されます。
事前準備で作成した「_share/head.ejs」に以下を記述していきましょう。
head.ejs
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Todo</title>
</head>
「head.ejs」の部品を呼び出すためには、「index.ejs」を編集して以下の通り記述します。
index.ejs
<html lang="en">
<body>...省略
同様に、「detail.ejs」からも「head.ejs」のincludeを行なってください。
画面で実際に確認してみましょう。ブラウザから「http://localhost:3000/todos」にアクセスしてみてください。
head
タグの内容は画面に表示されないため、きちんと適用されているか確かめるには各ブラウザのデベロッパーツールを使うと便利です。
参考:Google Chrome デベロッパーツールによる確認方法
- 「http://localhost:3000/todos」にアクセスする
- 画面を右クリックして「検証」をクリックする
- メニューの中から「Element」を選択する(HTML構造が表示される)
head
タグが適用されているか確認する。
headタグの適用確認
共通化:header・footerタグ
続いてheader
タグ(注:head
タグとは異なります)を共通部品として切り出します。切り出した内容は「header.ejs」に記述していきましょう。
header.ejs
<header>
<h1>Todoリスト</h1>
</header>
また、footer
も分割します。こちらの内容は「footer.ejs」に記述してください。
footer.ejs
<footer>フッター</footer>
二つの部品を呼び出すため、「index.ejs」と「detail.ejs」に以下の変更を適用します。
index.ejs
<!DOCTYPE html>
<html lang="en">
<body>
<main>
<h2>Todo一覧</h2>
<ul>
{ %>
<li></li>
</ul>
</main>
</body>
</html>
detail.ejs
<!DOCTYPE html>
<html lang="en">
<body>
<main>
<h2>詳細</h2>
<p>id: </p>
<p>タイトル: </p>
</main>
</body>
</html>
先ほどと同様に、ブラウザから確認して見ましょう。タグが正しく適用されていれば成功です。
共通化:pageTitle
最後に、h2
タグの部分を共通化しましょう。
ここでの問題として、「index.ejs」と「detail.ejs」ではh2タグの文言が異なる点が挙げられます。(前者は「Todo一覧」であるのに対し後者は「詳細」)。
このような場合、include時に変数を渡すことで値を変更できます。
index.ejs
include('相対パス', 引数)
上記の通り、変数を渡す時は第2引数を利用します。
まずは共通化ファイル「pageTitle.ejs」の作成からです。
pageTitle.ejs
<h2></h2>
呼び出すためには、「index.ejs」と「detail.ejs」で以下のように記述します。それぞれtitle
の値が異なる点に注目してください。
index.ejs
...省略
<main>
<ul>
...省略
detail.ejs
...省略
<main>
<ul>
...省略
以上で部品の共通化が完了しました。ブラウザで「http://localhost:3000/todos」にアクセスし、画面を確認してみましょう。
正しくページが表示されていれば成功です。
http://localhost:3000/todos
http://localhost:3000/todos/1
まとめ
今回はEJSのinclude
機能を使用し、部品の共通化を行いました。
Webアプリケーションの開発では、このように同一の記述を使い回す場面が少なくありません。
統一したスタイルを適用するときや、今回のようにheader・footerタグを使うときなど、部品の共通化により得られるメリットは多大です。
また、部品の共通化は「コンポーネント指向」の考え方にも関わってきます。コンポーネント志向とは、アプリケーションを小さな部品に分割し、各部を組み合わせて開発を進める手法です。
「React」や「Vue.js」といったJavaScriptのフレームワークも、このコンポーネント指向を設計思想としています。皆さんがWebアプリケーション開発に携わる上で、避けて通れない概念といえるでしょう。
