es-dev-server
Version:
Development server for modern web apps
153 lines • 5.69 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.getRequestFilePath = exports.isGeneratedFile = exports.isInlineScript = exports.shouldTransformToModule = exports.isPolyfill = exports.SSEStream = exports.toFilePath = exports.toBrowserPath = exports.getBodyAsString = exports.isUtf8 = exports.IsBinaryFileError = exports.RequestCancelledError = exports.logDebug = exports.setDebug = void 0;
const tslib_1 = require("tslib");
/* eslint-disable no-console, max-classes-per-file */
const is_stream_1 = tslib_1.__importDefault(require("is-stream"));
const get_stream_1 = tslib_1.__importDefault(require("get-stream"));
const stream_1 = tslib_1.__importDefault(require("stream"));
const path_1 = tslib_1.__importDefault(require("path"));
const mime_types_1 = tslib_1.__importDefault(require("mime-types"));
const isbinaryfile_1 = require("isbinaryfile");
const constants_1 = require("../constants");
let _debug = false;
function setDebug(debug) {
_debug = debug;
}
exports.setDebug = setDebug;
function logDebug(...messages) {
if (_debug) {
console.log('[es-dev-server]: ', ...messages.map(m => JSON.stringify(m)));
}
}
exports.logDebug = logDebug;
class RequestCancelledError extends Error {
}
exports.RequestCancelledError = RequestCancelledError;
class IsBinaryFileError extends Error {
}
exports.IsBinaryFileError = IsBinaryFileError;
/**
* koa-static stores the original served file path on ctx.body.path,
* we need this path for file transformation but we overwrite body
* with a string, so we keep a reference with a weakmap
*/
const filePathsForRequests = new WeakMap();
function isUtf8(context) {
const charSet = mime_types_1.default.charset(context.response.get('content-type'));
return charSet === false ? false : charSet.toLowerCase() === 'utf-8';
}
exports.isUtf8 = isUtf8;
/**
* Returns the body value as string. If the response is a stream, the
* stream is drained and the result is returned. Because koa-static stores
* a path variable on the stream, we need to create a new stream with
* the same variable to preserve correct behavior.
*
*/
async function getBodyAsString(ctx) {
let requestCanceled;
ctx.req.on('close', () => {
requestCanceled = true;
});
if (Buffer.isBuffer(ctx.body)) {
return ctx.body.toString();
}
if (typeof ctx.body === 'string') {
return ctx.body;
}
if (is_stream_1.default(ctx.body)) {
// cache request path, see above
// @ts-ignore
if (ctx.body.path) {
// @ts-ignore
filePathsForRequests.set(ctx.request, ctx.body.path);
}
// a stream can only be read once, so after reading it assign
// the string response to the body so that it can be accessed
// again later
try {
const bodyBuffer = await get_stream_1.default.buffer(ctx.body);
const contentLength = Number(ctx.response.get('content-length'));
if (await isbinaryfile_1.isBinaryFile(bodyBuffer, contentLength)) {
ctx.body = bodyBuffer;
throw new IsBinaryFileError();
}
const bodyString = bodyBuffer.toString();
ctx.body = bodyString;
return bodyString;
}
catch (error) {
if (requestCanceled) {
throw new RequestCancelledError();
}
throw error;
}
}
return ctx.body;
}
exports.getBodyAsString = getBodyAsString;
/**
* Turns a file path into a path suitable for browsers, with a / as seperator.
* @param {string} filePath
* @returns {string}
*/
function toBrowserPath(filePath) {
return filePath.replace(new RegExp(path_1.default.sep === '\\' ? '\\\\' : path_1.default.sep, 'g'), '/');
}
exports.toBrowserPath = toBrowserPath;
/**
* Transforms a file system path to a browser URL. For example windows uses `\` on the file system,
* but it should use `/` in the browser.
*/
function toFilePath(browserPath) {
return browserPath.replace(new RegExp('/', 'g'), path_1.default.sep);
}
exports.toFilePath = toFilePath;
class SSEStream extends stream_1.default.Transform {
sendMessage(name, data = '') {
this.write(`event: ${name}\ndata: ${data}\n\n`);
}
_transform(data, enc, cb) {
this.push(data.toString());
cb();
}
}
exports.SSEStream = SSEStream;
function isPolyfill(url) {
return url.includes('/polyfills/');
}
exports.isPolyfill = isPolyfill;
function shouldTransformToModule(url) {
return url.includes('transform-systemjs');
}
exports.shouldTransformToModule = shouldTransformToModule;
function isInlineScript(url) {
return url.includes(`inline-script-`) && url.includes('?source=');
}
exports.isInlineScript = isInlineScript;
/**
* Returns whether this is a file generated generated by the dev server
*/
function isGeneratedFile(url) {
return url.startsWith(constants_1.virtualFilePrefix) || isPolyfill(url) || isInlineScript(url);
}
exports.isGeneratedFile = isGeneratedFile;
function getRequestFilePath(ctx, rootDir) {
if (isPolyfill(ctx.url)) {
return null;
}
// inline module requests have the source in a query string
if (isInlineScript(ctx.url)) {
const url = ctx.url.split('?')[0];
const indexPath = toFilePath(url);
return path_1.default.join(rootDir, indexPath);
}
// otherwise koa-static adds the original file path on the body
if (ctx.body && ctx.body.path) {
return ctx.body.path;
}
return filePathsForRequests.get(ctx.request) || null;
}
exports.getRequestFilePath = getRequestFilePath;
//# sourceMappingURL=utils.js.map