Skip to content

Commit 049e238

Browse files
committed
feat: 添加对docs/challenges目录的热更新监控
1 parent 4675b92 commit 049e238

File tree

6 files changed

+195
-4
lines changed

6 files changed

+195
-4
lines changed

docs/challenges/测试热更新.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# 爬虫挑战合集元数据配置文件
2+
version: 1
3+
id: test-hot-reload
4+
name: 测试热更新功能
5+
difficulty: 1

docs/challenges/阿里滑块.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,7 @@ challenges:
9494
# 记录挑战最后修改时间,格式与create-time相同
9595
# 当任何字段变更时需同步更新此时间
9696
update-time: 2025-04-13 10:36:24
97+
# 测试热更新
98+
# 再次测试
99+
# 测试热更新3
100+
# 最终测试热更新

package-lock.json

Lines changed: 31 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
"@typescript-eslint/eslint-plugin": "5.62.0",
4545
"@typescript-eslint/parser": "5.62.0",
4646
"@vitejs/plugin-react": "^4.3.4",
47+
"chokidar": "^4.0.3",
4748
"eslint": "^8.57.0",
4849
"eslint-plugin-react": "^7.37.4",
4950
"gh-pages": "^6.3.0",

src/plugins/VirtualFileSystemPlugin.ts

