UNPKG

kite-framework

Version:

Modern, fast, flexible HTTP-JSON-RPC framework

163 lines (162 loc) 6.01 kB
"use strict"; /*** * Copyright (c) 2017 [Arthur Xie] * <https://github.com/kite-js/kite> * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.WatchService = void 0; const fs = require("fs"); const path = require("path"); /** * Watch service for watching file (controllers, services, and related files) */ class WatchService { /** * Watch service for watching file (controllers, services, and related files) changes * * If service is `enabled`, every file change event will cause a module deletion from NodeJS `require.cache`, * the module will be loaded with changed content next time. * * This service will watch for all files recursively, if a file in set to be watched, it's children module * will be also watched, except: * - files in 'node_modules' * - files in Kite's root (in case of someone use Kite as a lib out of NodeJS module) */ constructor(kiteroot, interval = 2000) { this.kiteroot = kiteroot; this.interval = interval; this.node_modules = path.sep + 'node_modules' + path.sep; // enabled ? this.enable() : this.disable(); } /** * Enable watching service */ setEnabled(enabled) { if (enabled) { this.enabled = true; if (!this.watching) { this.watching = new Map(); this.logService.info('Watching for file changes'); } } else { this.enabled = false; if (this.watching) { this.watching.forEach((callback, filename) => { fs.unwatchFile(filename); }); } delete this.watching; } } /** * Watch a file, if change detected, reload it * * Please note that this watcher is only works with node modules */ watch(filename, callback) { // skip if: // 1. service not enabled // 2. file is under "node_modules" // 3. file is a kite module if (!this.enabled || filename.includes(this.node_modules) || filename.startsWith(this.kiteroot + path.sep)) { return; } // if a file is being watched, update callback function if (this.watching.has(filename)) { // update callback if set if (callback) { this.watching.set(filename, callback); } return; } const workdirLen = this.workDir && this.workDir.length; const dirname = path.parse(this.workDir).name; fs.watchFile(filename, { interval: this.interval }, () => { let shortfn = filename; if (workdirLen && filename.startsWith(this.workDir)) { shortfn = dirname + filename.substr(workdirLen); } this.logService.info(`Change detected at "${shortfn}"`); this.clearCache(filename); }); this.watching.set(filename, callback); require.cache[filename].children.forEach((mod) => { this.watch(mod.filename); }); } /** * Clear node require cache, it's also search for parent modules, if parent modules are being watched, remove them too * @param filename filename to clear */ clearCache(filename) { let removeList = new Set(); removeList.add(filename); let findRelated = (filenames) => { let removeWork = new Set(); for (const filename of this.watching.keys()) { if (removeList.has(filename)) { continue; } require.cache[filename].children.every(child => { if (filenames.includes(child.filename)) { removeWork.add(filename); removeList.add(filename); return false; } return true; }); } // for (const key of Object.keys(require.cache)) { // let mod = require.cache[key] as NodeModule; // // Only find managed files // if (!this.watching.has(mod.filename) || removeList.has(mod.filename)) { // continue; // } // mod.children.every(child => { // if (filenames.includes(child.filename)) { // removeWork.add(mod.filename); // removeList.add(mod.filename); // return false; // } // return true; // }); // } if (removeWork.size) { findRelated(Array.from(removeWork)); } }; findRelated([filename]); for (const moduleFilename of removeList) { let callback = this.watching.get(moduleFilename); this.watching.delete(moduleFilename); delete require.cache[moduleFilename]; fs.unwatchFile(moduleFilename); if (callback) { callback(moduleFilename); } } } /** * Print out what is being watched */ printWatching() { console.log(this.watching.keys()); } setWorkDir(dir) { this.workDir = dir; } } exports.WatchService = WatchService;