From 2829a5965b6ce22fcd5eee05a54292e448e1d15b Mon Sep 17 00:00:00 2001 From: undefined Date: Thu, 20 Feb 2025 10:22:29 +0800 Subject: [PATCH] core: split hmr and watcher --- packages/hydrooj/src/entry/worker.ts | 3 +- .../src/service/{watcher.ts => hmr.ts} | 51 +++++-------------- packages/hydrooj/src/service/watch.ts | 31 +++++++++++ 3 files changed, 45 insertions(+), 40 deletions(-) rename packages/hydrooj/src/service/{watcher.ts => hmr.ts} (85%) create mode 100644 packages/hydrooj/src/service/watch.ts diff --git a/packages/hydrooj/src/entry/worker.ts b/packages/hydrooj/src/entry/worker.ts index cc259a582..e52856132 100644 --- a/packages/hydrooj/src/entry/worker.ts +++ b/packages/hydrooj/src/entry/worker.ts @@ -39,8 +39,7 @@ export async function apply(ctx: Context) { await modelSystem.runConfig(); const storage = require('../service/storage'); await storage.loadStorageService(); - // Make sure everything is ready and then start main entry - if (argv.options.watch) ctx.plugin(require('../service/watcher').default, {}); + ctx.plugin(require('../service/watcher').default, { watch: argv.options.watch }); await require('../service/worker').apply(ctx); await require('../service/server').apply(ctx); await require('../service/api').apply(ctx); diff --git a/packages/hydrooj/src/service/watcher.ts b/packages/hydrooj/src/service/hmr.ts similarity index 85% rename from packages/hydrooj/src/service/watcher.ts rename to packages/hydrooj/src/service/hmr.ts index 35427ded7..7e693dffe 100644 --- a/packages/hydrooj/src/service/watcher.ts +++ b/packages/hydrooj/src/service/hmr.ts @@ -3,9 +3,8 @@ /* eslint-disable import/no-dynamic-require */ /* eslint-disable @typescript-eslint/no-shadow */ import { readFileSync } from 'fs'; -import { relative, resolve, sep } from 'path'; +import { relative } from 'path'; import { codeFrameColumns } from '@babel/code-frame'; -import { FSWatcher, watch } from 'chokidar'; import { BuildFailure } from 'esbuild'; import { Context, Plugin, Service } from '../context'; import { Logger } from '../logger'; @@ -15,6 +14,9 @@ declare module '../context' { interface Events { 'hmr/reload': (reloads: Map }>) => void; } + interface Context { + hmr: HMR; + } } function isBuildFailure(e: any): e is BuildFailure { @@ -59,57 +61,30 @@ function loadDependencies(filename: string, ignored: Set) { return dependencies; } -const logger = new Logger('watch'); +const logger = new Logger('hmr'); -export default class Watcher extends Service { - private root: string; - private watcher: FSWatcher; +export default class HMR extends Service { + private root = process.cwd(); private externals: Set; private accepted: Set; private declined: Set; private stashed = new Set(); - constructor(public ctx: Context) { - super(ctx, 'watcher'); + constructor(public ctx: Context, config: { watch: boolean }) { + super(ctx, 'hmr'); this.externals = new Set(Object.keys(require.cache)); - } - - start() { - this.root = resolve(process.cwd()); - const roots = [this.root]; - if (process.env.WATCH_ROOT) roots.push(process.env.WATCH_ROOT); - this.watcher = watch(roots, { - ignored: (file) => [ - 'node_modules', '.git', 'logs', '.cache', '.yarn', 'tsconfig.tsbuildinfo', - ].some((rule) => file.startsWith(`${rule}/`) || file.endsWith(`/${rule}`) || file.includes(`/${rule}/`)), - }); - logger.info(`Start watching changes in ${this.root}`); - - // files independent from any plugins will trigger a full reload - const triggerLocalReload = this.ctx.debounce(() => this.triggerLocalReload(), 1000); - - this.watcher.on('change', (path) => { - if (path.includes(`${sep}.`)) return; - logger.debug('change detected:', relative(this.root, path)); - this.ctx.emit('app/watch/change', path); - + const debouncedReload = ctx.debounce(() => this.triggerLocalReload(), 1000); + this.ctx.on('app/watch/change', (path) => { if (this.externals.has(path)) { logger.warn('Require full reload'); } else if (require.cache[path]) { this.stashed.add(path); this.ctx.emit('app/before-reload', this.stashed); - triggerLocalReload(); + debouncedReload(); this.ctx.emit('app/reload', this.stashed); } }); - this.watcher.on('unlink', (path) => { - logger.debug('change detected:', `-${relative(this.root, path)}`); - this.ctx.emit('app/watch/unlink', path); - }); - } - - stop() { - return this.watcher.close(); + if (config.watch) ctx.plugin(require('./watch')); } private analyzeChanges() { diff --git a/packages/hydrooj/src/service/watch.ts b/packages/hydrooj/src/service/watch.ts new file mode 100644 index 000000000..b021e4f7d --- /dev/null +++ b/packages/hydrooj/src/service/watch.ts @@ -0,0 +1,31 @@ +import { relative, resolve, sep } from 'path'; +import { watch } from 'chokidar'; +import { Context } from '../context'; +import { Logger } from '../logger'; + +const logger = new Logger('watcher'); + +export const apply = (ctx: Context) => { + const root = resolve(process.cwd()); + const roots = [root]; + if (process.env.WATCH_ROOT) roots.push(process.env.WATCH_ROOT); + const watcher = watch(roots, { + ignored: (file) => [ + 'node_modules', '.git', 'logs', '.cache', '.yarn', 'tsconfig.tsbuildinfo', + ].some((rule) => file.startsWith(`${rule}/`) || file.endsWith(`/${rule}`) || file.includes(`/${rule}/`)), + }); + logger.info(`Start watching changes in ${root}`); + // files independent from any plugins will trigger a full reload + watcher.on('change', (path) => { + if (path.includes(`${sep}.`)) return; + logger.debug('change detected:', relative(root, path)); + ctx.emit('app/watch/change', path); + }); + watcher.on('unlink', (path) => { + logger.debug('change detected:', `-${relative(root, path)}`); + ctx.emit('app/watch/unlink', path); + }); + return () => { + watcher.close(); + }; +};