75 lines
2.1 KiB
TypeScript
75 lines
2.1 KiB
TypeScript
import { Plugin } from 'vite'
|
||
import fs from 'fs'
|
||
import path from 'path'
|
||
|
||
interface FileWatcherOptions {
|
||
// 目标可以是文件路径或文件夹路径
|
||
file: string;
|
||
// 回调函数,接收变化的文件路径、内容(如果有)和变化类型
|
||
fn: (filePath: string, content?: string, eventType?: 'add' | 'change' | 'unlink') => void;
|
||
// 防抖延迟,默认300ms
|
||
delay?: number;
|
||
}
|
||
|
||
export function fileWatcher(options: FileWatcherOptions): Plugin {
|
||
const {file, fn, delay = 300} = options
|
||
const targetPath = path.resolve(file)
|
||
let debounceTimer: NodeJS.Timeout | null = null
|
||
|
||
// 检查目标是否为文件夹
|
||
const isDir = fs.existsSync(targetPath) && fs.statSync(targetPath).isDirectory()
|
||
console.log('正在监听文件:' + targetPath)
|
||
return {
|
||
name: 'file-watcher-plugin',
|
||
|
||
configureServer(server) {
|
||
// 添加要监听的目标(文件或文件夹)
|
||
server.watcher.add(targetPath)
|
||
|
||
// 处理文件/文件夹变化的通用函数
|
||
const handleChange = (filePath: string, eventType: 'add' | 'change' | 'unlink') => {
|
||
if (isDir && !filePath.startsWith(targetPath)) {
|
||
return
|
||
}
|
||
if (!isDir && filePath !== targetPath) {
|
||
return
|
||
}
|
||
// 防抖处理
|
||
if (debounceTimer) {
|
||
clearTimeout(debounceTimer)
|
||
}
|
||
|
||
debounceTimer = setTimeout(async () => {
|
||
try {
|
||
let content: string | undefined
|
||
if (!isDir) {
|
||
content = fs.readFileSync(filePath, 'utf-8')
|
||
}
|
||
fn(filePath, content, eventType)
|
||
} catch (error) {
|
||
console.error('处理文件变化时出错:', error)
|
||
}
|
||
}, delay)
|
||
}
|
||
|
||
if (isDir) {
|
||
// 监听文件新增
|
||
server.watcher.on('add', (filePath) => {
|
||
handleChange(filePath, 'add')
|
||
})
|
||
|
||
// 监听文件删除
|
||
server.watcher.on('unlink', (filePath) => {
|
||
handleChange(filePath, 'unlink')
|
||
})
|
||
}
|
||
|
||
// 监听文件修改
|
||
server.watcher.on('change', (filePath) => {
|
||
handleChange(filePath, 'change')
|
||
})
|
||
|
||
},
|
||
}
|
||
}
|