クモのようにコツコツと

フロントエンドエンジニア イイダリョウの技術ブログ。略称「クモコツ」

【Express】静的HTMLファイルの表示(res.sendFile()、express.static())

Expressの続きです。前回はExpressをインストールしてハローワールドのテキストを表示しました。今回はHTMLを表示してみたく。res.send()でHTMLタグは表示。さらにres.sendFile()でHTMLファイル、express.static()で静的サイト全体を表示します。それではいきましょう!

【目次】

前回記事
※参考:Express事始め(インストール〜ハローワールドまで) - クモのようにコツコツと

※Node.js / Expressを習得するためにやったことまとめ qiita.com

前回のおさらい

テキストを表示している。日本語も文字化けしない! f:id:idr_zz:20200410072518j:plain

index.jsのコード

const express = require('express');
const app = express();

app.get('/', (req, res) => {
    res.send('こんにちは、えくすぷれす。');
});

app.listen(3000, () => {
    console.log('Start server port:3000');
});

Node.jsよりもシンプル!

詳細は前回記事を参照
※参考:Express事始め(インストール〜ハローワールドまで) - クモのようにコツコツと

res.send()メソッドでHTMLコードを表示する

res.send()の引数をHTMLタグにする

前回まで参考にしていた掌田さんの「Node.js超入門」ではこの後、HTMLテンプレートエンジンのEJSを導入する。

自分としてはその前にNode.jsの時にやったように静的なHTMLファイルを表示してみたい。

※参考:【Node.js】ルーティング設定で複数ページを表示する - クモのようにコツコツと

方法を調べたところ、いくつかの方法があった。まずはres.send()のハローワールド部分を変更する。

res.send()
色んなレスポンスが返せる汎用的なメソッド。

※参考:Express のレスポンス関連メソッド「res.end()」「res.send()」「res.json()」の違い - Corredor

Express公式サイトでもこの中にHTMLのタグを入れている。

※参考:Express 5.x - API Reference

res.send()の引数にh1タグとpタグを入れてみる

app.get('/', (req, res) => {
    res.send('<h1>ExpressでHTML</h1><p>本文です。本文です。本文ですったら本文です。</p>');
});

動作確認

index.jsを実行!

node index.js

ブラウザでローカルホストのポート3000を開く

http://localhost:3000/

おお、タグとして認識された! f:id:idr_zz:20200416185711j:plain

改行はエラー

ちなみにres.send()の中に改行を入れたらエラーになった!

app.get('/', (req, res) => {
    res.send(
        '<h1>ExpressでHTML</h1>
        <p>本文です。本文です。本文ですったら本文です。</p>'
    ); // この書き方だとエラーになる!
});

これはNode.jsのときと同じ挙動。

※参考:【Node.js】ハローワールドの打ち替え(ポート番号、日本語化、HTMLタグ化) - クモのようにコツコツと

htmlファイル一式を追加

次はhtmlファイルを読み込んで表示したい。まずファイル一式を作る。

ファイル構成

Node.jsの時に追加したような静的なhtmlファイル一式をベースにする。

※参考:【Node.js】ルーティング設定で複数ページを表示する - クモのようにコツコツと

このようなファイル構成になる

express_test
├node_modules(中身は省略)
├package.json
├package-lock.json
├public
│├css
││└style.css
│├js
││└script.js
│├index.html
│├other.html
│└sub
│ └index.html
└index.js

Node.jsのときはファイル一式を「html」というフォルダだったが、今回は「public」というフォルダ名にした。

HTMLファイル(TOP)

index.html

<!DOCTYPE HTML>
<html>
    <head>
        <meta charset="utf-8">
        <title>こんにちは、えくすぷれす。</title>
        <link rel="stylesheet" href="css/style.css">
        <script src="js/script.js"></script>
    </head>
