UNPKG

es-dev-server

Version:

Development server for modern web apps

111 lines 4.06 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.addToCache = exports.tryServeFromCache = exports.createResponseBodyCache = void 0; const tslib_1 = require("tslib"); const fs_1 = tslib_1.__importDefault(require("fs")); const lru_cache_1 = tslib_1.__importDefault(require("lru-cache")); const util_1 = require("util"); const utils_1 = require("./utils/utils"); const stat = util_1.promisify(fs_1.default.stat); /** * Cache by user agent + file path, so that there can be unique transforms * per browser. */ function createCacheKey(context) { return `${context.get('user-agent')}${context.url}`; } async function getLastModified(path) { try { return (await stat(path)).mtimeMs; } catch (error) { return -1; } } function createResponseBodyCache(cfg, fileWatcher) { /** @type {Map<String, String>} */ const cacheKeysForFilePaths = new Map(); const cache = new lru_cache_1.default({ length: (e, key) => e.body.length + (key ? key.length : 0), max: 52428800, // don't call dispose on overwriting noDisposeOnSet: true, // remove file path -> url mapping when we are no longer caching it dispose(cacheKey) { for (const [filePath, cacheKeyForFilePath] of cacheKeysForFilePaths.entries()) { if (cacheKeyForFilePath === cacheKey) { cacheKeysForFilePaths.delete(filePath); return; } } }, }); // remove file from cache on change fileWatcher.addListener('change', e => { const cacheKey = cacheKeysForFilePaths.get(e); if (cacheKey) { cache.del(cacheKey); } }); return { cache, cacheKeysForFilePaths }; } exports.createResponseBodyCache = createResponseBodyCache; async function tryServeFromCache(cache, context) { /** @type {string} */ let servingFromCache = false; const cacheKey = createCacheKey(context); const cached = cache.get(cacheKey); if (cached) { // we watch files, and remove them on change, but there can be edge cases // where these events do not come through properly (the file system is a 'live' system) // we double check the last modified timestamp first if (cached.lastModified === (await getLastModified(cached.filePath))) { context.body = cached.body; context.response.set(cached.headers); context.status = 200; servingFromCache = true; utils_1.logDebug(`Serving from response body cache: ${context.url}`); } else { // remove file from cache if it changed in the meantime, and serve regularly cache.del(cacheKey); } } return { cacheKey, context, cached: servingFromCache, cachedBody: cached === null || cached === void 0 ? void 0 : cached.body }; } exports.tryServeFromCache = tryServeFromCache; async function addToCache(config) { const { cache, cacheKey, cacheKeysForFilePaths, context, cfg } = config; if (context.method !== 'GET' || !context.body) { return; } if (context.status !== 200) { return; } if (utils_1.isGeneratedFile(context.url) || !context.response.is('js')) { return; } try { const body = await utils_1.getBodyAsString(context); const filePath = utils_1.getRequestFilePath(context, cfg.rootDir); if (!filePath) { return; } cacheKeysForFilePaths.set(filePath, context.url); cache.set(cacheKey, { body, headers: context.response.headers, filePath, lastModified: await getLastModified(filePath), }); utils_1.logDebug(`Adding to response body cache: ${context.url}`); } catch (error) { if (error instanceof utils_1.RequestCancelledError) { return; } throw error; } } exports.addToCache = addToCache; //# sourceMappingURL=response-body-cache.js.map