"use strict"; const budo = require("budo"); const defaultValue = require("default-value"); const assureArray = require("assure-array"); const path = require("path"); const entities = require("entities"); const stacked = require("stacked"); const injectLRScript = require("inject-lr-script"); function createExpressMiddleware(app, fullBundlePath) { let handler = stacked(); handler.use(injectLRScript({ local: true, path: "/budo/livereload.js" })); handler.use((req, res, next) => { // Ensure that we never intercept budo-served resources. Otherwise, the Express app might have something like a 404 handler or "always require login" middleware that stops requests for budo assets from ever coming out the other end of the Express app. if (req.url !== "/budo/livereload.js" && req.url !== `/${fullBundlePath}`) { app.handle(req, res, (err) => { if (err != null && err instanceof Error) { res .status(500) .set("content-type", "text/html") .send(`
${entities.escape(err.stack)}
`); } else { next(err); } }); } else { next(); } }); return handler; } module.exports = function ({ options, staticPath, staticBasePath, entryPaths, host }) { let middlewareList; let fullBundlePath = (options.staticPrefix != null) ? path.join(options.staticPrefix, options.bundlePath) : options.bundlePath; if (options.middleware != null) { middlewareList = assureArray(options.middleware).concat([ createExpressMiddleware(options.expressApp, fullBundlePath) ]); } else { middlewareList = [ createExpressMiddleware(options.expressApp, fullBundlePath) ]; } let budoOptions = { livePort: defaultValue(options.livereloadPort, 35729), stream: defaultValue(options.stream, process.stdout), port: options.port, host: host, dir: staticBasePath, serve: fullBundlePath, browserify: options.browserify, middleware: middlewareList, debug: defaultValue(options.sourceMaps, true), verbose: true }; let devServer = budo(entryPaths, budoOptions) .watch(staticPath(options.livereloadPattern), { awaitWriteFinish: { // NOTE: This is mostly just a hack to make sure that the process has time to get restarted (by eg. nodemon) before sending out a LiveReload update. Need to investigate whether there's a less hacky way to do this. stabilityThreshold: 130 } }) .live() .on("watch", (event, file) => { if (event === "change" || event === "add") { devServer.reload(file); } }) .on("pending", () => { // This event is called when the bundle is being regenerated, ie. after watchify has detected a change in the input files devServer.reload(fullBundlePath); }) .on("connect", (event) => { let reloadServer = event.webSocketServer; reloadServer.once("connection", (_socket) => { // This is to make sure the browser also reloads after the process has auto-restarted (eg. using `nodemon`) console.log("Triggering initial page refresh for new client..."); devServer.reload("*"); }); }); };