import { log } from "../core/utils/log.ts";
import { localIp, openBrowser } from "../core/utils/net.ts";
import { envBoolean, setEnv } from "../core/utils/env.ts";
import { normalizePath } from "../core/utils/path.ts";
import { resolveConfigFile } from "../core/utils/lume_config.ts";
import { init } from "../core/utils/hmr.ts";
import { fromFileUrl } from "../deps/path.ts";
import { SiteWatcher } from "../core/watcher.ts";
import logger from "../middlewares/logger.ts";
import noCache from "../middlewares/no_cache.ts";
import noCors from "../middlewares/no_cors.ts";
import reload from "../middlewares/reload.ts";
import { buildSite, createSite } from "./utils.ts";
import { initLocalStorage } from "./missing_worker_apis.ts";
import Server from "../core/server.ts";
addEventListener("message", (event) => {
const { type } = event.data;
if (type === "build" || type === "rebuild") {
return build(event.data);
}
if (type === "localStorage") {
return initLocalStorage(event.data.data);
}
});
interface BuildOptions {
type: "build" | "rebuild";
config?: string;
serve?: boolean;
cms?: boolean;
}
async function build({ type, config, serve, cms: loadCms }: BuildOptions) {
let server: Server | undefined;
// Set the live reload environment variable to add hash to the URLs in the module loader
setEnv("LUME_LIVE_RELOAD", "true");
// Show draft pages in development mode (if not set already)
const showDrafts = envBoolean("LUME_DRAFTS");
if (showDrafts === undefined) {
setEnv("LUME_DRAFTS", "true");
}
init();
const _config = await resolveConfigFile(["_config.ts", "_config.js"], config);
const site = await createSite(_config);
// Start the server and show the wait page while building the first time
if (serve) {
server = site.getServer();
server.wait();
log.info(`Web server started at http://${server.hostname}:${server.port}/`);
}
// Setup LumeCMS
let _cms: URL | undefined;
// deno-lint-ignore no-explicit-any
let cms: any;
if (loadCms) {
_cms = await resolveConfigFile(["_cms.ts", "_cms.js"]);
if (_cms) {
const mod = await import(_cms.href);
cms = mod.default;
const { lumeCMS } = await import("../plugins/lume_cms.ts");
site.use(lumeCMS({ cms }));
}
}
// Include the config files to the watcher
const reloadFiles: string[] = [];
if (_config) {
reloadFiles.push(normalizePath(fromFileUrl(_config), site.root()));
site.options.watcher.include.push(fromFileUrl(_config));
}
if (_cms) {
reloadFiles.push(normalizePath(fromFileUrl(_cms), site.root()));
site.options.watcher.include.push(fromFileUrl(_cms));
}
try {
await buildSite(site);
} catch (error) {
console.error(Deno.inspect(error, { colors: true }));
}
// Start the watcher
const watcher = site.getWatcher();
const srcFolder = normalizePath(site.options.src);
watcher.addEventListener("change", async (event) => {
const files = event.files!;
// If the config files have changed, reload the build process
if (reloadFiles.some((file) => files.has(file))) {
log.info("Reloading the site...");
log.output();
postMessage({ type: "reload" });
return;
}
const srcFiles = new Set(
[...files]
.filter((file) => file.startsWith(srcFolder))
.map((file) => srcFolder === "/" ? file : file.slice(srcFolder.length)),
);
log.info("Changes detected:");
srcFiles.forEach((file) => {
log.info(`- ${file}`);
});
await site.update(srcFiles);
log.output();
});
watcher.addEventListener("error", (event) => {
console.error(Deno.inspect(event.error, { colors: true }));
});
watcher.start();
if (!server) {
return;
}
// Start the local server
const { port, hostname, open } = site.options.server;
server.addEventListener("start", () => {
if (type === "build") {
const ipAddr = localIp();
log.info("\n Server started at:");
log.info(` http://${hostname}:${port}/ (local)`);
if (ipAddr) {
log.info(` http://${ipAddr}:${port}/ (network)`);
}
if (cms) {
log.info("\n LumeCMS started at:");
const { basePath } = cms.options;
log.info(
` http://${hostname}:${port}${basePath} (local)`,
);
if (ipAddr) {
log.info(
` http://${ipAddr}:${port}${basePath} (network)`,
);
}
}
if (open) {
openBrowser(`http://${hostname}:${port}/`);
}
}
site.dispatchEvent({ type: "afterStartServer" });
});
if (log.level < 5) {
server.use(logger());
}
// Add the reload middleware
server.addEventListener("start", () => {
server.useFirst(async (request, next) => {
const response = await next(request);
// Reload if the response header tells us to
if (response.headers.get("X-Lume-CMS") === "reload") {
log.info("Exiting process...");
const url = response.headers.get("Location") || request.url;
postMessage({ type: "exit" });
return server.handleWait(url);
}
return response;
});
}, { once: true });
server.useFirst(
reload({
watcher: new SiteWatcher(site),
basepath: site.options.location.pathname,
debugBar: site.debugBar,
}),
noCache(),
noCors(),
);
server.start();
log.output();
}