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(); }