zen-gitsync 2.5.1 → 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 +376 -55
- package/src/utils/index.js +15 -0
- 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
|
@@ -96,8 +96,41 @@ async function startUIServer(noOpen = false, savePort = false) {
|
|
|
96
96
|
|
|
97
97
|
// 添加请求日志中间件
|
|
98
98
|
app.use((req, res, next) => {
|
|
99
|
-
const
|
|
100
|
-
|
|
99
|
+
const startTime = Date.now();
|
|
100
|
+
const requestTime = new Date().toLocaleString('zh-CN', { hour12: false });
|
|
101
|
+
|
|
102
|
+
// 监听响应完成事件
|
|
103
|
+
res.on('finish', () => {
|
|
104
|
+
const duration = Date.now() - startTime;
|
|
105
|
+
const statusCode = res.statusCode;
|
|
106
|
+
|
|
107
|
+
// 根据状态码选择颜色
|
|
108
|
+
let statusColor = chalk.green;
|
|
109
|
+
if (statusCode >= 400 && statusCode < 500) {
|
|
110
|
+
statusColor = chalk.yellow;
|
|
111
|
+
} else if (statusCode >= 500) {
|
|
112
|
+
statusColor = chalk.red;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// 根据请求耗时选择颜色
|
|
116
|
+
let durationColor = chalk.gray;
|
|
117
|
+
if (duration > 1000) {
|
|
118
|
+
durationColor = chalk.red;
|
|
119
|
+
} else if (duration > 500) {
|
|
120
|
+
durationColor = chalk.yellow;
|
|
121
|
+
} else if (duration > 200) {
|
|
122
|
+
durationColor = chalk.cyan;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
console.log(
|
|
126
|
+
chalk.dim(`[${requestTime}]`),
|
|
127
|
+
chalk.bold(req.method),
|
|
128
|
+
req.url,
|
|
129
|
+
statusColor(`[${statusCode}]`),
|
|
130
|
+
durationColor(`${duration}ms`)
|
|
131
|
+
);
|
|
132
|
+
});
|
|
133
|
+
|
|
101
134
|
next();
|
|
102
135
|
});
|
|
103
136
|
|
|
@@ -592,8 +625,11 @@ async function startUIServer(noOpen = false, savePort = false) {
|
|
|
592
625
|
newProjectRoomId: newProjectRoomId
|
|
593
626
|
});
|
|
594
627
|
|
|
595
|
-
//
|
|
596
|
-
|
|
628
|
+
// 不再自动启动文件监控,只在用户手动开启自动更新开关时启动
|
|
629
|
+
// console.log('[切换目录] 将在3秒后初始化文件监控器');
|
|
630
|
+
// setTimeout(() => {
|
|
631
|
+
// initFileSystemWatcher().catch(err => console.error('[文件监控] 初始化失败:', err));
|
|
632
|
+
// }, 3000);
|
|
597
633
|
|
|
598
634
|
res.json({
|
|
599
635
|
success: true,
|
|
@@ -1940,9 +1976,28 @@ async function startUIServer(noOpen = false, savePort = false) {
|
|
|
1940
1976
|
return res.status(400).json({ error: '缺少文件路径参数' });
|
|
1941
1977
|
}
|
|
1942
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
|
+
|
|
1943
1988
|
// 执行git diff命令获取文件差异
|
|
1944
1989
|
const { stdout } = await execGitCommand(`git diff -- "${filePath}"`);
|
|
1945
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
|
+
|
|
1946
2001
|
res.json({ diff: stdout });
|
|
1947
2002
|
} catch (error) {
|
|
1948
2003
|
res.status(500).json({ error: error.message });
|
|
@@ -1957,9 +2012,28 @@ async function startUIServer(noOpen = false, savePort = false) {
|
|
|
1957
2012
|
return res.status(400).json({ error: '缺少文件路径参数' });
|
|
1958
2013
|
}
|
|
1959
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
|
+
|
|
1960
2024
|
// 执行git diff --cached命令获取已暂存文件差异
|
|
1961
2025
|
const { stdout } = await execGitCommand(`git diff --cached -- "${filePath}"`);
|
|
1962
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
|
+
|
|
1963
2037
|
res.json({ diff: stdout });
|
|
1964
2038
|
} catch (error) {
|
|
1965
2039
|
res.status(500).json({ error: error.message });
|
|
@@ -2891,64 +2965,211 @@ async function startUIServer(noOpen = false, savePort = false) {
|
|
|
2891
2965
|
|
|
2892
2966
|
// ========== NPM 脚本管理相关 API ==========
|
|
2893
2967
|
|
|
2968
|
+
// 存储正在进行的扫描任务
|
|
2969
|
+
let currentScanAbortController = null;
|
|
2970
|
+
|
|
2894
2971
|
// 扫描项目目录及子目录下的所有package.json,并提取scripts
|
|
2895
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;
|
|
2896
2984
|
try {
|
|
2897
2985
|
const projectRoot = process.cwd();
|
|
2898
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 }));
|
|
2899
3072
|
|
|
2900
|
-
// 递归扫描目录查找package.json
|
|
2901
3073
|
async function scanDirectory(dir, depth = 0) {
|
|
2902
|
-
|
|
2903
|
-
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++;
|
|
2904
3080
|
|
|
3081
|
+
// 检查当前目录的package.json
|
|
3082
|
+
await checkPackageJson(dir);
|
|
3083
|
+
|
|
3084
|
+
// 如果已经达到最大深度,不再继续
|
|
3085
|
+
if (depth >= MAX_DEPTH) return;
|
|
3086
|
+
|
|
3087
|
+
// 读取子目录
|
|
2905
3088
|
try {
|
|
3089
|
+
if (scanController.aborted) return;
|
|
3090
|
+
|
|
2906
3091
|
const items = await fs.readdir(dir, { withFileTypes: true });
|
|
3092
|
+
const subDirs = [];
|
|
2907
3093
|
|
|
3094
|
+
// 收集所有子目录
|
|
2908
3095
|
for (const item of items) {
|
|
2909
|
-
|
|
3096
|
+
if (scanController.aborted) return;
|
|
3097
|
+
if (!item.isDirectory()) continue;
|
|
2910
3098
|
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
dirName === 'build' ||
|
|
2918
|
-
dirName.startsWith('.')) {
|
|
2919
|
-
continue;
|
|
2920
|
-
}
|
|
2921
|
-
|
|
2922
|
-
// 递归扫描子目录
|
|
2923
|
-
await scanDirectory(fullPath, depth + 1);
|
|
2924
|
-
} else if (item.name === 'package.json') {
|
|
2925
|
-
// 读取package.json文件
|
|
2926
|
-
try {
|
|
2927
|
-
const content = await fs.readFile(fullPath, 'utf8');
|
|
2928
|
-
const packageData = JSON.parse(content);
|
|
2929
|
-
|
|
2930
|
-
// 只有当scripts存在且至少有一个脚本时才添加
|
|
2931
|
-
if (packageData.scripts && Object.keys(packageData.scripts).length > 0) {
|
|
2932
|
-
const relativePath = path.relative(projectRoot, dir);
|
|
2933
|
-
packageJsons.push({
|
|
2934
|
-
path: dir,
|
|
2935
|
-
relativePath: relativePath || '.',
|
|
2936
|
-
name: packageData.name || path.basename(dir),
|
|
2937
|
-
scripts: packageData.scripts
|
|
2938
|
-
});
|
|
2939
|
-
}
|
|
2940
|
-
} catch (error) {
|
|
2941
|
-
console.error(`读取package.json失败: ${fullPath}`, error);
|
|
2942
|
-
}
|
|
3099
|
+
const dirName = item.name;
|
|
3100
|
+
|
|
3101
|
+
// 跳过忽略的目录
|
|
3102
|
+
if (IGNORED_DIRS.has(dirName) || dirName.startsWith('.')) {
|
|
3103
|
+
skippedCount++;
|
|
3104
|
+
continue;
|
|
2943
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);
|
|
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);
|
|
2944
3132
|
}
|
|
3133
|
+
|
|
2945
3134
|
} catch (error) {
|
|
2946
|
-
|
|
3135
|
+
// 忽略无法访问的目录
|
|
2947
3136
|
}
|
|
3137
|
+
|
|
3138
|
+
// 记录该深度的耗时
|
|
3139
|
+
depthStats[depth].time += Date.now() - depthStart;
|
|
2948
3140
|
}
|
|
2949
3141
|
|
|
2950
|
-
//
|
|
2951
|
-
|
|
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}`);
|
|
2952
3173
|
|
|
2953
3174
|
res.json({
|
|
2954
3175
|
success: true,
|
|
@@ -3043,7 +3264,7 @@ async function startUIServer(noOpen = false, savePort = false) {
|
|
|
3043
3264
|
// 客户端可以请求开始/停止监控
|
|
3044
3265
|
socket.on('start_monitoring', () => {
|
|
3045
3266
|
if (!watcher) {
|
|
3046
|
-
initFileSystemWatcher();
|
|
3267
|
+
initFileSystemWatcher().catch(err => console.error('[文件监控] 初始化失败:', err));
|
|
3047
3268
|
socket.emit('monitoring_status', { active: true });
|
|
3048
3269
|
}
|
|
3049
3270
|
});
|
|
@@ -3081,8 +3302,99 @@ async function startUIServer(noOpen = false, savePort = false) {
|
|
|
3081
3302
|
});
|
|
3082
3303
|
});
|
|
3083
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
|
+
|
|
3084
3396
|
// 初始化文件系统监控
|
|
3085
|
-
function initFileSystemWatcher() {
|
|
3397
|
+
async function initFileSystemWatcher() {
|
|
3086
3398
|
// 停止已有的监控器
|
|
3087
3399
|
if (watcher) {
|
|
3088
3400
|
watcher.close().catch(err => console.error('关闭旧监控器失败:', err));
|
|
@@ -3100,15 +3412,18 @@ async function startUIServer(noOpen = false, savePort = false) {
|
|
|
3100
3412
|
return;
|
|
3101
3413
|
}
|
|
3102
3414
|
|
|
3415
|
+
const watcherStartTime = Date.now();
|
|
3416
|
+
console.log('[文件监控] 开始初始化监控器...');
|
|
3417
|
+
|
|
3418
|
+
// 从.gitignore读取忽略规则
|
|
3419
|
+
const ignorePatterns = await parseGitignore(currentDir);
|
|
3420
|
+
|
|
3103
3421
|
// 使用chokidar监控文件变动
|
|
3104
3422
|
watcher = chokidar.watch(currentDir, {
|
|
3105
|
-
ignored:
|
|
3106
|
-
/(^|[\/\\])\../, // 忽略.开头的文件和目录
|
|
3107
|
-
'**/node_modules/**', // 忽略node_modules
|
|
3108
|
-
'**/.git/**', // 忽略.git目录
|
|
3109
|
-
],
|
|
3423
|
+
ignored: ignorePatterns,
|
|
3110
3424
|
persistent: true,
|
|
3111
3425
|
ignoreInitial: true, // 忽略初始扫描时的文件
|
|
3426
|
+
depth: 10, // 限制扫描深度,避免过深的目录结构
|
|
3112
3427
|
awaitWriteFinish: {
|
|
3113
3428
|
stabilityThreshold: 300, // 等待文件写入完成的时间
|
|
3114
3429
|
pollInterval: 100 // 轮询间隔
|
|
@@ -3124,11 +3439,16 @@ async function startUIServer(noOpen = false, savePort = false) {
|
|
|
3124
3439
|
});
|
|
3125
3440
|
});
|
|
3126
3441
|
|
|
3442
|
+
watcher.on('ready', () => {
|
|
3443
|
+
const initTime = Date.now() - watcherStartTime;
|
|
3444
|
+
console.log(`[文件监控] 监控器初始化完成,耗时 ${initTime}ms`);
|
|
3445
|
+
});
|
|
3446
|
+
|
|
3127
3447
|
watcher.on('error', error => {
|
|
3128
|
-
console.error('
|
|
3448
|
+
console.error('[文件监控] 监控错误:', error);
|
|
3129
3449
|
});
|
|
3130
3450
|
|
|
3131
|
-
console.log('
|
|
3451
|
+
console.log('[文件监控] 监控器已启动(异步初始化中...)');
|
|
3132
3452
|
} catch (error) {
|
|
3133
3453
|
console.error('启动文件监控失败:', error);
|
|
3134
3454
|
}
|
|
@@ -3275,9 +3595,10 @@ async function startUIServer(noOpen = false, savePort = false) {
|
|
|
3275
3595
|
console.log(chalk.green(` 启动时间: ${new Date().toLocaleString()}`));
|
|
3276
3596
|
|
|
3277
3597
|
if (isGitRepo) {
|
|
3278
|
-
console.log(chalk.green(` 当前目录是Git
|
|
3279
|
-
|
|
3280
|
-
|
|
3598
|
+
console.log(chalk.green(` 当前目录是Git仓库`));
|
|
3599
|
+
console.log(chalk.yellow(` 文件监控已禁用(默认),需要时请在前端开启自动更新开关`));
|
|
3600
|
+
// 不再自动启动文件监控,只在用户开启自动更新开关时启动
|
|
3601
|
+
// initFileSystemWatcher().catch(err => console.error('[文件监控] 初始化失败:', err));
|
|
3281
3602
|
} else {
|
|
3282
3603
|
console.log(chalk.yellow(` 当前目录不是Git仓库,文件监控未启动`));
|
|
3283
3604
|
}
|
package/src/utils/index.js
CHANGED
|
@@ -202,6 +202,11 @@ function execSyncGitCommand(command, options = {}) {
|
|
|
202
202
|
}
|
|
203
203
|
let result = output.trim()
|
|
204
204
|
log && coloredLog(head, result)
|
|
205
|
+
// 打印当前目录和时间信息
|
|
206
|
+
if (log) {
|
|
207
|
+
const currentTime = new Date().toLocaleString('zh-CN', { hour12: false });
|
|
208
|
+
console.log(chalk.dim(`📁 目录: ${cwd} | ⏰ 时间: ${currentTime}`));
|
|
209
|
+
}
|
|
205
210
|
return result
|
|
206
211
|
} catch (e) {
|
|
207
212
|
// console.log(`执行命令出错 ==> `, command, e)
|
|
@@ -312,8 +317,18 @@ function execGitCommand(command, options = {}) {
|
|
|
312
317
|
if (stderr) {
|
|
313
318
|
log && coloredLog(head, stderr)
|
|
314
319
|
}
|
|
320
|
+
// 打印当前目录和时间信息
|
|
321
|
+
if (log && (stdout || stderr)) {
|
|
322
|
+
const currentTime = new Date().toLocaleString('zh-CN', { hour12: false });
|
|
323
|
+
console.log(chalk.dim(`📁 目录: ${cwd} | ⏰ 时间: ${currentTime}`));
|
|
324
|
+
}
|
|
315
325
|
if (error) {
|
|
316
326
|
log && coloredLog(head, error, 'error')
|
|
327
|
+
// 错误情况也打印目录和时间
|
|
328
|
+
if (log) {
|
|
329
|
+
const currentTime = new Date().toLocaleString('zh-CN', { hour12: false });
|
|
330
|
+
console.log(chalk.dim(`📁 目录: ${cwd} | ⏰ 时间: ${currentTime}`));
|
|
331
|
+
}
|
|
317
332
|
reject(error)
|
|
318
333
|
return
|
|
319
334
|
}
|