@@ -11,19 +11,39 @@ import path from 'path'
1111
1212const NEW_THRESHOLD_DAYS = 7 ; // 7天内更新显示 NEW
1313
14+ /**
15+ * 获取文件最后提交时间
16+ * 修复逻辑:CI 环境下严格依赖 Git 时间,失败则不显示 New,防止误判
17+ */
1418function getFileLastCommitTime ( filePath : string ) : number {
1519 try {
1620 if ( ! fs . existsSync ( filePath ) ) return 0 ;
21+
1722 // 获取 git 最后提交时间
18- const timestamp = execSync ( `git log -1 --format=%ct "${ filePath } "` , { encoding : 'utf-8' } ) ;
23+ // 使用 stdio: ignore 忽略 stderr,防止 git 报错中断构建
24+ const timestamp = execSync ( `git log -1 --format=%ct "${ filePath } "` , {
25+ encoding : 'utf-8' ,
26+ stdio : [ 'pipe' , 'pipe' , 'ignore' ]
27+ } ) ;
28+
1929 const time = parseInt ( timestamp . trim ( ) , 10 ) * 1000 ;
20- // 如果 git 获取失败(例如新文件),尝试获取文件系统时间
30+
31+ // 严谨判断:如果 git 获取失败 (time 为 NaN 或 0)
2132 if ( Number . isNaN ( time ) || time === 0 ) {
33+ // 【关键修复】
34+ // 在 CI 环境 (GitHub Actions) 中,如果拿不到 git 时间,直接返回 0。
35+ // 绝对不能回退到 fs.statSync,因为 CI 里 git checkout 下来的文件时间都是"刚刚",会导致全显示 New。
36+ if ( process . env . CI ) {
37+ return 0 ;
38+ }
39+ // 只有在本地开发环境,才允许回退到文件系统时间 (方便调试新建未提交的文件)
2240 return fs . statSync ( filePath ) . mtimeMs ;
2341 }
2442 return time ;
2543 } catch ( e ) {
26- return 0 ;
44+ // 发生错误时,CI 环境返回 0,本地环境尝试返回文件时间
45+ if ( process . env . CI ) return 0 ;
46+ return fs . existsSync ( filePath ) ? fs . statSync ( filePath ) . mtimeMs : 0 ;
2747 }
2848}
2949
@@ -44,25 +64,38 @@ function processSidebar(items: any[], baseDir: string) {
4464
4565 // 处理具体链接
4666 if ( item . link ) {
47- // 1. 处理文件后缀
48- let relativePath = item . link ;
67+ // 1. 规范化 link,移除开头的 /
68+ let relativePath = item . link . replace ( / ^ \/ / , '' ) ;
69+
70+ // 2. 补全后缀
4971 if ( ! relativePath . endsWith ( '.md' ) ) {
5072 relativePath += '.md' ;
5173 }
52- // 2. 移除开头的 /,防止 path.resolve 错误定位到系统根目录
53- relativePath = relativePath . replace ( / ^ \/ / , '' ) ;
5474
5575 // 3. 拼接完整的物理路径
56- // 注意:这里结合了 baseDir (docs/zh-CN) 来找到真实文件
57- const fullPath = path . resolve ( process . cwd ( ) , baseDir , relativePath ) ;
76+ // 【关键修复】检查 link 是否已经包含了 baseDir,防止出现 docs/en-US/docs/en-US/...
77+ let fullPath ;
78+
79+ // 注意:这里简单的字符串包含检查可能不够,建议检查开头
80+ // baseDir 例如: 'docs/en-US'
81+ if ( relativePath . startsWith ( baseDir ) ) {
82+ // 如果 link 已经是 /docs/en-US/guide/xxx,则直接基于 cwd 解析
83+ fullPath = path . resolve ( process . cwd ( ) , relativePath ) ;
84+ } else {
85+ // 如果 link 是 /guide/xxx,则拼接 baseDir
86+ fullPath = path . resolve ( process . cwd ( ) , baseDir , relativePath ) ;
87+ }
88+
89+ // 调试日志:如果构建时还发现路径不对,可以解开下面注释查看
90+ // console.log(`[Badge Check] Link: ${item.link} -> Full: ${fullPath}`);
5891
5992 const lastTime = getFileLastCommitTime ( fullPath ) ;
60- console . log ( `Path: ${ fullPath } , GitTime: ${ lastTime } ` ) ;
6193
6294 // 4. 判断并注入 HTML
63- if ( lastTime && ( now - lastTime < threshold ) ) {
64- // 防止重复添加(如果开发模式下热更新)
65- if ( ! item . text . includes ( 'vp-badge-new' ) ) {
95+ // 只有时间有效且在阈值内才添加
96+ if ( lastTime > 0 && ( now - lastTime < threshold ) ) {
97+ // 确保 item.text 是字符串且不重复添加
98+ if ( typeof item . text === 'string' && ! item . text . includes ( 'vp-badge-new' ) ) {
6699 item . text = `${ item . text } <span class="vp-badge-new">New</span>` ;
67100 }
68101 }
@@ -93,9 +126,12 @@ function injectNewBadge(config: any, baseDir: string) {
93126// ==============================================================================
94127
95128// 处理中文配置:物理路径在 docs/zh-CN
129+ // 中文配置通常 link 是 /install/xxx,拼接后为 /app/docs/zh-CN/install/xxx (正确)
96130injectNewBadge ( zhCNConfig , 'docs/zh-CN' ) ;
97131
98132// 处理英文配置:物理路径在 docs/en-US
133+ // 英文配置如果使用了 rewrites 或 link 本身带前缀 /docs/en-US/install/xxx
134+ // processSidebar 里的修复逻辑会处理它,避免重复拼接
99135injectNewBadge ( enUSConfig , 'docs/en-US' ) ;
100136
101137
0 commit comments