XuqmGroup-Web/scripts/verify-web-cache-contract.mjs

75 行
2.5 KiB
JavaScript

#!/usr/bin/env node
import { spawnSync } from 'node:child_process'
import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs'
import path from 'node:path'
import process from 'node:process'
const root = path.resolve(import.meta.dirname, '..')
const releaseId = 'cache-contract-test'
const yarn = process.platform === 'win32' ? 'yarn.cmd' : 'yarn'
function run(args) {
const result = spawnSync(yarn, args, {
cwd: root,
env: { ...process.env, VITE_RELEASE_ID: releaseId },
stdio: 'inherit',
})
if (result.status !== 0) process.exit(result.status ?? 1)
}
function files(directory, suffix) {
return readdirSync(directory, { withFileTypes: true }).flatMap(entry => {
const current = path.join(directory, entry.name)
if (entry.isDirectory()) return files(current, suffix)
return entry.name.endsWith(suffix) ? [current] : []
})
}
function requireText(file, values) {
const content = readFileSync(file, 'utf8')
for (const value of values) {
if (!content.includes(value)) {
throw new Error(`${path.relative(root, file)} 缺少缓存契约:${value}`)
}
}
}
function verifyBuild(output, publicPrefix) {
const assetDirectory = path.join(output, 'releases', releaseId, 'assets')
if (!existsSync(assetDirectory) || !statSync(assetDirectory).isDirectory()) {
throw new Error(`${path.relative(root, output)} 未生成版本化 assets 目录`)
}
const html = files(output, '.html').map(file => readFileSync(file, 'utf8')).join('\n')
const expected = `${publicPrefix}releases/${releaseId}/assets/`
if (!html.includes(expected)) {
throw new Error(`${path.relative(root, output)} 的 HTML 未引用 ${expected}`)
}
}
run(['workspace', 'tenant-platform', 'build'])
run(['workspace', 'ops-platform', 'build'])
run(['workspace', '@xuqm/docs-site', 'build'])
verifyBuild(path.join(root, 'tenant-platform', 'dist'), '/')
verifyBuild(path.join(root, 'ops-platform', 'dist'), '/')
verifyBuild(path.join(root, 'docs-site', 'docs', '.vitepress', 'dist'), '/docs/')
for (const nginx of ['nginx/tenant.conf', 'nginx/ops.conf']) {
requireText(path.join(root, nginx), [
'no-cache, no-store, must-revalidate',
'public, max-age=31536000, immutable',
'try_files $uri =404',
])
}
for (const dockerfile of ['Dockerfile.tenant', 'Dockerfile.ops']) {
requireText(path.join(root, dockerfile), [
'ARG PREVIOUS_IMAGE=',
'/etc/xuqm_asset_layout_v2',
'COPY --from=previous',
'VITE_RELEASE_ID=${SERVICE_VERSION}',
])
}
console.log('Web 缓存与上一版本资源保留契约验证通过')