109 lines
3.2 KiB
JavaScript
Raw Normal View History

2026-07-02 10:52:09 +08:00
import { copyFileSync, existsSync, mkdirSync, readdirSync, rmSync } from 'node:fs'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
import { spawnSync } from 'node:child_process'
const __dirname = path.dirname(fileURLToPath(import.meta.url))
const desktopRoot = path.resolve(__dirname, '..')
const workspaceRoot = path.resolve(desktopRoot, '..')
const backendProject = path.join(
workspaceRoot,
'YD_TrainingCompetition_Api',
'YD_TrainingCompetition_Api.csproj',
)
const frontendRoot = path.join(workspaceRoot, 'YD_TrainingCompetition_Api_Web')
const frontendDist = path.join(frontendRoot, 'dist')
const packagedBackend = path.join(desktopRoot, 'build', 'backend')
const packagedFrontend = path.join(desktopRoot, 'frontend')
const skipFrontendBuild = process.argv.includes('--skip-frontend-build')
function run(command, args, options = {}) {
const useCmd = process.platform === 'win32' && command === 'npm'
const executable = useCmd ? process.env.ComSpec || 'cmd.exe' : command
const executableArgs = useCmd ? ['/d', '/s', '/c', `npm ${args.join(' ')}`] : args
console.log(`\n> ${command} ${args.join(' ')}`)
const result = spawnSync(executable, executableArgs, {
cwd: options.cwd || workspaceRoot,
env: {
...process.env,
...(options.env || {}),
},
stdio: 'inherit',
})
if (result.error) {
throw result.error
}
if (result.status !== 0) {
process.exit(result.status || 1)
}
}
function cleanDirectory(directory) {
rmSync(directory, { force: true, recursive: true })
mkdirSync(directory, { recursive: true })
}
function copyDirectory(source, destination) {
mkdirSync(destination, { recursive: true })
for (const entry of readdirSync(source, { withFileTypes: true })) {
const sourcePath = path.join(source, entry.name)
const destinationPath = path.join(destination, entry.name)
if (entry.isDirectory()) {
copyDirectory(sourcePath, destinationPath)
} else if (entry.isFile()) {
copyFileSync(sourcePath, destinationPath)
}
}
}
cleanDirectory(packagedBackend)
cleanDirectory(packagedFrontend)
run('dotnet', [
'publish',
backendProject,
'-c',
'Release',
'-r',
'win-x64',
'--self-contained',
'true',
'-o',
packagedBackend,
'/p:PublishSingleFile=false',
])
if (skipFrontendBuild) {
console.log('\n> skip frontend install/build, using existing dist')
} else {
run('npm', ['install'], { cwd: frontendRoot })
run('npm', ['run', 'build'], {
cwd: frontendRoot,
env: {
VITE_API_BASE_URL: 'http://localhost:9996',
},
})
}
if (!existsSync(frontendDist)) {
throw new Error(`前端构建产物不存在:${frontendDist}`)
}
copyDirectory(frontendDist, packagedFrontend)
// 同时把前端拷进后端 wwwroot,使后端通过 http 直接托管页面与静态资源。
const backendWwwRoot = path.join(packagedBackend, 'wwwroot')
cleanDirectory(backendWwwRoot)
copyDirectory(frontendDist, backendWwwRoot)
const appSettingsPath = path.join(workspaceRoot, 'YD_TrainingCompetition_Api', 'appsettings.json')
if (existsSync(appSettingsPath)) {
copyFileSync(appSettingsPath, path.join(packagedBackend, 'appsettings.json'))
}
console.log('\n桌面端打包资源已准备完成。')