1
1

とにかくシンプルな静的 HTTP (Web) サーバを Deno で書く

Posted at

背景

ESM (ECMAScript Module) の import 宣言を使用している場合、ローカルファイル読み込み (HTML ファイルを直接開く) では動いてくれません。何らかの HTTP サーバを立てて、それ経由で読み込む必要があります。

もうちょっと具体的に言うと: CORS ポリシーに引っかかります。

HTTP サーバといえば Apache とか nginx とかがありますが、しかし簡単なテスト動作をしたいだけなのにルート権限で色々いじくったりするのは面倒だし行儀が悪い。

かといって、わざわざ Docker とか仮想環境を作ってやるほどの規模のことでもない。

ルート権限無しでサッと起動できる HTTP サーバがあると便利なわけです。ということで、Deno で極限シンプルな HTTP サーバを作ってみることにします。

準備とか

ファイル構成はこんな感じ。

./
 |- main.js
 |- static
 |   |- any_script.js
 |   |- any_style.css
 |
 |- pages
     |- index.html
     |- hello.html
ファイル内容例
any_script.js
window.addEventListener("load", () => {
  console.log("window loaded");
});
any_style.css
@charset "UTF-8";

h1 {
  color: red;
}
index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="/static/any_style.css">
    <script type="module" src="/static/any_script.js"></script>
  </head>
  <body>
    <h1>index</h1>
    <p><a href="./hello.html">hello</a></p>
  </body>
</html>
hello.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="/static/any_style.css">
    <script type="module" src="/static/any_script.js"></script>
  </head>
  <body>
    <h1>hello</h1>  
  </body>
</html>

そして、こんな感じで起動。

deno --allow-net --allow-read main.js

HTML ページ (pages) の URL はこんな感じ。

  • http://localhost:8000/
  • http://localhost:8000/hello.html

CSS や JavaScript (static) の URL はこんな感じ。

  • http://localhost:8000/static/any_style.css
  • http://localhost:8000/static/any_script.js

完成品

import { serveDir } from "jsr:@std/http@1";

Deno.serve(request => {
  const url = new URL(request.url);

  if(url.pathname.startsWith("/static")) {
    return serveDir(request, { fsRoot: "./static", urlRoot: "static"});
  }

  return serveDir(request, { fsRoot: "./pages", urlRoot: ""});
});

std パッケージ std/httpserveDir と、あとは Deno ネームスペース API の Deno.serve だけで全て完結します。

URL がルート https://localhost:8000/ のときは、自動で https://localhost:8000/index.html につなげてくれました。

serveserveDirhttps://deno.land/... から import しているコードを見かけるかもしれません。これは少し古いやり方で、最近では "jsr:..." というのを使うのが公式で推奨されています。

std ライブラリリファレンス上部にその旨示されています。

古いとはいっても、そう何年と昔でない (ブログ作成日は 2024年5月) のですが。

pages / static 分けすらしないなら

つまり、こういうファイル構成。

./
 |- main.js
 |- items
     |- any_script.js
     |- any_style.css
     |- index.html
     |- hello.html
ファイル内容例
any_script.js
window.addEventListener("load", () => {
  console.log("window loaded");
});
any_style.css
@charset "UTF-8";

h1 {
  color: red;
}

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
-   <link rel="stylesheet" href="/static/any_style.css">
-   <script type="module" src="/static/any_script.js"></script>
+   <link rel="stylesheet" href="./any_style.css">
+   <script type="module" src="./any_script.js"></script>
  </head>
  <body>
    <h1>index</h1>
    <p><a href="./hello.html">hello</a></p>
  </body>
</html>

hello.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
-   <link rel="stylesheet" href="/static/any_style.css">
-   <script type="module" src="/static/any_script.js"></script>
+   <link rel="stylesheet" href="./any_style.css">
+   <script type="module" src="./any_script.js"></script>
  </head>
  <body>
    <h1>hello</h1>  
  </body>
</html>

apache デフォルト設定の /var/www/html と同等。

ディレクトリ名変更以外、上の main.js をさらに削るだけ。

main.js
import { serveDir } from "jsr:@std/http@1";

Deno.serve(request => {
  return serveDir(request, { fsRoot: "./items", urlRoot: ""});
});

というかこれ、(import 除いて) ワンライナーにできてしまう。

main.js
import { serveDir } from "jsr:@std/http@1";

Deno.serve(request => serveDir(request, { fsRoot: "./items", urlRoot: ""}));

おわり

細かい設定も無し。ステキ。

1
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1