Lines changed: 75 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -432,15 +432,30 @@ export default function virtualFileSystemPlugin(
432432
options: VirtualFileSystemPluginOptions
433433
): PluginOption {
434434
const { directory, outputPath = 'virtual-file-system.js' } = options;
435+
// 用于缓存已加载的YAML文件列表
436+
let cachedYamlFiles: string[] = [];
437+
438+
// 打印启动时的监控目录信息
439+
console.log(`[VirtualFileSystemPlugin] 监控目录: ${directory}`);
440+
console.log(`[VirtualFileSystemPlugin] 输出文件: ${outputPath}`);
435441

436442
return {
437443
name: 'virtual-file-system-plugin',
438444
buildStart() {
439445
// 在这里添加文件监听,当YAML文件或Markdown文件变更时重新构建
440446
if (fs.existsSync(directory)) {
441-
// 监听YAML文件
442-
const yamlFiles = getAllYamlFiles(directory);
443-
yamlFiles.forEach((file: string) => {
447+
console.log(`[VirtualFileSystemPlugin] 开始监控目录: ${directory}`);
448+
449+
// 监听整个目录,而不是单独的文件,这样能监控到新增文件
450+
this.addWatchFile(directory);
451+
452+
// 初始化时扫描一次所有YAML文件
453+
cachedYamlFiles = getAllYamlFiles(directory);
454+
console.log(`[VirtualFileSystemPlugin] 找到 ${cachedYamlFiles.length} 个YAML文件`);
455+
456+
// 监听所有YAML文件
457+
cachedYamlFiles.forEach((file: string) => {
458+
console.log(`[VirtualFileSystemPlugin] 添加监控: ${file}`);
444459
this.addWatchFile(file);
445460
});
446461

@@ -449,6 +464,8 @@ export default function virtualFileSystemPlugin(
449464
mdFiles.forEach((file: string) => {
450465
this.addWatchFile(file);
451466
});
467+
} else {
468+
console.warn(`[VirtualFileSystemPlugin] 警告: 目录 ${directory} 不存在`);
452469
}
453470
},
454471
resolveId(id) {
@@ -471,6 +488,16 @@ export default function virtualFileSystemPlugin(
471488
const isBuild = process.env.NODE_ENV === 'production' || this.meta?.watchMode === false;
472489
console.log(`VirtualFileSystemPlugin: Running in ${isBuild ? 'build' : 'development'} mode`);
473490

491+
// 每次加载时重新扫描所有YAML文件,确保能捕获到新增文件
492+
const currentYamlFiles = getAllYamlFiles(directory);
493+
const newFiles = currentYamlFiles.filter(file => !cachedYamlFiles.includes(file));
494+
495+
if (newFiles.length > 0) {
496+
console.log(`[VirtualFileSystemPlugin] 检测到 ${newFiles.length} 个新YAML文件`);
497+
// 将新文件添加到缓存
498+
cachedYamlFiles = [...cachedYamlFiles, ...newFiles];
499+
}
500+
474501
// 收集并处理YAML挑战和Markdown内容
475502
const rawChallenges = collectYAMLChallenges(directory, process.cwd(), isBuild);
476503
// 使用parseChallenges函数处理成正确的Challenge类型
@@ -482,6 +509,51 @@ export default function virtualFileSystemPlugin(
482509
}
483510
}
484511
return null;
512+
},
513+
handleHotUpdate(ctx) {
514+
// 检测热更新触发
515+
const { file, server } = ctx;
516+
517+
// 检查是否是docs/challenges目录下的YAML文件变更,或者是目录变更
518+
if (file.includes('docs/challenges')) {
519+
// 如果是YAML文件变更或目录变更,触发重新加载
520+
const isYamlFile = file.endsWith('.yml') || file.endsWith('.yaml');
521+
const isDirectory = fs.existsSync(file) && fs.statSync(file).isDirectory();
522+
523+
if (isYamlFile || isDirectory) {
524+
console.log(`[VirtualFileSystemPlugin] 热更新触发: ${file}`);
525+
526+
// 如果是文件变更,检查是否是新文件
527+
if (isYamlFile && !cachedYamlFiles.includes(file)) {
528+
console.log(`[VirtualFileSystemPlugin] 检测到新YAML文件: ${file}`);
529+
cachedYamlFiles.push(file);
530+
}
531+
532+
// 如果是目录变更,重新扫描目录以查找新文件
533+
if (isDirectory) {
534+
const currentYamlFiles = getAllYamlFiles(directory);
535+
const newFiles = currentYamlFiles.filter(f => !cachedYamlFiles.includes(f));
536+
537+
if (newFiles.length > 0) {
538+
console.log(`[VirtualFileSystemPlugin] 目录变更,检测到 ${newFiles.length} 个新YAML文件`);
539+
newFiles.forEach(newFile => {
540+
console.log(`[VirtualFileSystemPlugin] 添加新文件到缓存: ${newFile}`);
541+
cachedYamlFiles.push(newFile);
542+
});
543+
}
544+
}
545+
546+
// 强制模块失效,触发重新加载
547+
const mod = server.moduleGraph.getModuleById(`/${outputPath}`);
548+
if (mod) {
549+
server.moduleGraph.invalidateModule(mod);
550+
}
551+
552+
// 告知客户端刷新页面
553+
return ctx.modules;
554+
}
555+
}
556+
return;
485557
}
486558
};
487559
}

vite.config.ts

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import react from '@vitejs/plugin-react'
33
import virtualFileSystemPlugin from './src/plugins/VirtualFileSystemPlugin'
44
import path from 'path'
55
import fs from 'fs'
6+
import { Plugin } from 'vite'
7+
import chokidar from 'chokidar'
68

79
// 自定义插件:复制Markdown相关的资源文件到dist目录
810
function copyMarkdownAssetsPlugin() {
@@ -149,6 +151,75 @@ function getContentType(filePath: string): string {
149151
}
150152
}
151153

154+
// 创建一个监控docs/challenges目录变更的自定义插件
155+
function challengesWatchPlugin(): Plugin {
156+
const challengesDir = path.resolve(__dirname, 'docs/challenges');
157+
let watcher: any = null;
158+
159+
return {
160+
name: 'challenges-watch-plugin',
161+
configureServer(server) {
162+
// 首先打印监控路径信息,确认配置正确
163+
console.log(`[challenges-watch] 正在监控目录: ${challengesDir}`);
164+
165+
// 使用chokidar监控整个目录,以便检测新文件的创建
166+
console.log(`[challenges-watch] 监控目录: ${challengesDir}`);
167+
168+
// 创建单独的chokidar监控器,监控目录和所有YAML文件
169+
watcher = chokidar.watch([
170+
challengesDir, // 监控整个目录以检测新文件
171+
path.join(challengesDir, '**/*.yml'), // 监控所有YAML文件
172+
path.join(challengesDir, '**/*.yaml') // 监控所有YAML文件
173+
], {
174+
ignoreInitial: true, // 初始化时不触发事件
175+
persistent: true,
176+
ignorePermissionErrors: true,
177+
awaitWriteFinish: {
178+
stabilityThreshold: 100,
179+
pollInterval: 100
180+
},
181+
// 启用添加目录监控
182+
depth: 10, // 监控的目录深度
183+
alwaysStat: true // 提供更准确的文件信息
184+
});
185+
186+
// 监听所有文件事件
187+
watcher.on('all', (event: string, filePath: string) => {
188+
// 只处理YAML文件相关事件
189+
if (filePath.endsWith('.yml') || filePath.endsWith('.yaml')) {
190+
console.log(`[challenges-watch] YAML文件事件 ${event}: ${filePath}`);
191+
192+
// 通知客户端强制刷新
193+
server.moduleGraph.invalidateAll();
194+
server.ws.send({
195+
type: 'full-reload',
196+
path: '*'
197+
});
198+
} else if (event === 'addDir') {
199+
// 新增目录时打印日志
200+
console.log(`[challenges-watch] 新增目录: ${filePath}`);
201+
}
202+
});
203+
204+
// 输出正在监控的文件列表
205+
setTimeout(() => {
206+
const watchedPaths = watcher.getWatched();
207+
console.log('[challenges-watch] 已监控的文件/目录:', Object.keys(watchedPaths).length);
208+
for (const dir in watchedPaths) {
209+
console.log(`[challenges-watch] - ${dir}: ${watchedPaths[dir].length} 个文件`);
210+
}
211+
}, 1000);
212+
},
213+
closeBundle() {
214+
// 关闭watcher
215+
if (watcher) {
216+
watcher.close();
217+
watcher = null;
218+
}
219+
}
220+
};
221+
}
222+
152223
// https://vite.dev/config/
153224
export default defineConfig({
154225
base: '/crawler-leetcode/',
@@ -159,6 +230,13 @@ export default defineConfig({
159230
outputPath: 'virtual-challenges.js'
160231
}),
161232
copyMarkdownAssetsPlugin(),
162-
serveMarkdownAssetsPlugin()
233+
serveMarkdownAssetsPlugin(),
234+
// 添加自定义监控插件
235+
challengesWatchPlugin()
163236
],
237+
server: {
238+
watch: {
239+
// 移除ignored配置,改用默认配置
240+
}
241+
}
164242
})

0 commit comments

Comments
 (0)