forked from joepie91/budo-express
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
121 lines
3.6 KiB
JavaScript
121 lines
3.6 KiB
JavaScript
"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 util = require("util");
|
|
|
|
let reloadClientTag = Buffer.from("<script src=\"/budo/livereload.js\"></script>");
|
|
|
|
function monkeyPatchEnd(res) {
|
|
// NOTE: This is a hack, to auto-inject the Budo livereload client in any outgoing HTML response (but only in development mode).
|
|
let end = res.end.bind(res);
|
|
|
|
res.end = function monkeyPatchedEnd(... args) {
|
|
let originalChunk = args[0];
|
|
let prefix;
|
|
|
|
if (originalChunk == null || typeof originalChunk === "string" || Buffer.isBuffer(originalChunk)) {
|
|
if (!res.headersSent) {
|
|
// If headers have already been sent, we'll just have to hope that the browser will still look at our appended tag, as we can't change the response size anymore...
|
|
// TODO: Make this more robust in the future
|
|
let typeHeader = res.getHeader("content-type");
|
|
|
|
if (typeHeader != null && typeHeader.startsWith("text/html")) {
|
|
let contentLength = res.getHeader("content-length");
|
|
|
|
if (contentLength != null) {
|
|
// Compensate for the additional bytes introduced by our injected script tag
|
|
res.setHeader("content-length", parseInt(contentLength) + reloadClientTag.length);
|
|
}
|
|
|
|
prefix = reloadClientTag;
|
|
}
|
|
}
|
|
|
|
// Reset the `end` method back to the original method; we don't need to get in the way anymore
|
|
res.end = end;
|
|
|
|
let originalChunkAsBuffer = (typeof originalChunk === "string")
|
|
? Buffer.from(originalChunk)
|
|
: originalChunk;
|
|
|
|
if (prefix != null) {
|
|
let chunk = (originalChunkAsBuffer == null)
|
|
? reloadClientTag
|
|
: Buffer.concat([ originalChunkAsBuffer, reloadClientTag ]);
|
|
|
|
end(chunk, ... args.slice(1));
|
|
} else {
|
|
end(... args);
|
|
}
|
|
} else {
|
|
throw new Error(`Expected a buffer or string in 'end', but got something else: ${util.inspect(args[0])}`);
|
|
}
|
|
};
|
|
}
|
|
|
|
function createExpressMiddleware(app) {
|
|
return function expressMiddleware(req, res, next) {
|
|
try {
|
|
monkeyPatchEnd(res);
|
|
} catch (error) {
|
|
process.nextTick(() => {
|
|
throw error;
|
|
});
|
|
}
|
|
|
|
app.handle(req, res, (err) => {
|
|
if (err != null && err instanceof Error) {
|
|
res
|
|
.status(500)
|
|
.send(`${reloadClientTag}<pre>${entities.escape(err.stack)}</pre>`);
|
|
} else {
|
|
next(err);
|
|
}
|
|
});
|
|
};
|
|
}
|
|
|
|
module.exports = function ({ options, staticPath, staticBasePath, entryPaths, host }) {
|
|
let middlewareList;
|
|
|
|
if (options.middleware != null) {
|
|
middlewareList = assureArray(options.middleware).concat([
|
|
createExpressMiddleware(options.expressApp)
|
|
]);
|
|
} else {
|
|
middlewareList = [
|
|
createExpressMiddleware(options.expressApp)
|
|
];
|
|
}
|
|
|
|
let budoOptions = {
|
|
watchGlob: staticPath(options.livereloadPattern),
|
|
live: options.livereloadPattern,
|
|
livePort: defaultValue(options.livereloadPort, 35729),
|
|
stream: defaultValue(options.stream, process.stdout),
|
|
port: options.port,
|
|
host: host,
|
|
dir: staticBasePath,
|
|
serve: (options.staticPrefix != null)
|
|
? path.join(options.staticPrefix, options.bundlePath)
|
|
: options.bundlePath,
|
|
browserify: options.browserify,
|
|
middleware: middlewareList,
|
|
debug: defaultValue(options.sourceMaps, true),
|
|
};
|
|
|
|
let devServer = budo(entryPaths, budoOptions).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("*");
|
|
});
|
|
});
|
|
};
|