refactor: clean up gallery tooling and document the workflow
All checks were successful
Deploy on push / deploy (push) Has been skipped
All checks were successful
Deploy on push / deploy (push) Has been skipped
This commit is contained in:
131
scripts/serve.js
Normal file
131
scripts/serve.js
Normal file
@@ -0,0 +1,131 @@
|
||||
const fs = require("fs");
|
||||
const http = require("http");
|
||||
const path = require("path");
|
||||
|
||||
const { repoRoot } = require("./lib/meals");
|
||||
|
||||
const DEFAULT_HOST = "127.0.0.1";
|
||||
const DEFAULT_PORT = 4321;
|
||||
const MIME_TYPES = {
|
||||
".css": "text/css; charset=utf-8",
|
||||
".gif": "image/gif",
|
||||
".html": "text/html; charset=utf-8",
|
||||
".ico": "image/x-icon",
|
||||
".jpg": "image/jpeg",
|
||||
".js": "application/javascript; charset=utf-8",
|
||||
".json": "application/json; charset=utf-8",
|
||||
".map": "application/json; charset=utf-8",
|
||||
".mp3": "audio/mpeg",
|
||||
".png": "image/png",
|
||||
".svg": "image/svg+xml",
|
||||
".ttf": "font/ttf",
|
||||
".txt": "text/plain; charset=utf-8",
|
||||
".webmanifest": "application/manifest+json; charset=utf-8",
|
||||
".woff": "font/woff",
|
||||
".woff2": "font/woff2",
|
||||
};
|
||||
|
||||
function parseArgs(argv) {
|
||||
const options = {
|
||||
host: process.env.HOST || DEFAULT_HOST,
|
||||
port: Number.parseInt(process.env.PORT || String(DEFAULT_PORT), 10),
|
||||
};
|
||||
|
||||
for (let index = 0; index < argv.length; index += 1) {
|
||||
const arg = argv[index];
|
||||
const value = argv[index + 1];
|
||||
|
||||
if (arg === "--host" && value) {
|
||||
options.host = value;
|
||||
index += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg === "--port" && value) {
|
||||
options.port = Number.parseInt(value, 10);
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Number.isInteger(options.port) || options.port <= 0 || options.port > 65535) {
|
||||
throw new Error("Port must be an integer between 1 and 65535");
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
function getContentType(filePath) {
|
||||
return MIME_TYPES[path.extname(filePath).toLowerCase()] || "application/octet-stream";
|
||||
}
|
||||
|
||||
function resolveRequestPath(requestUrl) {
|
||||
const url = new URL(requestUrl, "http://localhost");
|
||||
const pathname = decodeURIComponent(url.pathname);
|
||||
const requestedPath = pathname === "/" ? "/index.html" : pathname;
|
||||
const absolutePath = path.resolve(repoRoot, `.${requestedPath}`);
|
||||
const withinRepo =
|
||||
absolutePath === repoRoot || absolutePath.startsWith(`${repoRoot}${path.sep}`);
|
||||
|
||||
if (!withinRepo) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (fs.existsSync(absolutePath) && fs.statSync(absolutePath).isDirectory()) {
|
||||
return path.join(absolutePath, "index.html");
|
||||
}
|
||||
|
||||
return absolutePath;
|
||||
}
|
||||
|
||||
function sendFile(response, filePath) {
|
||||
const stream = fs.createReadStream(filePath);
|
||||
|
||||
response.writeHead(200, {
|
||||
"Content-Type": getContentType(filePath),
|
||||
"Cache-Control": "no-cache",
|
||||
});
|
||||
|
||||
stream.pipe(response);
|
||||
stream.on("error", () => {
|
||||
response.writeHead(500, { "Content-Type": "text/plain; charset=utf-8" });
|
||||
response.end("Failed to read file");
|
||||
});
|
||||
}
|
||||
|
||||
function createServer() {
|
||||
return http.createServer((request, response) => {
|
||||
const filePath = resolveRequestPath(request.url || "/");
|
||||
|
||||
if (!filePath) {
|
||||
response.writeHead(403, { "Content-Type": "text/plain; charset=utf-8" });
|
||||
response.end("Forbidden");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!fs.existsSync(filePath) || !fs.statSync(filePath).isFile()) {
|
||||
response.writeHead(404, { "Content-Type": "text/plain; charset=utf-8" });
|
||||
response.end("Not found");
|
||||
return;
|
||||
}
|
||||
|
||||
sendFile(response, filePath);
|
||||
});
|
||||
}
|
||||
|
||||
function main() {
|
||||
const options = parseArgs(process.argv.slice(2));
|
||||
const server = createServer();
|
||||
|
||||
server.listen(options.port, options.host, () => {
|
||||
console.log(`Serving ${repoRoot} at http://${options.host}:${options.port}`);
|
||||
});
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
try {
|
||||
main();
|
||||
} catch (error) {
|
||||
console.error(error.message);
|
||||
process.exitCode = 1;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user