zen-gitsync 2.5.3 → 2.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +148 -148
- package/package.json +1 -1
- package/src/ui/public/assets/index-BlZI1-J0.js +59 -0
- package/src/ui/public/assets/{index-BApDCqKk.css → index-D0V6ggoJ.css} +1 -1
- package/src/ui/public/assets/vendor-D9qDBEE1.css +1 -0
- package/src/ui/public/assets/vendor-TIhvVDcs.js +68 -0
- package/src/ui/public/index.html +17 -16
- package/src/ui/server/index.js +341 -53
- package/src/ui/public/assets/index-CnCbYqLq.js +0 -59
- package/src/ui/public/assets/vendor-Dys2BbyU.js +0 -75
- package/src/ui/public/assets/vendor-HJmoQ7iQ.css +0 -1
package/src/ui/public/index.html
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html lang="
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8" />
|
|
5
|
-
<
|
|
6
|
-
<
|
|
7
|
-
<
|
|
8
|
-
<
|
|
9
|
-
<
|
|
10
|
-
<link rel="
|
|
11
|
-
<link rel="stylesheet" crossorigin href="/assets/
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
</
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="zh-CN" translate="no">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="google" content="notranslate" />
|
|
6
|
+
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
7
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
8
|
+
<title>Zen-GitSync - Git同步工具</title>
|
|
9
|
+
<script type="module" crossorigin src="/assets/index-BlZI1-J0.js"></script>
|
|
10
|
+
<link rel="modulepreload" crossorigin href="/assets/vendor-TIhvVDcs.js">
|
|
11
|
+
<link rel="stylesheet" crossorigin href="/assets/vendor-D9qDBEE1.css">
|
|
12
|
+
<link rel="stylesheet" crossorigin href="/assets/index-D0V6ggoJ.css">
|
|
13
|
+
</head>
|
|
14
|
+
<body>
|
|
15
|
+
<div id="app"></div>
|
|
16
|
+
</body>
|
|
17
|
+
</html>
|
package/src/ui/server/index.js
CHANGED
|
@@ -625,8 +625,11 @@ async function startUIServer(noOpen = false, savePort = false) {
|
|
|
625
625
|
newProjectRoomId: newProjectRoomId
|
|
626
626
|
});
|
|
627
627
|
|
|
628
|
-
//
|
|
629
|
-
|
|
628
|
+
// 不再自动启动文件监控,只在用户手动开启自动更新开关时启动
|
|
629
|
+
// console.log('[切换目录] 将在3秒后初始化文件监控器');
|
|
630
|
+
// setTimeout(() => {
|
|
631
|
+
// initFileSystemWatcher().catch(err => console.error('[文件监控] 初始化失败:', err));
|
|
632
|
+
// }, 3000);
|
|
630
633
|
|
|
631
634
|
res.json({
|
|
632
635
|
success: true,
|
|
@@ -1973,9 +1976,28 @@ async function startUIServer(noOpen = false, savePort = false) {
|
|
|
1973
1976
|
return res.status(400).json({ error: '缺少文件路径参数' });
|
|
1974
1977
|
}
|
|
1975
1978
|
|
|
1979
|
+
// 检查是否是编译/压缩文件(通常很大且不需要查看diff)
|
|
1980
|
+
const isCompiledFile = /\.(min\.js|umd\.cjs|bundle\.js|dist\.js|prod\.js)$/i.test(filePath);
|
|
1981
|
+
if (isCompiledFile) {
|
|
1982
|
+
return res.json({
|
|
1983
|
+
diff: '⚠️ 检测到编译/打包文件,diff内容过大已跳过显示。\n\n提示:这类文件通常是自动生成的,不建议查看diff。\n如需查看,请使用命令行:git diff -- "' + filePath + '"',
|
|
1984
|
+
isLargeFile: true
|
|
1985
|
+
});
|
|
1986
|
+
}
|
|
1987
|
+
|
|
1976
1988
|
// 执行git diff命令获取文件差异
|
|
1977
1989
|
const { stdout } = await execGitCommand(`git diff -- "${filePath}"`);
|
|
1978
1990
|
|
|
1991
|
+
// 检查diff大小,如果超过500KB,只返回提示
|
|
1992
|
+
const diffSizeKB = Buffer.byteLength(stdout, 'utf8') / 1024;
|
|
1993
|
+
if (diffSizeKB > 500) {
|
|
1994
|
+
return res.json({
|
|
1995
|
+
diff: `⚠️ Diff内容过大 (${diffSizeKB.toFixed(1)}KB),已跳过显示以避免浏览器卡顿。\n\n提示:请使用命令行查看:git diff -- "${filePath}"`,
|
|
1996
|
+
isLargeFile: true,
|
|
1997
|
+
size: diffSizeKB
|
|
1998
|
+
});
|
|
1999
|
+
}
|
|
2000
|
+
|
|
1979
2001
|
res.json({ diff: stdout });
|
|
1980
2002
|
} catch (error) {
|
|
1981
2003
|
res.status(500).json({ error: error.message });
|
|
@@ -1990,9 +2012,28 @@ async function startUIServer(noOpen = false, savePort = false) {
|
|
|
1990
2012
|
return res.status(400).json({ error: '缺少文件路径参数' });
|
|
1991
2013
|
}
|
|
1992
2014
|
|
|
2015
|
+
// 检查是否是编译/压缩文件
|
|
2016
|
+
const isCompiledFile = /\.(min\.js|umd\.cjs|bundle\.js|dist\.js|prod\.js)$/i.test(filePath);
|
|
2017
|
+
if (isCompiledFile) {
|
|
2018
|
+
return res.json({
|
|
2019
|
+
diff: '⚠️ 检测到编译/打包文件,diff内容过大已跳过显示。\n\n提示:这类文件通常是自动生成的,不建议查看diff。\n如需查看,请使用命令行:git diff --cached -- "' + filePath + '"',
|
|
2020
|
+
isLargeFile: true
|
|
2021
|
+
});
|
|
2022
|
+
}
|
|
2023
|
+
|
|
1993
2024
|
// 执行git diff --cached命令获取已暂存文件差异
|
|
1994
2025
|
const { stdout } = await execGitCommand(`git diff --cached -- "${filePath}"`);
|
|
1995
2026
|
|
|
2027
|
+
// 检查diff大小
|
|
2028
|
+
const diffSizeKB = Buffer.byteLength(stdout, 'utf8') / 1024;
|
|
2029
|
+
if (diffSizeKB > 500) {
|
|
2030
|
+
return res.json({
|
|
2031
|
+
diff: `⚠️ Diff内容过大 (${diffSizeKB.toFixed(1)}KB),已跳过显示以避免浏览器卡顿。\n\n提示:请使用命令行查看:git diff --cached -- "${filePath}"`,
|
|
2032
|
+
isLargeFile: true,
|
|
2033
|
+
size: diffSizeKB
|
|
2034
|
+
});
|
|
2035
|
+
}
|
|
2036
|
+
|
|
1996
2037
|
res.json({ diff: stdout });
|
|
1997
2038
|
} catch (error) {
|
|
1998
2039
|
res.status(500).json({ error: error.message });
|
|
@@ -2924,64 +2965,211 @@ async function startUIServer(noOpen = false, savePort = false) {
|
|
|
2924
2965
|
|
|
2925
2966
|
// ========== NPM 脚本管理相关 API ==========
|
|
2926
2967
|
|
|
2968
|
+
// 存储正在进行的扫描任务
|
|
2969
|
+
let currentScanAbortController = null;
|
|
2970
|
+
|
|
2927
2971
|
// 扫描项目目录及子目录下的所有package.json,并提取scripts
|
|
2928
2972
|
app.get('/api/scan-npm-scripts', async (req, res) => {
|
|
2973
|
+
// 取消之前的扫描
|
|
2974
|
+
if (currentScanAbortController) {
|
|
2975
|
+
currentScanAbortController.aborted = true;
|
|
2976
|
+
}
|
|
2977
|
+
|
|
2978
|
+
// 创建新的abort controller
|
|
2979
|
+
currentScanAbortController = {
|
|
2980
|
+
aborted: false,
|
|
2981
|
+
abort() { this.aborted = true; }
|
|
2982
|
+
};
|
|
2983
|
+
const scanController = currentScanAbortController;
|
|
2929
2984
|
try {
|
|
2930
2985
|
const projectRoot = process.cwd();
|
|
2931
2986
|
const packageJsons = [];
|
|
2987
|
+
const startTime = Date.now();
|
|
2988
|
+
|
|
2989
|
+
console.log(`[NPM扫描-后端] 开始扫描项目: ${projectRoot}`);
|
|
2990
|
+
|
|
2991
|
+
// 需要忽略的目录列表(更全面)
|
|
2992
|
+
const IGNORED_DIRS = new Set([
|
|
2993
|
+
'node_modules',
|
|
2994
|
+
'.git',
|
|
2995
|
+
'.svn',
|
|
2996
|
+
'.hg',
|
|
2997
|
+
'dist',
|
|
2998
|
+
'build',
|
|
2999
|
+
'coverage',
|
|
3000
|
+
'out',
|
|
3001
|
+
'target',
|
|
3002
|
+
'vendor',
|
|
3003
|
+
'__pycache__',
|
|
3004
|
+
'.next',
|
|
3005
|
+
'.nuxt',
|
|
3006
|
+
'.vscode',
|
|
3007
|
+
'.idea',
|
|
3008
|
+
'tmp',
|
|
3009
|
+
'temp',
|
|
3010
|
+
'cache',
|
|
3011
|
+
'.cache'
|
|
3012
|
+
]);
|
|
3013
|
+
|
|
3014
|
+
// 优先扫描的子目录(monorepo常见结构)
|
|
3015
|
+
const PRIORITY_DIRS = ['packages', 'apps', 'libs', 'services', 'modules'];
|
|
3016
|
+
|
|
3017
|
+
let scannedCount = 0;
|
|
3018
|
+
let skippedCount = 0;
|
|
3019
|
+
let fileReadCount = 0; // 统计实际读取的文件数量
|
|
3020
|
+
|
|
3021
|
+
// 检查指定目录下是否有package.json
|
|
3022
|
+
async function checkPackageJson(dir) {
|
|
3023
|
+
if (scanController.aborted) return false;
|
|
3024
|
+
|
|
3025
|
+
try {
|
|
3026
|
+
const packagePath = path.join(dir, 'package.json');
|
|
3027
|
+
|
|
3028
|
+
// 先检查文件是否存在,避免不必要的读取
|
|
3029
|
+
try {
|
|
3030
|
+
await fs.access(packagePath);
|
|
3031
|
+
} catch {
|
|
3032
|
+
// 文件不存在,直接返回
|
|
3033
|
+
return false;
|
|
3034
|
+
}
|
|
3035
|
+
|
|
3036
|
+
// 检查文件大小,避免读取异常大的文件
|
|
3037
|
+
const stats = await fs.stat(packagePath);
|
|
3038
|
+
const fileSizeMB = stats.size / (1024 * 1024);
|
|
3039
|
+
if (fileSizeMB > 1) {
|
|
3040
|
+
// package.json超过1MB是异常情况,跳过
|
|
3041
|
+
console.log(`[NPM扫描] 跳过超大文件 (${fileSizeMB.toFixed(2)}MB): ${packagePath}`);
|
|
3042
|
+
return false;
|
|
3043
|
+
}
|
|
3044
|
+
|
|
3045
|
+
fileReadCount++; // 只有文件存在且大小合理时才计数
|
|
3046
|
+
const content = await fs.readFile(packagePath, 'utf8');
|
|
3047
|
+
const packageData = JSON.parse(content);
|
|
3048
|
+
|
|
3049
|
+
// 只有当scripts存在且至少有一个脚本时才添加
|
|
3050
|
+
if (packageData.scripts && Object.keys(packageData.scripts).length > 0) {
|
|
3051
|
+
const relativePath = path.relative(projectRoot, dir);
|
|
3052
|
+
packageJsons.push({
|
|
3053
|
+
path: dir,
|
|
3054
|
+
relativePath: relativePath || '.',
|
|
3055
|
+
name: packageData.name || path.basename(dir),
|
|
3056
|
+
scripts: packageData.scripts
|
|
3057
|
+
});
|
|
3058
|
+
return true;
|
|
3059
|
+
}
|
|
3060
|
+
} catch (error) {
|
|
3061
|
+
// 文件不存在或解析失败,忽略
|
|
3062
|
+
}
|
|
3063
|
+
return false;
|
|
3064
|
+
}
|
|
3065
|
+
|
|
3066
|
+
// 递归扫描目录,最大深度4层
|
|
3067
|
+
const MAX_DEPTH = 4;
|
|
3068
|
+
const MAX_DIRS_PER_LEVEL = 50; // 每层最多扫描50个子目录
|
|
3069
|
+
|
|
3070
|
+
// 统计每层深度的扫描数量
|
|
3071
|
+
const depthStats = Array(MAX_DEPTH + 1).fill(0).map(() => ({ count: 0, time: 0 }));
|
|
2932
3072
|
|
|
2933
|
-
// 递归扫描目录查找package.json
|
|
2934
3073
|
async function scanDirectory(dir, depth = 0) {
|
|
2935
|
-
|
|
2936
|
-
if (depth >
|
|
3074
|
+
if (scanController.aborted) return;
|
|
3075
|
+
if (depth > MAX_DEPTH) return;
|
|
3076
|
+
|
|
3077
|
+
const depthStart = Date.now();
|
|
3078
|
+
scannedCount++;
|
|
3079
|
+
depthStats[depth].count++;
|
|
2937
3080
|
|
|
3081
|
+
// 检查当前目录的package.json
|
|
3082
|
+
await checkPackageJson(dir);
|
|
3083
|
+
|
|
3084
|
+
// 如果已经达到最大深度,不再继续
|
|
3085
|
+
if (depth >= MAX_DEPTH) return;
|
|
3086
|
+
|
|
3087
|
+
// 读取子目录
|
|
2938
3088
|
try {
|
|
3089
|
+
if (scanController.aborted) return;
|
|
3090
|
+
|
|
2939
3091
|
const items = await fs.readdir(dir, { withFileTypes: true });
|
|
3092
|
+
const subDirs = [];
|
|
2940
3093
|
|
|
3094
|
+
// 收集所有子目录
|
|
2941
3095
|
for (const item of items) {
|
|
2942
|
-
|
|
3096
|
+
if (scanController.aborted) return;
|
|
3097
|
+
if (!item.isDirectory()) continue;
|
|
2943
3098
|
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
dirName === 'build' ||
|
|
2951
|
-
dirName.startsWith('.')) {
|
|
2952
|
-
continue;
|
|
2953
|
-
}
|
|
2954
|
-
|
|
2955
|
-
// 递归扫描子目录
|
|
2956
|
-
await scanDirectory(fullPath, depth + 1);
|
|
2957
|
-
} else if (item.name === 'package.json') {
|
|
2958
|
-
// 读取package.json文件
|
|
2959
|
-
try {
|
|
2960
|
-
const content = await fs.readFile(fullPath, 'utf8');
|
|
2961
|
-
const packageData = JSON.parse(content);
|
|
2962
|
-
|
|
2963
|
-
// 只有当scripts存在且至少有一个脚本时才添加
|
|
2964
|
-
if (packageData.scripts && Object.keys(packageData.scripts).length > 0) {
|
|
2965
|
-
const relativePath = path.relative(projectRoot, dir);
|
|
2966
|
-
packageJsons.push({
|
|
2967
|
-
path: dir,
|
|
2968
|
-
relativePath: relativePath || '.',
|
|
2969
|
-
name: packageData.name || path.basename(dir),
|
|
2970
|
-
scripts: packageData.scripts
|
|
2971
|
-
});
|
|
2972
|
-
}
|
|
2973
|
-
} catch (error) {
|
|
2974
|
-
console.error(`读取package.json失败: ${fullPath}`, error);
|
|
2975
|
-
}
|
|
3099
|
+
const dirName = item.name;
|
|
3100
|
+
|
|
3101
|
+
// 跳过忽略的目录
|
|
3102
|
+
if (IGNORED_DIRS.has(dirName) || dirName.startsWith('.')) {
|
|
3103
|
+
skippedCount++;
|
|
3104
|
+
continue;
|
|
2976
3105
|
}
|
|
3106
|
+
|
|
3107
|
+
subDirs.push(item);
|
|
3108
|
+
}
|
|
3109
|
+
|
|
3110
|
+
// 限制每层扫描的子目录数量
|
|
3111
|
+
const dirsToScan = subDirs.slice(0, MAX_DIRS_PER_LEVEL);
|
|
3112
|
+
if (subDirs.length > MAX_DIRS_PER_LEVEL) {
|
|
3113
|
+
skippedCount += subDirs.length - MAX_DIRS_PER_LEVEL;
|
|
3114
|
+
}
|
|
3115
|
+
|
|
3116
|
+
// 优先处理优先目录
|
|
3117
|
+
const priorityDirs = dirsToScan.filter(item => PRIORITY_DIRS.includes(item.name));
|
|
3118
|
+
const normalDirs = dirsToScan.filter(item => !PRIORITY_DIRS.includes(item.name));
|
|
3119
|
+
|
|
3120
|
+
// 先扫描优先目录
|
|
3121
|
+
for (const item of priorityDirs) {
|
|
3122
|
+
if (scanController.aborted) return;
|
|
3123
|
+
const subDirPath = path.join(dir, item.name);
|
|
3124
|
+
await scanDirectory(subDirPath, depth + 1);
|
|
2977
3125
|
}
|
|
3126
|
+
|
|
3127
|
+
// 再扫描普通目录
|
|
3128
|
+
for (const item of normalDirs) {
|
|
3129
|
+
if (scanController.aborted) return;
|
|
3130
|
+
const subDirPath = path.join(dir, item.name);
|
|
3131
|
+
await scanDirectory(subDirPath, depth + 1);
|
|
3132
|
+
}
|
|
3133
|
+
|
|
2978
3134
|
} catch (error) {
|
|
2979
|
-
|
|
3135
|
+
// 忽略无法访问的目录
|
|
2980
3136
|
}
|
|
3137
|
+
|
|
3138
|
+
// 记录该深度的耗时
|
|
3139
|
+
depthStats[depth].time += Date.now() - depthStart;
|
|
2981
3140
|
}
|
|
2982
3141
|
|
|
2983
|
-
//
|
|
2984
|
-
|
|
3142
|
+
// 执行递归扫描
|
|
3143
|
+
console.log(`[NPM扫描-后端] 开始递归扫描(最大深度${MAX_DEPTH}层)`);
|
|
3144
|
+
const scanStart = Date.now();
|
|
3145
|
+
await scanDirectory(projectRoot, 0);
|
|
3146
|
+
console.log(`[NPM扫描-后端] 递归扫描完成,耗时${Date.now() - scanStart}ms`);
|
|
3147
|
+
|
|
3148
|
+
// 扫描完成,清除abort controller
|
|
3149
|
+
if (currentScanAbortController === scanController) {
|
|
3150
|
+
currentScanAbortController = null;
|
|
3151
|
+
}
|
|
3152
|
+
|
|
3153
|
+
const scanTime = Date.now() - startTime;
|
|
3154
|
+
|
|
3155
|
+
if (scanController.aborted) {
|
|
3156
|
+
console.log(`npm脚本扫描被取消,耗时${scanTime}ms`);
|
|
3157
|
+
return res.json({
|
|
3158
|
+
success: true,
|
|
3159
|
+
packages: [],
|
|
3160
|
+
totalScripts: 0,
|
|
3161
|
+
cancelled: true
|
|
3162
|
+
});
|
|
3163
|
+
}
|
|
3164
|
+
|
|
3165
|
+
// 输出每层深度的统计
|
|
3166
|
+
const depthInfo = depthStats
|
|
3167
|
+
.map((stat, depth) => stat.count > 0 ? `深度${depth}:${stat.count}个(${stat.time}ms)` : null)
|
|
3168
|
+
.filter(Boolean)
|
|
3169
|
+
.join(', ');
|
|
3170
|
+
|
|
3171
|
+
console.log(`npm脚本扫描完成,耗时${scanTime}ms,扫描了${scannedCount}个目录,读取了${fileReadCount}个package.json文件,跳过${skippedCount}个目录,找到${packageJsons.length}个有效的package.json`);
|
|
3172
|
+
console.log(`[NPM扫描-后端] 深度分布: ${depthInfo}`);
|
|
2985
3173
|
|
|
2986
3174
|
res.json({
|
|
2987
3175
|
success: true,
|
|
@@ -3076,7 +3264,7 @@ async function startUIServer(noOpen = false, savePort = false) {
|
|
|
3076
3264
|
// 客户端可以请求开始/停止监控
|
|
3077
3265
|
socket.on('start_monitoring', () => {
|
|
3078
3266
|
if (!watcher) {
|
|
3079
|
-
initFileSystemWatcher();
|
|
3267
|
+
initFileSystemWatcher().catch(err => console.error('[文件监控] 初始化失败:', err));
|
|
3080
3268
|
socket.emit('monitoring_status', { active: true });
|
|
3081
3269
|
}
|
|
3082
3270
|
});
|
|
@@ -3114,8 +3302,99 @@ async function startUIServer(noOpen = false, savePort = false) {
|
|
|
3114
3302
|
});
|
|
3115
3303
|
});
|
|
3116
3304
|
|
|
3305
|
+
// 读取并解析.gitignore文件
|
|
3306
|
+
async function parseGitignore(projectPath) {
|
|
3307
|
+
const gitignorePath = path.join(projectPath, '.gitignore');
|
|
3308
|
+
const ignorePatterns = [
|
|
3309
|
+
/(^|[\/\\])\../, // 始终忽略.开头的文件(除了.gitignore本身)
|
|
3310
|
+
'**/.git/**', // 始终忽略.git目录
|
|
3311
|
+
|
|
3312
|
+
// 额外排除常见的编译产物和大文件,减少监控开销
|
|
3313
|
+
'**/*.umd.cjs', // UMD打包文件
|
|
3314
|
+
'**/*.min.js', // 压缩JS文件
|
|
3315
|
+
'**/*.bundle.js', // Webpack打包文件
|
|
3316
|
+
'**/*.dist.js', // 构建产物
|
|
3317
|
+
'**/*.prod.js', // 生产环境文件
|
|
3318
|
+
'**/lib/**', // 通常是编译产物
|
|
3319
|
+
'**/es/**', // ES模块编译产物
|
|
3320
|
+
'**/esm/**', // ES模块编译产物
|
|
3321
|
+
'**/*.map', // Source map文件
|
|
3322
|
+
'**/*.chunk.js', // 代码分割chunk
|
|
3323
|
+
];
|
|
3324
|
+
|
|
3325
|
+
try {
|
|
3326
|
+
const gitignoreContent = await fs.readFile(gitignorePath, 'utf8');
|
|
3327
|
+
const lines = gitignoreContent.split('\n');
|
|
3328
|
+
let validRules = 0;
|
|
3329
|
+
|
|
3330
|
+
for (let line of lines) {
|
|
3331
|
+
line = line.trim();
|
|
3332
|
+
|
|
3333
|
+
// 跳过空行和注释
|
|
3334
|
+
if (!line || line.startsWith('#')) continue;
|
|
3335
|
+
|
|
3336
|
+
// 移除行尾的空格
|
|
3337
|
+
line = line.replace(/\s+$/, '');
|
|
3338
|
+
|
|
3339
|
+
// 跳过否定规则(chokidar不支持否定规则,这些规则会被忽略)
|
|
3340
|
+
if (line.startsWith('!')) {
|
|
3341
|
+
continue;
|
|
3342
|
+
}
|
|
3343
|
+
|
|
3344
|
+
// 将gitignore规则转换为glob模式
|
|
3345
|
+
let pattern;
|
|
3346
|
+
|
|
3347
|
+
// 如果以/开头,表示从根目录开始匹配
|
|
3348
|
+
if (line.startsWith('/')) {
|
|
3349
|
+
pattern = line.substring(1);
|
|
3350
|
+
// 如果是目录,添加/**后缀
|
|
3351
|
+
if (!pattern.includes('*') && !pattern.includes('.')) {
|
|
3352
|
+
ignorePatterns.push(pattern);
|
|
3353
|
+
ignorePatterns.push(pattern + '/**');
|
|
3354
|
+
} else {
|
|
3355
|
+
ignorePatterns.push(pattern);
|
|
3356
|
+
}
|
|
3357
|
+
} else if (line.endsWith('/')) {
|
|
3358
|
+
// 明确的目录规则
|
|
3359
|
+
const dirName = line.slice(0, -1);
|
|
3360
|
+
ignorePatterns.push('**/' + dirName);
|
|
3361
|
+
ignorePatterns.push('**/' + dirName + '/**');
|
|
3362
|
+
} else {
|
|
3363
|
+
// 文件或目录规则
|
|
3364
|
+
// 如果包含*通配符,直接使用
|
|
3365
|
+
if (line.includes('*')) {
|
|
3366
|
+
ignorePatterns.push('**/' + line);
|
|
3367
|
+
} else {
|
|
3368
|
+
// 既匹配文件也匹配目录
|
|
3369
|
+
ignorePatterns.push('**/' + line);
|
|
3370
|
+
ignorePatterns.push('**/' + line + '/**');
|
|
3371
|
+
}
|
|
3372
|
+
}
|
|
3373
|
+
|
|
3374
|
+
validRules++;
|
|
3375
|
+
}
|
|
3376
|
+
|
|
3377
|
+
console.log(`[文件监控] 从.gitignore读取了 ${validRules} 条有效的忽略规则`);
|
|
3378
|
+
} catch (error) {
|
|
3379
|
+
// .gitignore不存在或读取失败,使用默认规则
|
|
3380
|
+
console.log('[文件监控] 未找到.gitignore,使用默认忽略规则');
|
|
3381
|
+
ignorePatterns.push(
|
|
3382
|
+
'**/node_modules/**',
|
|
3383
|
+
'**/dist/**',
|
|
3384
|
+
'**/build/**',
|
|
3385
|
+
'**/coverage/**',
|
|
3386
|
+
'**/.nuxt/**',
|
|
3387
|
+
'**/.next/**',
|
|
3388
|
+
'**/out/**',
|
|
3389
|
+
'**/*.log'
|
|
3390
|
+
);
|
|
3391
|
+
}
|
|
3392
|
+
|
|
3393
|
+
return ignorePatterns;
|
|
3394
|
+
}
|
|
3395
|
+
|
|
3117
3396
|
// 初始化文件系统监控
|
|
3118
|
-
function initFileSystemWatcher() {
|
|
3397
|
+
async function initFileSystemWatcher() {
|
|
3119
3398
|
// 停止已有的监控器
|
|
3120
3399
|
if (watcher) {
|
|
3121
3400
|
watcher.close().catch(err => console.error('关闭旧监控器失败:', err));
|
|
@@ -3133,15 +3412,18 @@ async function startUIServer(noOpen = false, savePort = false) {
|
|
|
3133
3412
|
return;
|
|
3134
3413
|
}
|
|
3135
3414
|
|
|
3415
|
+
const watcherStartTime = Date.now();
|
|
3416
|
+
console.log('[文件监控] 开始初始化监控器...');
|
|
3417
|
+
|
|
3418
|
+
// 从.gitignore读取忽略规则
|
|
3419
|
+
const ignorePatterns = await parseGitignore(currentDir);
|
|
3420
|
+
|
|
3136
3421
|
// 使用chokidar监控文件变动
|
|
3137
3422
|
watcher = chokidar.watch(currentDir, {
|
|
3138
|
-
ignored:
|
|
3139
|
-
/(^|[\/\\])\../, // 忽略.开头的文件和目录
|
|
3140
|
-
'**/node_modules/**', // 忽略node_modules
|
|
3141
|
-
'**/.git/**', // 忽略.git目录
|
|
3142
|
-
],
|
|
3423
|
+
ignored: ignorePatterns,
|
|
3143
3424
|
persistent: true,
|
|
3144
3425
|
ignoreInitial: true, // 忽略初始扫描时的文件
|
|
3426
|
+
depth: 10, // 限制扫描深度,避免过深的目录结构
|
|
3145
3427
|
awaitWriteFinish: {
|
|
3146
3428
|
stabilityThreshold: 300, // 等待文件写入完成的时间
|
|
3147
3429
|
pollInterval: 100 // 轮询间隔
|
|
@@ -3157,11 +3439,16 @@ async function startUIServer(noOpen = false, savePort = false) {
|
|
|
3157
3439
|
});
|
|
3158
3440
|
});
|
|
3159
3441
|
|
|
3442
|
+
watcher.on('ready', () => {
|
|
3443
|
+
const initTime = Date.now() - watcherStartTime;
|
|
3444
|
+
console.log(`[文件监控] 监控器初始化完成,耗时 ${initTime}ms`);
|
|
3445
|
+
});
|
|
3446
|
+
|
|
3160
3447
|
watcher.on('error', error => {
|
|
3161
|
-
console.error('
|
|
3448
|
+
console.error('[文件监控] 监控错误:', error);
|
|
3162
3449
|
});
|
|
3163
3450
|
|
|
3164
|
-
console.log('
|
|
3451
|
+
console.log('[文件监控] 监控器已启动(异步初始化中...)');
|
|
3165
3452
|
} catch (error) {
|
|
3166
3453
|
console.error('启动文件监控失败:', error);
|
|
3167
3454
|
}
|
|
@@ -3308,9 +3595,10 @@ async function startUIServer(noOpen = false, savePort = false) {
|
|
|
3308
3595
|
console.log(chalk.green(` 启动时间: ${new Date().toLocaleString()}`));
|
|
3309
3596
|
|
|
3310
3597
|
if (isGitRepo) {
|
|
3311
|
-
console.log(chalk.green(` 当前目录是Git
|
|
3312
|
-
|
|
3313
|
-
|
|
3598
|
+
console.log(chalk.green(` 当前目录是Git仓库`));
|
|
3599
|
+
console.log(chalk.yellow(` 文件监控已禁用(默认),需要时请在前端开启自动更新开关`));
|
|
3600
|
+
// 不再自动启动文件监控,只在用户开启自动更新开关时启动
|
|
3601
|
+
// initFileSystemWatcher().catch(err => console.error('[文件监控] 初始化失败:', err));
|
|
3314
3602
|
} else {
|
|
3315
3603
|
console.log(chalk.yellow(` 当前目录不是Git仓库,文件监控未启动`));
|
|
3316
3604
|
}
|