import { log } from "../core/utils/log.ts"; import { localIp, openBrowser } from "../core/utils/net.ts"; import { env, setEnv } from "../core/utils/env.ts"; import { normalizePath } from "../core/utils/path.ts"; import { resolveConfigFile } from "../core/utils/lume_config.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 { parseArgs } from "../deps/cli.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 = env("LUME_DRAFTS"); if (showDrafts === undefined) { setEnv("LUME_DRAFTS", "true"); } // Start the server before loading the site to reduce uptime if (serve) { const cli = parseArgs(Deno.args, { string: ["port", "hostname"], alias: { serve: "s", port: "p" }, }); // Only start the server if a port is specified (because it might be changed in the _config file) if (cli.port) { server = new Server({ port: parseInt(cli.port), hostname: cli.hostname, }); server.wait(); log.info("Web server started..."); } } 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) { if (!server) { server = site.getServer(); server.wait(); log.info("Web server started..."); } else { // Swap the servers to keep the middlewares and options const tmp = site.getServer(); site.server = server; server.middlewares = tmp.middlewares; server.options = tmp.options; } } // 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(); watcher.addEventListener("change", async (event) => { const files = event.files!; log.info("Changes detected:"); files.forEach((file) => { log.info(`- ${file}`); }); // 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; } await site.update(files); 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(); }