1.5.1版本,体验性修复、打包fpk、docker镜像、windows包

This commit is contained in:
Yeomai committed 2026-10-18 15:32:56 +08:00
1 parent 813407de30
commit a6e45e0cb1
17 files changed
+3451 -15

No files matched your search

+166
View File
@@ -0,0 +1,166 @@
import { createHash } from 'node:crypto'
import { spawnSync } from 'node:child_process'
import {
access,
copyFile,
cp,
mkdir,
readFile,
rm,
writeFile
} from 'node:fs/promises'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
import sharp from 'sharp'
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..')
const outputRoot = path.join(root, 'dist-windows')
const stageRoot = path.join(outputRoot, 'staging')
const runtimeRoot = path.join(stageRoot, 'runtime')
const appRoot = path.join(runtimeRoot, 'app')
const nodeDir = path.join(runtimeRoot, 'node')
const ffmpegDir = path.join(runtimeRoot, 'ffmpeg')
const buildDir = path.join(stageRoot, 'build')
const cacheDir = path.join(outputRoot, 'cache')
const nodeVersion = '22.23.3'
function run(command, args, cwd = root) {
const result = spawnSync(command, args, {
cwd,
encoding: 'utf8',
stdio: 'inherit',
windowsHide: true,
shell: process.platform === 'win32' && /\.(?:cmd|bat)$/i.test(command)
})
if (result.error) throw result.error
if (result.status !== 0) {
throw new Error(`${command} ${args.join(' ')} 失败,退出代码 ${result.status}`)
}
}
async function exists(file) {
try {
await access(file)
return true
} catch {
return false
}
}
async function download(file, url) {
if (await exists(file)) return
await mkdir(path.dirname(file), { recursive: true })
console.log(`下载 ${url}`)
const response = await fetch(url)
if (!response.ok) throw new Error(`下载失败:${response.status} ${url}`)
await writeFile(file, Buffer.from(await response.arrayBuffer()))
}
async function prepareNode() {
const cacheFile = path.join(cacheDir, `node-v${nodeVersion}-win-x64.exe`)
const nodeExe = path.join(nodeDir, 'node.exe')
await download(
cacheFile,
`https://nodejs.org/dist/v${nodeVersion}/win-x64/node.exe`
)
const sums = await (await fetch(
`https://nodejs.org/dist/v${nodeVersion}/SHASUMS256.txt`
)).text()
const expected = sums
.split(/\r?\n/)
.map(line => line.trim().split(/\s+/))
.find(parts => parts[1] === 'win-x64/node.exe')?.[0]
const actual = createHash('sha256')
.update(await readFile(cacheFile))
.digest('hex')
if (!expected || actual !== expected) {
throw new Error('内置 Node.js 校验失败')
}
await mkdir(nodeDir, { recursive: true })
await copyFile(cacheFile, nodeExe)
run(nodeExe, ['--version'])
}
async function findFfmpegDir() {
const candidates = [
process.env.FFMPEG_DIR,
'C:\\ffmpeg-8.0.1-essentials_build\\bin'
].filter(Boolean)
for (const candidate of candidates) {
if (
await exists(path.join(candidate, 'ffmpeg.exe'))
&& await exists(path.join(candidate, 'ffprobe.exe'))
) {
return candidate
}
}
const located = spawnSync('where.exe', ['ffmpeg.exe'], { encoding: 'utf8' })
const first = located.stdout?.trim().split(/\r?\n/)[0]
if (first && await exists(path.join(path.dirname(first), 'ffprobe.exe'))) {
return path.dirname(first)
}
throw new Error('未找到 ffmpeg.exe 和 ffprobe.exe,请设置 FFMPEG_DIR')
}
async function main() {
run('npm.cmd', ['run', 'build'])
await rm(stageRoot, { recursive: true, force: true })
await Promise.all([
mkdir(appRoot, { recursive: true }),
mkdir(buildDir, { recursive: true })
])
await cp(path.join(root, '.output'), path.join(appRoot, '.output'), {
recursive: true,
dereference: true
})
await copyFile(path.join(root, 'package.json'), path.join(appRoot, 'package.json'))
await copyFile(
path.join(root, 'package-lock.json'),
path.join(appRoot, 'package-lock.json')
)
await cp(path.join(root, 'server', 'cli'), path.join(appRoot, 'server', 'cli'), {
recursive: true
})
console.log('安装 Windows 运行时生产依赖')
run(
'npm.cmd',
['ci', '--omit=dev', '--ignore-scripts', '--no-audit', '--no-fund'],
appRoot
)
await prepareNode()
const sourceFfmpeg = await findFfmpegDir()
await mkdir(ffmpegDir, { recursive: true })
await copyFile(
path.join(sourceFfmpeg, 'ffmpeg.exe'),
path.join(ffmpegDir, 'ffmpeg.exe')
)
await copyFile(
path.join(sourceFfmpeg, 'ffprobe.exe'),
path.join(ffmpegDir, 'ffprobe.exe')
)
run(path.join(ffmpegDir, 'ffmpeg.exe'), ['-version'])
await sharp(path.join(root, 'app', 'assets', 'image', 'logo-light.png'))
.resize(512, 512, {
fit: 'contain',
background: { r: 0, g: 0, b: 0, alpha: 0 }
})
.png()
.toFile(path.join(buildDir, 'icon.png'))
console.log(`Windows 运行时已准备到 ${runtimeRoot}`)
}
main().catch((error) => {
console.error(error)
process.exit(1)
})