2021-03-01 15:06:11 +08:00

126 lines
4.9 KiB
JavaScript

"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.watchFileIfOutOfRoot = exports.lookupFile = exports.readBody = exports.cachedRead = void 0;
const path_1 = __importDefault(require("path"));
const fs_extra_1 = __importDefault(require("fs-extra"));
const lru_cache_1 = __importDefault(require("lru-cache"));
const stream_1 = require("stream");
const serverPluginServeStatic_1 = require("../server/serverPluginServeStatic");
const mime_types_1 = __importDefault(require("mime-types"));
const getETag = require('etag');
const fsReadCache = new lru_cache_1.default({
max: 10000
});
/**
* Read a file with in-memory cache.
* Also sets appropriate headers and body on the Koa context.
* This is exposed on middleware context as `ctx.read` with the `ctx` already
* bound, so it can be used as `ctx.read(file)`.
*/
async function cachedRead(ctx, file) {
const lastModified = fs_extra_1.default.statSync(file).mtimeMs;
const cached = fsReadCache.get(file);
if (ctx) {
ctx.set('Cache-Control', 'no-cache');
ctx.type = mime_types_1.default.lookup(path_1.default.extname(file)) || 'application/octet-stream';
}
if (cached && cached.lastModified === lastModified) {
if (ctx) {
// a private marker in case the user ticks "disable cache" during dev
ctx.__notModified = true;
ctx.etag = cached.etag;
ctx.lastModified = new Date(cached.lastModified);
if (ctx.get('If-None-Match') === ctx.etag && serverPluginServeStatic_1.seenUrls.has(ctx.url)) {
ctx.status = 304;
}
serverPluginServeStatic_1.seenUrls.add(ctx.url);
ctx.body = cached.content;
}
return cached.content;
}
// #395 some file is an binary file, eg. font
let content = await fs_extra_1.default.readFile(file);
// Populate the "sourcesContent" array and resolve relative paths in the
// "sources" array, so the debugger can trace back to the original source.
if (file.endsWith('.map')) {
const map = JSON.parse(content.toString('utf8'));
if (!map.sourcesContent || !map.sources.every(path_1.default.isAbsolute)) {
const sourcesContent = map.sourcesContent || [];
map.sources = await Promise.all(map.sources.map(async (source, i) => {
const originalPath = path_1.default.resolve(path_1.default.dirname(file), source);
if (!sourcesContent[i]) {
const originalCode = await cachedRead(null, originalPath);
sourcesContent[i] = originalCode.toString('utf8');
}
return originalPath;
}));
map.sourcesContent = sourcesContent;
content = Buffer.from(JSON.stringify(map));
}
}
const etag = getETag(content);
fsReadCache.set(file, {
content,
etag,
lastModified
});
if (ctx) {
ctx.etag = etag;
ctx.lastModified = new Date(lastModified);
ctx.body = content;
ctx.status = 200;
// watch the file if it's out of root.
const { root, watcher } = ctx;
watchFileIfOutOfRoot(watcher, root, file);
}
return content;
}
exports.cachedRead = cachedRead;
/**
* Read already set body on a Koa context and normalize it into a string.
* Useful in post-processing middlewares.
*/
async function readBody(stream) {
if (stream instanceof stream_1.Readable) {
return new Promise((resolve, reject) => {
let res = '';
stream
.on('data', (chunk) => (res += chunk))
.on('error', reject)
.on('end', () => {
resolve(res);
});
});
}
else {
return !stream || typeof stream === 'string' ? stream : stream.toString();
}
}
exports.readBody = readBody;
function lookupFile(dir, formats, pathOnly = false) {
for (const format of formats) {
const fullPath = path_1.default.join(dir, format);
if (fs_extra_1.default.existsSync(fullPath) && fs_extra_1.default.statSync(fullPath).isFile()) {
return pathOnly ? fullPath : fs_extra_1.default.readFileSync(fullPath, 'utf-8');
}
}
const parentDir = path_1.default.dirname(dir);
if (parentDir !== dir) {
return lookupFile(parentDir, formats, pathOnly);
}
}
exports.lookupFile = lookupFile;
/**
* Files under root are watched by default, but with user aliases we can still
* serve files out of root. Add such files to the watcher (if not node_modules)
*/
function watchFileIfOutOfRoot(watcher, root, file) {
if (!file.startsWith(root) && !/node_modules/.test(file)) {
watcher.add(file);
}
}
exports.watchFileIfOutOfRoot = watchFileIfOutOfRoot;
//# sourceMappingURL=fsUtils.js.map