<body>
    <section>
        <h1>こんにちは、えくすぷれす。</h1>
        <p>ExpressでHTMLタグを作れるのかテストですと。</p>
        <p><a href="other.html">別ページへ</a></p>
        <p><a href="sub/">下層ページへ</a></p>
        <p><a href="hoge.html">架空のページへ</a></p>
    </section>
</body>
</html>

HTMLファイル(別ページ)

other.html

<!DOCTYPE HTML>
<html>
    <head>
        <meta charset="utf-8">
        <title>別のぺえじ</title>
        <link rel="stylesheet" href="css/style.css">
        <script src="js/script.js"></script>
    </head>
<body>
    <section>
        <h1>ここは別のページです</h1>
        <p>Expressで複数ページを表示するテスト。</p>
        <p><a href="/index.html">TOPページへ</a></p>
    </section>
</body>
</html>

HTMLファイル(下層ページ)

sub/index.html

<!DOCTYPE HTML>
<html>
    <head>
        <meta charset="utf-8">
        <title>下層ぺえじ</title>
        <link rel="stylesheet" href="../css/style.css">
        <script src="../js/script.js"></script>
    </head>
<body>
    <section>
        <h1>ここは下層ページです</h1>
        <p>Node.jsで複数ページを作るテスト。</p>
        <p><a href="../index.html">TOPページへ</a></p>
    </section>
</body>
</html>

CSSファイル

css/style.css

h1 {
    color: red;
}

h1タグを赤字にする。

JSファイル

js/script.js

alert("こんにちは、えくすぷれす!");

アラートを立ち上げる。

基本的にはNode.jsの時ととほぼ同じ内容。多少テキストをExpress向けに打ち直したくらい。

※参考:【Node.js】ルーティング設定で複数ページを表示する - クモのようにコツコツと

res.sendFile()メソッドでhtmlファイルを表示

res.sendFile()メソッドとは

まず試したのはres.sendFile()メソッド。Express公式サイトのFAQページによると

どのようにしてプレーン HTML をレンダリングするのですか?

レンダリングしません。res.render() 関数で HTML を「レンダリング」する必要はありません。 特定のファイルがある場合は、res.sendFile() 関数を使用します。 ディレクトリーから多数の資産を提供する場合は、express.static() ミドルウェア関数を使用します。

※参考:Express に関する FAQ

HTMLのレンダリングは必要ないと。そして特定のファイルを読み込む場合はres.sendFile()メソッドを利用するとのこと。(もう一つのexpress.static()メソッドについては後述)

Express公式サイトのres.sendFile()メソッド解説

※参考:Express 4.x - API リファレンス

公式サイトでは引数にコールバック関数があり、その中でif文でエラー時の挙動が書いてある。

もう少しシンプルに第一引数にパスを書くだけでもいいようだ。

res.sendFile(__dirname + '/index.html');

※参考:接近戦に強いExpress入門 ~Webサーバー、テンプレートエンジン、セッション、BASIC認証~ - Qiita

__dirnameはルートディレクトリ

__dirnameとはなんぞや

__dirname には、現在実行中のソースコードが格納されているディレクトリパスが格納されています。

※参考:node.js で絶対パスや相対パスを取得する方法 npm __dirname · GitHub

ふむふむ、ルートのディレクトリになるようだ。

res.send()メソッドからres.sendFile()メソッドに書き換え

res.send()だった部分をres.sendFile()に変更する。

app.get('/', (req, res) => {
    res.sendFile(__dirname + '/public/index.html');
}); 

ルートの__dirnameから/public/ディレクトリのindex.htmlを読み込む。

動作確認

先程のサーバは一旦閉じる(Ctrl + C)。

index.jsを実行!

node index.js

ブラウザを開く

http://localhost:3000/

おお、ページが表示された! f:id:idr_zz:20200416194749j:plain

しかしながら…

  • アラートが立ち上がらないのでJSが認識されていない
  • 見出しの色が変わってないのでCSSが認識されていない

また、別のページ移動しようとすると… f:id:idr_zz:20200416194918j:plain ページが見つからないと…

