forked from sashin/sashinexists
69 lines
2.2 KiB
JavaScript
69 lines
2.2 KiB
JavaScript
import { Tree } from "@weborigami/async-tree";
|
|
import http from "node:http";
|
|
import { createServer } from "node:net";
|
|
import process from "node:process";
|
|
import assertTreeIsDefined from "../common/assertTreeIsDefined.js";
|
|
import { isTransformApplied, transformObject } from "../common/utilities.js";
|
|
import { requestListener } from "../server/server.js";
|
|
import debug from "./debug.js";
|
|
import ExplorableSiteTransform from "./ExplorableSiteTransform.js";
|
|
import watch from "./watch.js";
|
|
|
|
const defaultPort = 5000;
|
|
|
|
/**
|
|
* Start a local web server for the indicated tree.
|
|
*
|
|
* @typedef {import("@weborigami/types").AsyncTree} AsyncTree
|
|
* @typedef {import("@weborigami/async-tree").Treelike} Treelike
|
|
*
|
|
* @param {Treelike} treelike
|
|
* @param {number} [port]
|
|
* @this {AsyncTree|null}
|
|
*/
|
|
export default async function serve(treelike, port) {
|
|
assertTreeIsDefined(this, "dev:serve");
|
|
let tree;
|
|
if (treelike) {
|
|
tree = Tree.from(treelike, { parent: this });
|
|
if (!isTransformApplied(ExplorableSiteTransform, tree)) {
|
|
tree = transformObject(ExplorableSiteTransform, tree);
|
|
}
|
|
} else {
|
|
// By default, watch the default tree and add default pages.
|
|
const withDefaults = await debug.call(this);
|
|
tree = await watch.call(this, withDefaults);
|
|
}
|
|
|
|
if (port === undefined) {
|
|
if (process.env.PORT) {
|
|
// Use the port specified in the environment.
|
|
port = parseInt(process.env.PORT);
|
|
} else {
|
|
// Find an open port.
|
|
port = await findOpenPort(defaultPort);
|
|
}
|
|
}
|
|
|
|
// @ts-ignore
|
|
http.createServer(requestListener(tree)).listen(port, undefined, () => {
|
|
console.log(
|
|
`Server running at http://localhost:${port}. Press Ctrl+C to stop.`
|
|
);
|
|
});
|
|
}
|
|
|
|
// Return the first open port number on or after the given port number.
|
|
// From https://gist.github.com/mikeal/1840641?permalink_comment_id=2896667#gistcomment-2896667
|
|
function findOpenPort(port) {
|
|
const server = createServer();
|
|
return new Promise((resolve, reject) =>
|
|
server
|
|
.on("error", (/** @type {any} */ error) =>
|
|
error.code === "EADDRINUSE" ? server.listen(++port) : reject(error)
|
|
)
|
|
.on("listening", () => server.close(() => resolve(port)))
|
|
.listen(port)
|
|
);
|
|
}
|