UNPKG

reboost

Version:

A super fast dev server for rapid web development

229 lines (228 loc) 10.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.initCache = void 0; const tslib_1 = require("tslib"); const md5_file_1 = (0, tslib_1.__importDefault)(require("md5-file")); const chalk_1 = (0, tslib_1.__importDefault)(require("chalk")); // @ts-expect-error No need to install declaration const hash_sum_1 = (0, tslib_1.__importDefault)(require("hash-sum")); const fs_1 = (0, tslib_1.__importDefault)(require("fs")); const path_1 = (0, tslib_1.__importDefault)(require("path")); const utils_1 = require("./utils"); const initCache = (config, plugins, log) => { let unsavedCacheInfos = {}; const noop = () => { }; const getCurrentVersion = () => { const { version } = JSON.parse(fs_1.default.readFileSync(path_1.default.resolve(__dirname, '../../package.json'), 'utf8')); return version; }; const versionFilePath = () => path_1.default.join(config.cacheDir, 'version'); const cacheIDsFilePath = () => path_1.default.join(config.cacheDir, 'cache_id_map.json'); const dependentsDataFilePath = () => path_1.default.join(config.cacheDir, 'dependents_data.json'); const memoized = { cacheVersion: undefined, cacheIDs: undefined, dependentsData: undefined }; const needsSave = { cacheVersion: false, cacheIDs: false, dependentsData: false, }; const it = { getFilesDir: () => path_1.default.join(config.cacheDir, 'files'), cacheFilePath: (cacheID) => path_1.default.join(it.getFilesDir(), cacheID + (config.debugMode ? '.js' : '')), sourceMapPath: (cacheID) => path_1.default.join(it.getFilesDir(), cacheID + (config.debugMode ? '.js' : '') + '.map'), cacheInfoFilePath: (cacheID) => path_1.default.join(it.getFilesDir(), cacheID + '.json'), getCurrentPlugins: () => { return plugins .filter((p) => p && p.name) .map((p) => { let id = p.name; if (typeof p.getCacheKey === 'function') { const cacheKey = p.getCacheKey({ serializeObject: utils_1.serializeObject }) + ''; id += '@' + (cacheKey.length > 6 ? (0, hash_sum_1.default)(cacheKey) : cacheKey); } else { log('info', chalk_1.default.yellow(`Required hook "getCacheKey" is not implemented in ${p.name}`)); } return id; }) .join(' && '); }, get version() { if (!memoized.cacheVersion) { memoized.cacheVersion = fs_1.default.existsSync(versionFilePath()) ? fs_1.default.readFileSync(versionFilePath(), 'utf8') : getCurrentVersion(); needsSave.cacheVersion = true; } return memoized.cacheVersion; }, get cacheIDs() { if (!memoized.cacheIDs) { const cacheIDs = fs_1.default.existsSync(cacheIDsFilePath()) ? JSON.parse(fs_1.default.readFileSync(cacheIDsFilePath(), 'utf8')) : {}; memoized.cacheIDs = (0, utils_1.observable)(cacheIDs, () => { needsSave.cacheIDs = true; }); } return memoized.cacheIDs; }, get dependentsData() { if (!memoized.dependentsData) { const dependentsData = fs_1.default.existsSync(dependentsDataFilePath()) ? JSON.parse(fs_1.default.readFileSync(dependentsDataFilePath(), 'utf8')) : {}; memoized.dependentsData = (0, utils_1.observable)(dependentsData, () => { needsSave.dependentsData = true; }); } return memoized.dependentsData; }, cacheInfo: new Proxy({}, { get: (cacheInfos, cacheID) => { if (!cacheInfos[cacheID]) { const cacheInfo = JSON.parse(fs_1.default.readFileSync(it.cacheInfoFilePath(cacheID), 'utf8')); cacheInfos[cacheID] = (0, utils_1.observable)(cacheInfo, () => { unsavedCacheInfos[cacheID] = cacheInfo; }); } return cacheInfos[cacheID]; }, set: (cacheInfos, cacheID, cacheInfo) => { if (typeof cacheInfo === 'undefined') { cacheInfos[cacheID] = undefined; return true; } cacheInfos[cacheID] = (0, utils_1.observable)(cacheInfo, () => { unsavedCacheInfos[cacheID] = cacheInfo; }); unsavedCacheInfos[cacheID] = cacheInfo; return true; } }), saveData: () => { const stringify = (json) => JSON.stringify(json, null, config.debugMode ? 2 : 0); if (needsSave.cacheVersion) { fs_1.default.writeFileSync(versionFilePath(), it.version); needsSave.cacheVersion = false; } if (needsSave.cacheIDs) { fs_1.default.writeFileSync(cacheIDsFilePath(), stringify(it.cacheIDs)); needsSave.cacheIDs = false; } if (needsSave.dependentsData) { fs_1.default.writeFileSync(dependentsDataFilePath(), stringify(it.dependentsData)); needsSave.dependentsData = false; } Object.keys(unsavedCacheInfos).forEach((cacheID) => { fs_1.default.writeFileSync(it.cacheInfoFilePath(cacheID), stringify(unsavedCacheInfos[cacheID])); }); unsavedCacheInfos = {}; }, removeFile: (file) => { const cacheID = it.cacheIDs[file]; if (cacheID) { it.cacheIDs[file] = undefined; it.cacheInfo[cacheID] = undefined; fs_1.default.unlink(it.cacheFilePath(cacheID), noop); fs_1.default.unlink(it.cacheInfoFilePath(cacheID), noop); if (fs_1.default.existsSync(it.sourceMapPath(cacheID))) { fs_1.default.unlink(it.sourceMapPath(cacheID), noop); } } }, removeDependents: (dependency) => { const dependentsData = it.dependentsData; const dependents = dependentsData[dependency]; if (dependents) { dependentsData[dependency] = undefined; dependents.forEach((dependent) => it.removeFile(dependent)); } }, verifyFiles: () => { if (fs_1.default.existsSync(it.getFilesDir())) { const files = Object.keys(it.cacheIDs); files.forEach((file) => { if (!fs_1.default.existsSync(file)) it.removeFile(file); }); const dependencies = Object.keys(it.dependentsData); dependencies.forEach((dependency) => { if (!fs_1.default.existsSync(dependency)) it.removeDependents(dependency); }); } it.saveData(); }, hasDependenciesChanged: async (file) => { const deps = it.cacheInfo[it.cacheIDs[file]].dependencies; if (!deps) return false; for (const dependency in deps) { try { const dependencyMeta = deps[dependency]; const currentMtime = Math.floor(fs_1.default.statSync(dependency).mtimeMs); if (dependencyMeta.mtime === currentMtime) continue; const currentHash = await (0, md5_file_1.default)(dependency); if (dependencyMeta.hash !== currentHash) return true; } catch (e) { // Probably the `fs.statSync` function caused error if // the dependency file is unavailable return true; } } return false; }, updateDependencies: async (filePath, dependencies, firstTime = false) => { const dependentsData = it.dependentsData; const cacheInfo = it.cacheInfo[it.cacheIDs[filePath]]; let added; let removed; if (firstTime) { added = dependencies; removed = []; } else { const prevDeps = Object.keys(cacheInfo.dependencies || {}); ({ added, removed } = (0, utils_1.diff)(prevDeps, dependencies)); } added.forEach((dependency) => { const dependents = dependentsData[dependency] || []; if (!dependents.includes(filePath)) dependents.push(filePath); dependentsData[dependency] = dependents; }); removed.forEach((dependency) => { if (dependentsData[dependency]) { const dependents = dependentsData[dependency] || []; // Remove current file from dependents const filtered = dependents.filter((dependent) => dependent !== filePath); dependentsData[dependency] = filtered.length ? filtered : undefined; } }); if (dependencies.length === 0) return cacheInfo.dependencies = undefined; const depsData = {}; await Promise.all(dependencies.map(async (dependency) => { if (fs_1.default.existsSync(dependency)) { depsData[dependency] = { hash: await (0, md5_file_1.default)(dependency), mtime: Math.floor(fs_1.default.statSync(dependency).mtimeMs) }; } else { depsData[dependency] = {}; } })); cacheInfo.dependencies = depsData; } }; return it; }; exports.initCache = initCache;