クモのようにコツコツと

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

【Node.js】ルーティング設定でCSS、JSファイルを読み込む

Node.jsの続きです。前回はfsモジュールを使ってHTMLファイルを表示しました。今回はここからCSS、JSファイルを読み込みたく。そのためにはルーティング設定が必要でした。それではいきましょう!

【目次】

前回記事
※参考:【Node.js】fsモジュールでHTMLファイルを表示する - クモのようにコツコツと

Node.js / Expressを習得するためにやったことまとめ(随時更新)
qiita.com

CSSとJSのファイルをリンク

前回、fnモジュールを使ってHTMLファイルを表示した。

f:id:idr_zz:20200312065429j:plain

HTMLコード

<!DOCTYPE HTML>
<html>
    <head>
        <meta charset="utf-8">
        <title>こんにちは、のおど・じぇいえす。</title>
    </head>
<body>
    <section>
        <h1>こんにちは、のおど・じぇいえす。</h1>
        <p>Node.jsでHTMLタグを作れるのかテストですと。</p>
    </section>
</body>
</html>

JSコード

const http = require('http');
const fs = require('fs');

const hostname = '127.0.0.1';
const port = 3000;

const server = http.createServer((req, res) => {
  fs.readFile('./html/index.html', 'UTF-8',
  (error, data) => {
    res.writeHead(200, {'Content-Type': 'text/html'});
    res.write(data);
    res.end();
  });
});

server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});

詳細は前回記事を参照。

※参考:【Node.js】fsモジュールでHTMLファイルを表示する - クモのようにコツコツと

今回も掌田さんの「Node.js超入門」を参考に進める。

Node.js超入門[第2版]

Node.js超入門[第2版]

書籍では次にHTMLテンプレートエンジンのEJSに入るが、それは既に体験済みなので、その先のルーティング設定をやってみる。

CSS、JSファイルを読み込む

HTMLファイルだけだと寂しいのでCSSやJSのファイルを読み込んでみたい。

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でHTMLタグを作れるのかテストですと。</p>
    </section>
</body>
</html>
  • headタグの中でcssファイルとjsファイルを読み込む

CSSファイルを作る。

CSSコード

h1 {
    color: red;
}

ほんとに簡易な内容。h1タグを赤くするだけ。

JSファイルも作る。

alert("こんにちは、のおど・じぇいえす!");

JSも簡単に。アラートでハローワールド。

Node.jsサーバを起動(ファイルが読み込まれない!)

この状態でターミナルを立ち上げでcdコマンドでフォルダに移動。

cd (ファイルパス)/node_test

Node.jsサーバを立ち上げる!

node node_test.js

サーバが起動するとターミナルにコンソールログが帰ってくる。

Server running at http://127.0.0.1:3000/

ブラウザでURLを開くが…

http://127.0.0.1:3000/

挙動は変わらない。 f:id:idr_zz:20200312065429j:plain

CSSスタイルが当たってないしアラートも立ち上がらない。index.htmlしか読み込まれていないということだ。

ルーティング設定

CSS、JSファイルを読み込ませるには「ルーティング設定」をする必要がある。

ネットワーク上で行われる道案内であり
通信において「あ~、君はそこに行きたいのか~。じゃあ、取りあえずそっちの道を行きなよ」と、データさんの行くべき道を示してくれる仕組みのこと
です。

※参考:https://wa3.i-3-i.info/word1498.html

const url = require('url');

まず、require()メソッドでurlオブジェクトを読み込む。

const server = http.createServer(RouteSetting);

変数serverhttp.createServe()の中の処理は長くなるので外部関数RouteSettingにする。

RouteSettingでルーティングの設定

function RouteSetting(req, res) {
  const url_parts = url.parse(req.url);
  switch (url_parts.pathname) {
    case '/':
    // '/'にアクセスした時の処理
      break;
  
    case '/css/style.css':
    // cssファイルにアクセスした時の処理
    break;

    case '/js/script.js':
    // jsファイルにアクセスした時の処理
    break;
  }
}
  • 関数RouteSetting()を定義。引数は左からリクエストreq、レスポンスres
  • 変数url_partsurl.parse()メソッドでリクエストのURLをオブジェクトに変換する
  • switch文の条件はurl_partspathname
    index.html、cssファイル、jsファイルにアクセスがあった時の設定を書く

パースとはJSONをオブジェクト形式に変換すること。

※参考:REST APIとは何かを調べまくったらようやくイメージができてきたのでまとめた - クモのようにコツコツと

Swich文はif文のような分岐の書き方。並列条件でif文と違って書き順の影響を受けない。

※参考:【JSの基本-後編】書ける前に読む!HTML、CSS、JSの書式-5 - クモのようにコツコツと


※2021/04/01追記

レンさんよりコメントをいただきまして、今のNode.jsのバージョンではurl.parse()ではなくnew URL()で書く方法が推奨されているようです。(脆弱性のアラートが出る)

※参考:[Node.js] 新旧APIでのURLパースの違い - Qiita

ルーティング設定を反映

前回のコードにルーティング設定を追加していく。

JSコード

const http = require('http');
const fs = require('fs');
const url = require('url');

最初にrequire()httpfsurlを読み込む。変数名も同じ。