やはりres.sendFile()メソッドで指定したindex.htmlファイル単体しか読み込まれていない。

express.static()メソッドでファイル一式を読み込む

express.static()メソッドとは

そこで先程のExpress公式サイトのFAQに出てきたもう一つの方法を使うことになる。

ディレクトリーから多数の資産を提供する場合は、express.static() ミドルウェア関数を使用します。

※参考:Express に関する FAQ

うむ、多数の資産!提供してほしい!!

express.static()の書き方はシンプル。

app.use(express.static('public'));
  • app.use()メソッドの引数に入っている
  • express.static()メソッドの引数はフォルダ名

静的アセットファイルを格納しているディレクトリーの名前を express.static ミドルウェア関数に渡して、ファイルの直接提供を開始します。例えば、public というディレクトリー内のイメージ、CSS ファイル、JavaScript ファイルを提供するには、次のコードを使用します。

静的なCSSやJSファイルなどを格納してexpress.static()で読み込むと。

※参考:Express での静的ファイルの提供

ミドルウェアとは(今回は構築していない)

ミドルウェアについては以前も調べた。

複数のURLパスへのリクエストに対して行う処理をミドルウェアというまとまりにして、リクエストレスポンスサイクルの中間に配置する

※参考:ExpressとJSフレームワーク(React、Vue、Angularなど)との関係について調べたこと - クモのようにコツコツと

しかし今回はミドルウェアは構築していないので静的なHTMLファイル一式も全部この中に入れてみよう。

app.use()メソッドとは

ちなみにapp.use()とは?

app.use([path,] callback [, callback...])
Mounts the specified middleware function or functions at the specified path: the middleware function is executed when the base of the requested path matches path.

指定されたミドルウェア機能を指定されたパスにマウントします。ミドルウェア機能は、要求されたパスのベースがパスと一致したときに実行されます。

ミドルウェアと指定したパスの間でパスが一致した時に処理を実行するメソッドのようだ。

動作確認

それでは挙動確認してみる。先程のサーバは一旦閉じる(Ctrl + C)。

index.jsを実行!

node index.js

ブラウザを開く

http://localhost:3000/

お、アラートが立ち上がった! f:id:idr_zz:20200416200748j:plain JSが動いている証拠!(以後、ページ移動のたびに立ち上がるので省略

続いてTopページが表示される f:id:idr_zz:20200416200839j:plain 見出しが赤くなっている。CSSが動いている証拠!

別ページに行ってみる。 f:id:idr_zz:20200416200921j:plain 表示された!

下層ページに行ってみる。 f:id:idr_zz:20200416201004j:plain 表示された!

架空ページは… f:id:idr_zz:20200416201057j:plain そんなページは有馬千円。

どれも想定通りの動き!

es.sendFile()を削除(コメントアウト)してみる

index.js

app.get('/', (req, res) => {
    // es.sendFile(__dirname + '/public/index.html');
}); 

ちなみに試しにes.sendFile()メソッドを削除(コメントアウト)してみたが、問題なくページが表示された!

express.static()の1行があれば静的サイトは表示されるようだ!

app.use(express.static('public'));

Expressのコード全体

最後にindex.jsのコード全体。

const express = require('express');
const app = express();

app.use(express.static('public'));

app.get('/', (req, res) => {
    // es.sendFile(__dirname + '/public/index.html');
}); 

app.listen(3000, () => {
    console.log('Start server port:3000');
});

最後に

ということでExpressでHTMLコードを表示しました。Node.jsのときはファイルごとにルーティング設定をしていましたが、Expressはexpress.static()でディレクトリ名を指定するだけなのでとても楽でした!

HTMLテンプレートエンジンなどのミドルウェアでアプリを構築する場合も、CSS、JS、画像などの静的なファイルexpress.static()で読み込むようです。

次回からはミドルウェア編ということでHTMLテンプレートエンジンのEJSを取り入れてみようと思います。それではまた!


※Node.js / Expressを習得するためにやったことまとめ qiita.com