一つのファイルでサーバーとHTMLファイルとコードを共有するやつ
ちょっと説明がし難いがindex.htmlというファイルがあったとして、ファイルプロトコル経由で
file://path/index.html
などのように直接ブラウザで起動すると、プロトコルの関係でファイルが読み込めなかったり、エラーになったりすることがよくある。サーバーをたててlocalhostなどから読み込めばいいのだが、微妙にセットアップが面倒臭い。下記コードをindex.htmlとして保存すると
node index.html
とするだけでブラウザが立ち上がり、index.html自身をルートとしてそのディレクトリ以下のファイルを配信する簡易サーバーが立ち上がる。具体的には、
http://localhost:port/index.html
のような形でアクセスできるようになる。コマンドを実行したディレクトリの絶対パスをもとにポートを自動生成しているので、すでにサーバーが起動済みの場合、
node index.html
は新規にサーバーを立ち上げずに、既存のlocalhost:port/index.htmlをブラウザで開く。 特殊な魔法を使っているので、HTMLとしてもJSとしてもvalidで、ブラウザでもnodeでもコードの一部を共有している。
<!-- (function () { /* --> <!DOCTYPE html> <html> <head> <title>Title</title> <meta charset="UTF-8"> </head> <body> <p>Hello!</p> </body> </html> <script src="index.html"></script> <!-- */ // Shared among server and client sides function mapPort(s) { var hashCode = 0; for (var i = 0; i < s.length; i++) { hashCode += hashCode * 31 + s.charCodeAt(i); } return 49152 + hashCode % 16384; } // Only for browser if (typeof window !== 'undefined') { if (location.protocol == 'file:') { var url = 'http://localhost:' + mapPort(location.pathname); var req = new XMLHttpRequest(); req.open('GET', url, false); try { req.send(null); location.href = url; } catch (ex) { document.writeln("<p>Server is not running. Please run the server by node index.html</p>"); } } return; } // Only for Node.js // Running a simple server. var http = require('http'), fs = require('fs'), child_process = require('child_process'), path = require('path'); var ROOT_DIR = path.dirname(process.argv[1]); function openInBrowser(url) { return child_process.spawnSync('open', [url]); } var port = mapPort(process.argv[1]); var server = http.createServer(function (req, res) { var fPath = path.join(ROOT_DIR, req.url, /\/$/.test(req.url) ? 'index.html' : ''), file = null; try { file = fs.readFileSync(fPath); } catch (e) { // NOOP } res.writeHead(file ? 200 : 404); res.end(file || "File Not Found"); }).listen({port: port }, function () { console.log('successfully established'); openInBrowser('http://localhost:' + port); }).on('error', function () { console.log('already open?'); openInBrowser('http://localhost:' + port); }); })(); // -->