const fs = require('fs') const http = require('http') const path = require('path') const chalk = require('chalk') const pify = require('pify') const serveHandler = require('serve-handler') const fsStat = pify(fs.stat) const DEFAULT_PORT = 9080 const onResponse = (request, response) => { if (response.statusCode >= 400) { console.log(chalk`{gray '-->'} {red ${response.statusCode}} ${request.url}`) } else if (response.statusCode >= 200 && response.statusCode < 300) { console.log(chalk`{gray '-->'} {green ${response.statusCode}} ${request.url}`) } else { console.log(chalk`{gray '-->'} {green.dim ${response.statusCode}} ${request.url}`) } } const onRequest = (request, response) => { console.log(chalk`{gray '<--'} {blue [${request.method}]} ${request.url}`) response.on('finish', () => onResponse(request, response)) } const startServer = ({ port, rootDirectory }) => { const server = http.createServer((request, response) => { if (request.url.startsWith('/node_modules/')) { request.url = request.url.substr(14) return serveHandler(request, response, { directoryListing: false, public: path.resolve('./node_modules'), }) } return serveHandler(request, response, { directoryListing: false, public: rootDirectory, }) }) server.on('request', onRequest) server.listen(port, () => { console.log(`Running at http://localhost:${port}`) }) } const parsePort = (portString) => { const port = Number(portString) if (!Number.isInteger(port)) { throw new Error(`Port '${portString}' is invalid; must be an integer`) } else if (port < 0 || port > 65535) { throw new Error(`Port '${portString}' is out of range; must be between 0 and 65535 inclusive`) } return port } const parseDirectoryArgument = async (pathString) => { const resolvedPath = path.resolve(pathString) const directoryStats = await fsStat(resolvedPath) if (!directoryStats.isDirectory()) { throw new Error(`Invalid path '${pathString}'; must be a directory`) } return resolvedPath } const main = async () => { const args = process.argv.slice(2) const options = { port: process.env.port || DEFAULT_PORT, rootDirectory: path.resolve('.'), } while (args.length) { if (/^(--port|-p)$/i.test(args[0])) { if (args[1] === undefined) { throw new Error('Missing port argument') } options.port = parsePort(args[1]) args.splice(0, 2) } else { options.rootDirectory = await parseDirectoryArgument(args[0]) args.splice(0, 1) } } startServer(options) } main() .catch((error) => { console.error(error) process.exit(1) })