fix(preview): 流式文件服务与 HEAD 跳读;静默开关;redirect 转义;argv 缺值报错
复审四项: - serveFile 改 createReadStream 直 pipe(Content-Length 取自先行 stat)—— 64MB 文件 RSS 平坦(冒烟实测 -53MB 增长,此前整读驻留);HEAD 只发头 零读盘;流错误掐断连接不崩进程;头纪律抽 applyHeaders 唯一出口。 - createPreviewServer 增 quiet 选项(缺省 verbose);sf.ts preview:start 与 server.mjs 直跑入口各加 --quiet;CLI 透传经子进程冒烟验证。 - redirect 迁移页内嵌 location 时 HTML 转义(</&/"——Location 头原样)。 - parseCliArgs 末尾缺值 flag 显式报错(不再静默 undefined 漏成默认值)。 测试 12→13(新增 quiet 开关用例;用例 12 增 --quiet stdout 断言): 根套件 380 + 主题 26 = 406 全绿;typecheck/lint 干净。 Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -15,7 +15,9 @@
|
||||
// 9. 目录列表禁用(dist 子目录请求 → 404,不出文件清单)
|
||||
// 10. HEAD 方法支持(200 同头无 body)
|
||||
// 11. CLI:--host 外值拒绝(校验先于 DB 访问——tsx 直跑 sf.ts)
|
||||
// 12. CLI happy path:真实 job 子进程全链(job 定位 → manifest 读 → 监听可服务 → 关停)
|
||||
// 12. CLI happy path:真实 job 子进程全链(job 定位 → manifest 读 → 监听可服务 → 关停;
|
||||
// --quiet 透传——子进程 stdout 无逐请求访问日志)
|
||||
// 13. quiet 开关:quiet:true 静默逐请求日志;缺省(verbose)逐请求一行 stdout
|
||||
import { execFile, spawn } from 'node:child_process'
|
||||
import { createHash } from 'node:crypto'
|
||||
import { mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'
|
||||
@@ -23,7 +25,7 @@ import { request } from 'node:http'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { dirname, join, resolve } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { afterAll, beforeAll, describe, expect, it } from 'vitest'
|
||||
import { afterAll, beforeAll, describe, expect, it, vi } from 'vitest'
|
||||
import type { RouteManifest, RouteManifestRoute } from '@sf/contracts'
|
||||
import { createBuildJob } from '../../apps/api/src/modules/build/build.service.js'
|
||||
import { createImportJob } from '../../apps/api/src/modules/import/import.service.js'
|
||||
@@ -353,7 +355,7 @@ describe('预览服务器(真实构建产物 + 手构 manifest 扩展)', ()
|
||||
const jobId = manifest!.build_job_id
|
||||
const child = spawn(
|
||||
process.execPath,
|
||||
[TSX_CLI, join(REPO_ROOT, 'scripts', 'sf.ts'), 'preview:start', '--build', jobId, '--port', '0'],
|
||||
[TSX_CLI, join(REPO_ROOT, 'scripts', 'sf.ts'), 'preview:start', '--build', jobId, '--port', '0', '--quiet'],
|
||||
{ cwd: REPO_ROOT, stdio: ['ignore', 'pipe', 'pipe'] },
|
||||
)
|
||||
let stdout = ''
|
||||
@@ -379,6 +381,9 @@ describe('预览服务器(真实构建产物 + 手构 manifest 扩展)', ()
|
||||
expect(res.status).toBe(200)
|
||||
expect(res.headers.get('x-robots-tag')).toBe('noindex, nofollow')
|
||||
expect(await res.text()).toStrictEqual(await readFile(join(distDir, 'index.html'), 'utf8'))
|
||||
// --quiet 透传:服务过请求后子进程 stdout 仍无逐请求访问日志行
|
||||
await new Promise((r) => setTimeout(r, 500))
|
||||
expect(stdout).not.toMatch(/\[preview\] (GET|HEAD)/)
|
||||
} finally {
|
||||
child.kill()
|
||||
await new Promise<void>((resolveP) => {
|
||||
@@ -390,4 +395,26 @@ describe('预览服务器(真实构建产物 + 手构 manifest 扩展)', ()
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
it('13. quiet 开关:quiet:true 静默逐请求日志;缺省 verbose 逐请求一行', async () => {
|
||||
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {})
|
||||
try {
|
||||
const previewLines = (): number => logSpy.mock.calls.filter((c) => String(c[0]).includes('[preview] ')).length
|
||||
// quiet 实例:请求零访问日志
|
||||
const quietServer = createPreviewServer({ distDir, routeManifest: manifest!, port: 0, quiet: true })
|
||||
const addr = await quietServer.start()
|
||||
try {
|
||||
expect((await fetch(`http://127.0.0.1:${addr.port}/`)).status).toBe(200)
|
||||
expect(previewLines()).toBe(0)
|
||||
} finally {
|
||||
await quietServer.stop()
|
||||
}
|
||||
// 缺省 verbose 对照(beforeAll 主服务):请求恰一行访问日志
|
||||
const before = previewLines()
|
||||
await get('/')
|
||||
expect(previewLines()).toBe(before + 1)
|
||||
} finally {
|
||||
logSpy.mockRestore()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user