const indexPage = fs.readFileSync('./html/index.html', 'UTF-8');
const styleCss = fs.readFileSync('./html/css/style.css', 'UTF-8');
const scriptJs = fs.readFileSync('./html/js/script.js', 'UTF-8');

次にfs.readFileSync()でhtml、css、jsファイルを読み込む。変数名はindexPagestyleCssscriptJs

前回のreadFile()メソッドだとうまく動かず 、readFileSync()メソッドで読み込む必要があった。2つの違いは非同期処理か同期処理か。

  • readFile():非同期処理
  • readFileSync():同期処理

まよったらreadFileSyncを使う
Node.jsをはじめたばかりで「同期?非同期?」な人は、とりあえず、fs.readFileSyncを使うのが無難です。

とのこと!

※参考:https://www.tech-tech.xyz/nodejs-readfile-readfilesync.html

そのあとはhttp.createServer()の中をRouteSetting()に外部関数化する以外は変わらない。

const hostname = '127.0.0.1';
const port = 3000;

const server = http.createServer(RouteSetting);

server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});

swich文でURLとファイルをルーティング

で、本丸。RouteSetting()関数の定義!URLとファイルと紐付けていく。

function RouteSetting(req, res) {
  const url_parts = url.parse(req.url);
  switch (url_parts.pathname) {

以下、swich文の中身。caseを追加していく。

一つ目はHTMLファイルの条件。

    case '/':
    case '/index.html':
      res.writeHead(200, {'Content-Type': 'text/html'});
      res.write(indexPage);
      res.end();
      break;

今回初めて知ったんだが、caseを二つ連ねると処理に対して条件を複数設定できるようだ!

※参考:複数のcaseで同じ処理を実行 - 条件分岐 - C言語 入門

/またはindex.htmlならば、という条件にした。

res.writeHead()Content-Typeext/html

res.write()の引数はindexPageのhtmlファイル。

次はCSSファイルの設定。

    case '/css/style.css':
    res.writeHead(200, {'Content-Type': 'text/css'});
    res.write(styleCss);
    res.end();
    break;

style.cssならばという条件でres.writeHead()Content-Typetext/cssにする。

※参考:node.js css読み込み | ゴンの気まぐれなるままに

res.write()の引数はstyleCssのcssファイル。

三つ目はjsファイル。

    case '/js/script.js':
      res.writeHead(200, {'Content-Type': 'text/plain'});
      res.write(scriptJs);
      res.end();
      break;

script.jsならば、という条件でres.writeHead()Content-Typetext/plain。「js」じゃないんだな。

※参考:node.js html内のjsファイルの読み込み | ゴンの気まぐれなるままに

res.write()の引数はscriptJsのjsファイル。

最後はdefaultelse(さもなくば)的な設定。

    default:
      res.writeHead(200, {'Content-Type': 'text/plain'});
      res.end('お探しのページは見つかりません。');
      break;
  }
}

上記のどれにも当てはまらない場合は「お探しのページは見つかりません。」というテキストを表示。


(2020/08/15追記)

上記の書き方だと日本語が文字化けになったため、下記の記事で書き換えてみた。

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

サーバを起動(CSS、JSファイル読み込み成功!)

リベンジでサーバ起動!

node node_test.js

起動成功!

http://127.0.0.1:3000/

ブラウザを開くと、お、アラートが立ち上がった! f:id:idr_zz:20200330202233j:plain

アラートを閉じると、見出しが赤くなってる! f:id:idr_zz:20200330202257j:plain

コード全体

最終的にこうなった。

const http = require('http');
const fs = require('fs');
const url = require('url');

const indexPage = fs.readFileSync('./html/index.html', 'UTF-8');
const otherPage = fs.readFileSync('./html/other.html', 'UTF-8');
const styleCss = fs.readFileSync('./html/css/style.css', 'UTF-8');
const scriptJs = fs.readFileSync('./html/js/script.js', 'UTF-8');

const hostname = '127.0.0.1';
const port = 3000;

const server = http.createServer(RouteSetting);

server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});

function RouteSetting(req, res) {
  const url_parts = url.parse(req.url);
  switch (url_parts.pathname) {
    case '/':
    case '/index.html':
      res.writeHead(200, {'Content-Type': 'text/html'});
      res.write(indexPage);
      res.end();
      break;
  
    case '/css/style.css':
    res.writeHead(200, {'Content-Type': 'text/css'});
    res.write(styleCss);
    res.end();
    break;

    case '/js/script.js':
      res.writeHead(200, {'Content-Type': 'text/plain'});
      res.write(scriptJs);
      res.end();
      break;

    default:
      res.writeHead(200, {'Content-Type': 'text/plain'});
      res.end('お探しのページは見つかりません。');
      break;
  }
}

最後に

ということで、CSS、JSファイルを読み込むことに成功しました。フロントエンドに慣れていると、ルーティング設定をしないとファイルが読み込まれないのはちょっと手間に感じる。

しかし、逆に、全然違う場所にあるファイルもルーティング設定によって自分の思い通りの構成に設定することもできる。

テンプレートエンジンを使っていくとページのパーツや値を組み合わせてサイトと作ることができる。バックエンドのメリットをだんだんと感じていきたい。

次回は引き続きルーティング設定で複数ページのサイトと作ってみたく。それではまた!


Node.js / Expressを習得するためにやったことまとめ(随時更新)
qiita.com