UNPKG

honkit

Version:

HonKit is building beautiful books using Markdown.

210 lines (209 loc) 7.89 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const tiny_lr_1 = __importDefault(require("tiny-lr")); const open_1 = __importDefault(require("open")); const immutable_1 = __importDefault(require("immutable")); const parse_1 = __importDefault(require("../parse")); const output_1 = __importDefault(require("../output")); const modifiers_1 = __importDefault(require("../modifiers")); const promise_1 = __importDefault(require("../utils/promise")); const options_1 = __importDefault(require("./options")); const getBook_1 = __importDefault(require("./getBook")); const getOutputFolder_1 = __importDefault(require("./getOutputFolder")); const server_1 = __importDefault(require("./server")); const watch_1 = __importDefault(require("./watch")); const shouldFullRebuild_1 = require("./shouldFullRebuild"); const page_cache_1 = require("../output/page-cache"); const fs_1 = __importDefault(require("fs")); let server, lrServer, lrPath; function triggerLiveReload() { if (lrPath) { lrServer.changed({ body: { files: [lrPath] } }); } } function waitForCtrlC() { const d = promise_1.default.defer(); process.on("SIGINT", () => { d.resolve(); }); return d.promise; } function startServer(args, kwargs) { const outputFolder = (0, getOutputFolder_1.default)(args); const port = kwargs.port; const browser = kwargs["browser"]; const book = (0, getBook_1.default)(args, kwargs); const hasWatch = kwargs["watch"]; const hasOpen = kwargs["open"]; const hasLiveReloading = kwargs["live"]; const reload = kwargs["reload"]; const Generator = output_1.default.getGenerator(kwargs.format); const logger = book.getLogger(); logger.info.ok("Starting server ..."); let lastOutput = null; return promise_1.default.all([ server.start(outputFolder, port), generateBook({ book, outputFolder, hasLiveReloading, Generator, reload }).then((output) => { lastOutput = output; return output; }) ]) .then(() => { console.log(`Serving book on http://localhost:${port}`); if (hasOpen) { (0, open_1.default)(`http://localhost:${port}`, { app: browser }); } }) .then(() => { if (!hasWatch) { return waitForCtrlC(); } // update book immutably. does not use book again // Pass outputFolder to watch to prevent infinite rebuild loops // https://github.com/honkit/honkit/issues/491 (0, watch_1.default)({ watchDir: book.getRoot(), outputFolder, callback: (error, filepath, eventType) => { if (error) { console.error(error); return; } // If the file does not exist in file system, show a warning and skip // Probably, the file has been deleted if (!fs_1.default.existsSync(filepath)) { logger.warn.ok(`${filepath} does not exist in file system.`); return; } // set livereload path lrPath = filepath; // Full rebuild is required for: // 1. Structure files (SUMMARY.md, GLOSSARY.md, book.json, book.js) // 2. New file additions (to update asset list and page structure) const needsFullRebuild = (0, shouldFullRebuild_1.shouldFullRebuild)(filepath, eventType); // Incremental update for existing pages (only for .md files that don't require full rebuild) if (lastOutput && filepath.endsWith(".md") && !needsFullRebuild) { logger.warn.ok("Rebuild " + filepath); const changedOutput = lastOutput.reloadPage(lastOutput.book.getContentRoot(), filepath).merge({ incrementalChangeFileSet: immutable_1.default.Set([filepath]) }); return incrementalBuild({ output: changedOutput, Generator }).then(() => { if (hasLiveReloading) triggerLiveReload(); }); } // Full rebuild for structure changes, new files, or non-markdown files const reason = needsFullRebuild ? " (full rebuild)" : ""; logger.info.ok("Rebuild " + filepath + reason); return generateBook({ book, outputFolder, hasLiveReloading, Generator, reload }).then((output) => { lastOutput = output; if (hasLiveReloading) triggerLiveReload(); }); } }); }); } function generateBook({ book, outputFolder, hasLiveReloading, Generator, reload }) { // Stop server if running if (reload) { book.getLogger().info.ok(`Clear cache`); (0, page_cache_1.clearCache)(); } return parse_1.default.parseBook(book).then((resultBook) => { if (hasLiveReloading) { // Enable livereload plugin let config = resultBook.getConfig(); // @ts-expect-error ts-migrate(2554) FIXME: Expected 3 arguments, but got 2. config = modifiers_1.default.Config.addPlugin(config, "livereload"); resultBook = resultBook.set("config", config); } return output_1.default.generate(Generator, resultBook, { root: outputFolder }); }); } function incrementalBuild({ output, Generator }) { return output_1.default.incrementalBuild(Generator, output); } exports.default = { name: "serve [book] [output]", description: "serve the book as a website for testing", options: [ { name: "port", description: "Port for server to listen on", defaults: 4000 }, { name: "lrport", description: "Port for livereload server to listen on", defaults: 35729 }, { name: "watch", description: "Enable file watcher and live reloading", defaults: true }, { name: "live", description: "Enable live reloading", defaults: true }, { name: "open", description: "Enable opening book in browser", defaults: false }, { name: "browser", description: "Specify browser for opening book", defaults: "" }, options_1.default.log, options_1.default.format, options_1.default.reload ], exec: function (args, kwargs) { server = new server_1.default(); const hasWatch = kwargs["watch"]; const hasLiveReloading = kwargs["live"]; return (0, promise_1.default)() .then(() => { if (!hasWatch || !hasLiveReloading) { return; } lrServer = (0, tiny_lr_1.default)({}); return promise_1.default.nfcall(lrServer.listen.bind(lrServer), kwargs.lrport).then(() => { console.log("Live reload server started on port:", kwargs.lrport); console.log("Press CTRL+C to quit ..."); console.log(""); }); }) .then(() => { return startServer(args, kwargs); }); } };