Node-REDをWebサーバっぽく使う

Node-REDだけでSPAを作るメモ
フロントエンドのファイルはNuxtで書いたやつをでビルドしたもの

# Node-RED側

``` javascript
[{"id":"a51e456b.d4d848","type":"http in","z":"602759b5.37fbe8","name":"","url":"/web/*","method":"get","upload":false,"swaggerDoc":"","x":530,"y":4160,"wires":[["b336907c.b932a"]]},{"id":"b336907c.b932a","type":"function","z":"602759b5.37fbe8","name":"","func":"const filepath = '/data/web'\nif(!/\\?/.test(msg.req.url)){\n    urlPath = msg.req.url.replace(/^\\/web/,'');\n    if(urlPath =='/' || !/\\./.test(msg.req.url))urlPath = '/index.html'\n    msg.filename = filepath + urlPath;\n    return msg;\n}\n","outputs":1,"noerr":0,"x":670,"y":4160,"wires":[["5e338aef.e61274"]]},{"id":"1b20081a.f68c58","type":"http response","z":"602759b5.37fbe8","name":"","statusCode":"","headers":{},"x":1310,"y":4160,"wires":[]},{"id":"32b1b536.1c40fa","type":"function","z":"602759b5.37fbe8","name":"Content-Type","func":"let ext = msg.filename.split('.').pop();\nlet contentType = msg.mimeTypes[`.${ext}`];\n\nmsg.headers = {};\nmsg.headers['Content-Type'] = contentType;\nreturn msg;","outputs":1,"noerr":0,"x":1140,"y":4160,"wires":[["1b20081a.f68c58"]]},{"id":"5e338aef.e61274","type":"file in","z":"602759b5.37fbe8","name":"","filename":"","format":"","chunk":false,"sendError":false,"encoding":"none","x":790,"y":4160,"wires":[["b91a41ab.7776"]]},{"id":"b91a41ab.7776","type":"template","z":"602759b5.37fbe8","name":"mime.types","field":"mimeTypes","fieldType":"msg","format":"json","syntax":"mustache","template":"{\n\".aac\":\"audio/aac\",\n\".abw\":\"application/x-abiword\",\n\".arc\":\"application/x-freearc\",\n\".avi\":\"video/x-msvideo\",\n\".azw\":\"application/vnd.amazon.ebook\",\n\".bin\":\"application/octet-stream\",\n\".bmp\":\"image/bmp\",\n\".bz\":\"application/x-bzip\",\n\".bz2\":\"application/x-bzip2\",\n\".csh\":\"application/x-csh\",\n\".css\":\"text/css\",\n\".csv\":\"text/csv\",\n\".doc\":\"application/msword\",\n\".docx\":\"application/vnd.openxmlformats-officedocument.wordprocessingml.document\",\n\".eot\":\"application/vnd.ms-fontobject\",\n\".epub\":\"application/epub+zip\",\n\".gz\":\"application/gzip\",\n\".gif\":\"image/gif\",\n\".htm\":\"text/html\",\n\".html\":\"text/html\",\n\".ico\":\"image/vnd.microsoft.icon\",\n\".ics\":\"text/calendar\",\n\".jar\":\"application/java-archive\",\n\".jpeg\":\"image/jpeg\",\n\".jpg\":\"image/jpeg\",\n\".js\":\"text/javascript\",\n\".json\":\"application/json\",\n\".jsonld\":\"application/ld+json\",\n\".mid\":\"audio/midi audio/x-midi\",\n\".midi\":\"audio/midi audio/x-midi\",\n\".mjs\":\"text/javascript\",\n\".mp3\":\"audio/mpeg\",\n\".mpeg\":\"video/mpeg\",\n\".mpkg\":\"application/vnd.apple.installer+xml\",\n\".odp\":\"application/vnd.oasis.opendocument.presentation\",\n\".ods\":\"application/vnd.oasis.opendocument.spreadsheet\",\n\".odt\":\"application/vnd.oasis.opendocument.text\",\n\".oga\":\"audio/ogg\",\n\".ogv\":\"video/ogg\",\n\".ogx\":\"application/ogg\",\n\".otf\":\"font/otf\",\n\".png\":\"image/png\",\n\".pdf\":\"application/pdf\",\n\".php\":\"appliction/php\",\n\".ppt\":\"application/vnd.ms-powerpoint\",\n\".pptx\":\"application/vnd.openxmlformats-officedocument.presentationml.presentation\",\n\".rar\":\"application/x-rar-compressed\",\n\".rtf\":\"application/rtf\",\n\".sh\":\"application/x-sh\",\n\".svg\":\"image/svg+xml\",\n\".swf\":\"application/x-shockwave-flash\",\n\".tar\":\"application/x-tar\",\n\".tif\":\"image/tiff\",\n\".tiff\":\"image/tiff\",\n\".ts\":\"video/mp2t\",\n\".ttf\":\"font/ttf\",\n\".txt\":\"text/plain\",\n\".vsd\":\"application/vnd.visio\",\n\".wav\":\"audio/wav\",\n\".weba\":\"audio/webm\",\n\".webm\":\"video/webm\",\n\".webp\":\"image/webp\",\n\".woff\":\"font/woff\",\n\".woff2\":\"font/woff2\",\n\".xhtml\":\"application/xhtml+xml\",\n\".xls\":\"application/vnd.ms-excel\",\n\".xlsx\":\"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\",\n\".xml\":\"application/xml\",\n\".xul\":\"application/vnd.mozilla.xul+xml\",\n\".zip\":\"application/zip\",\n\".3gp\":\"video/3gpp\",\n\".3g2\":\"video/3gpp2\",\n\".7z\":\"application/x-7z-compressed\"\n}","output":"json","x":950,"y":4160,"wires":[["32b1b536.1c40fa"]]},{"id":"cec26454.08f6e8","type":"http in","z":"602759b5.37fbe8","name":"","url":"/web","method":"get","upload":false,"swaggerDoc":"","x":520,"y":4240,"wires":[["8f188ff1.f20b1"]]},{"id":"8f188ff1.f20b1","type":"function","z":"602759b5.37fbe8","name":"","func":"const filepath = '/data/dist/index.html'\nmsg.filename = filepath \nreturn msg;","outputs":1,"noerr":0,"x":670,"y":4240,"wires":[["8f48ed4e.fb64b"]]},{"id":"2be98cd5.3aa5e4","type":"http response","z":"602759b5.37fbe8","name":"","statusCode":"","headers":{},"x":1310,"y":4240,"wires":[]},{"id":"3e4234f.27000cc","type":"function","z":"602759b5.37fbe8","name":"Content-Type","func":"let ext = msg.filename.split('.').pop();\nlet contentType = msg.mimeTypes[`.${ext}`];\n\nmsg.headers = {};\nmsg.headers['Content-Type'] = contentType;\nreturn msg;","outputs":1,"noerr":0,"x":1140,"y":4240,"wires":[["2be98cd5.3aa5e4"]]},{"id":"8f48ed4e.fb64b","type":"file in","z":"602759b5.37fbe8","name":"","filename":"","format":"","chunk":false,"sendError":false,"encoding":"none","x":790,"y":4240,"wires":[["a1a8ec5a.671f6"]]},{"id":"a1a8ec5a.671f6","type":"template","z":"602759b5.37fbe8","name":"mime.types","field":"mimeTypes","fieldType":"msg","format":"json","syntax":"mustache","template":"{\n\".aac\":\"audio/aac\",\n\".abw\":\"application/x-abiword\",\n\".arc\":\"application/x-freearc\",\n\".avi\":\"video/x-msvideo\",\n\".azw\":\"application/vnd.amazon.ebook\",\n\".bin\":\"application/octet-stream\",\n\".bmp\":\"image/bmp\",\n\".bz\":\"application/x-bzip\",\n\".bz2\":\"application/x-bzip2\",\n\".csh\":\"application/x-csh\",\n\".css\":\"text/css\",\n\".csv\":\"text/csv\",\n\".doc\":\"application/msword\",\n\".docx\":\"application/vnd.openxmlformats-officedocument.wordprocessingml.document\",\n\".eot\":\"application/vnd.ms-fontobject\",\n\".epub\":\"application/epub+zip\",\n\".gz\":\"application/gzip\",\n\".gif\":\"image/gif\",\n\".htm\":\"text/html\",\n\".html\":\"text/html\",\n\".ico\":\"image/vnd.microsoft.icon\",\n\".ics\":\"text/calendar\",\n\".jar\":\"application/java-archive\",\n\".jpeg\":\"image/jpeg\",\n\".jpg\":\"image/jpeg\",\n\".js\":\"text/javascript\",\n\".json\":\"application/json\",\n\".jsonld\":\"application/ld+json\",\n\".mid\":\"audio/midi audio/x-midi\",\n\".midi\":\"audio/midi audio/x-midi\",\n\".mjs\":\"text/javascript\",\n\".mp3\":\"audio/mpeg\",\n\".mpeg\":\"video/mpeg\",\n\".mpkg\":\"application/vnd.apple.installer+xml\",\n\".odp\":\"application/vnd.oasis.opendocument.presentation\",\n\".ods\":\"application/vnd.oasis.opendocument.spreadsheet\",\n\".odt\":\"application/vnd.oasis.opendocument.text\",\n\".oga\":\"audio/ogg\",\n\".ogv\":\"video/ogg\",\n\".ogx\":\"application/ogg\",\n\".otf\":\"font/otf\",\n\".png\":\"image/png\",\n\".pdf\":\"application/pdf\",\n\".php\":\"appliction/php\",\n\".ppt\":\"application/vnd.ms-powerpoint\",\n\".pptx\":\"application/vnd.openxmlformats-officedocument.presentationml.presentation\",\n\".rar\":\"application/x-rar-compressed\",\n\".rtf\":\"application/rtf\",\n\".sh\":\"application/x-sh\",\n\".svg\":\"image/svg+xml\",\n\".swf\":\"application/x-shockwave-flash\",\n\".tar\":\"application/x-tar\",\n\".tif\":\"image/tiff\",\n\".tiff\":\"image/tiff\",\n\".ts\":\"video/mp2t\",\n\".ttf\":\"font/ttf\",\n\".txt\":\"text/plain\",\n\".vsd\":\"application/vnd.visio\",\n\".wav\":\"audio/wav\",\n\".weba\":\"audio/webm\",\n\".webm\":\"video/webm\",\n\".webp\":\"image/webp\",\n\".woff\":\"font/woff\",\n\".woff2\":\"font/woff2\",\n\".xhtml\":\"application/xhtml+xml\",\n\".xls\":\"application/vnd.ms-excel\",\n\".xlsx\":\"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\",\n\".xml\":\"application/xml\",\n\".xul\":\"application/vnd.mozilla.xul+xml\",\n\".zip\":\"application/zip\",\n\".3gp\":\"video/3gpp\",\n\".3g2\":\"video/3gpp2\",\n\".7z\":\"application/x-7z-compressed\"\n}","output":"json","x":950,"y":4240,"wires":[["3e4234f.27000cc"]]}]
```

## やってること

エンドポイントへのアクセスをファイルパスに読み替えてファイルを取ってきて返却する


## ポイント

### mine-typeの指定

指定しないとCSSが適用されない

### ディレクトリ直アクセスをindex.htmlへ流す

webサーバのエントリーポイント設定みたいなもの

# Nuxt側

``` javascript:nuxt.config.js
export default {
  publicPath: 'http://${ドメイン}/web/',
  router: {
    base: '/web/'
  }
}
```

publicPathは相対パス設定でもいいかも