chore(gerp): deploy.ps1 转纯 ASCII 消除 BOM 警告
- PS 5.1 无 BOM 时按 ANSI 代码页解析 UTF-8 文件,中文会乱码导致语法错误; 保留 BOM 又会触发首行 "'#' 不是 cmdlet" 警告 - 脚本注释与输出改为英文(纯 ASCII),无 BOM 下可被 PS 5.1 正确解析 - 头部注释注明须保持 ASCII 以防回归
This commit is contained in:
1 parent
b1022d7ac9
commit
312660c41f
1 file changed
+107
-105
+107
-105
@@ -1,105 +1,107 @@
|
||||
# GERP 前端部署脚本:全量编译并同步产物到生产目录(TempLate/GERP)
|
||||
#
|
||||
# 用途:
|
||||
# 1. 清理旧构建产物(dist 与 TempLate/GERP/assets),保证无 hash 残留
|
||||
# 2. 全量重新构建(vue-tsc 类型检查 + vite build)
|
||||
# 3. 同步 dist 产物到 TempLate/GERP(index.html + assets)
|
||||
# 4. 校验 TempLate 与 dist 完全一致
|
||||
#
|
||||
# 用法:
|
||||
# PowerShell 中执行: .\deploy.ps1
|
||||
# (若报执行策略限制: Set-ExecutionPolicy -Scope Process Bypass 后再执行)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
$ProjectRoot = Split-Path -Parent $MyInvocation.MyCommand.Path # d:\SMANAGE\GERP
|
||||
$DistDir = Join-Path $ProjectRoot 'dist'
|
||||
$ProdRoot = Join-Path (Split-Path -Parent $ProjectRoot) 'TempLate\GERP' # d:\SMANAGE\TempLate\GERP
|
||||
$ProdAssetsDir = Join-Path $ProdRoot 'assets'
|
||||
$IndexHtml = Join-Path $ProdRoot 'index.html'
|
||||
|
||||
Write-Host "`n===== GERP 部署开始 =====" -ForegroundColor Cyan
|
||||
Write-Host "工程目录: $ProjectRoot"
|
||||
Write-Host "生产目录: $ProdRoot"
|
||||
Write-Host ""
|
||||
|
||||
# 1. 清理旧产物(dist + 生产 assets),保证全量构建无 hash 残留
|
||||
Write-Host '[1/4] 清理旧构建产物...' -ForegroundColor Yellow
|
||||
if (Test-Path $DistDir) {
|
||||
Remove-Item -Recurse -Force $DistDir
|
||||
Write-Host " 已删除: $DistDir"
|
||||
}
|
||||
if (Test-Path $ProdAssetsDir) {
|
||||
Remove-Item -Recurse -Force $ProdAssetsDir
|
||||
Write-Host " 已删除: $ProdAssetsDir"
|
||||
}
|
||||
if (Test-Path $IndexHtml) {
|
||||
Remove-Item -Force $IndexHtml
|
||||
Write-Host " 已删除: $IndexHtml"
|
||||
}
|
||||
Write-Host ''
|
||||
|
||||
# 2. 全量构建(vue-tsc 类型检查 + vite build)
|
||||
Write-Host '[2/4] 执行 npm run build(类型检查 + 全量编译)...' -ForegroundColor Yellow
|
||||
Push-Location $ProjectRoot
|
||||
try {
|
||||
npm run build
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "构建失败,exit code = $LASTEXITCODE"
|
||||
}
|
||||
} finally {
|
||||
Pop-Location
|
||||
}
|
||||
Write-Host ' 构建成功'
|
||||
Write-Host ''
|
||||
|
||||
# 3. 同步产物到生产目录
|
||||
Write-Host '[3/4] 同步产物到生产目录...' -ForegroundColor Yellow
|
||||
if (-not (Test-Path $ProdRoot)) {
|
||||
New-Item -ItemType Directory -Path $ProdRoot -Force | Out-Null
|
||||
}
|
||||
Copy-Item -Recurse -Force (Join-Path $DistDir '*') $ProdRoot
|
||||
Copy-Item -Force (Join-Path $DistDir 'index.html') $IndexHtml
|
||||
Write-Host ' 同步完成'
|
||||
Write-Host ''
|
||||
|
||||
# 4. 校验生产目录与 dist 完全一致(文件名集合)
|
||||
Write-Host '[4/4] 校验产物一致性...' -ForegroundColor Yellow
|
||||
function Get-AssetNames([string]$dir) {
|
||||
if (-not (Test-Path $dir)) { return @() }
|
||||
return @(Get-ChildItem -Path $dir -Recurse -File | ForEach-Object { $_.FullName.Substring($dir.Length) })
|
||||
}
|
||||
$distNames = Get-AssetNames (Join-Path $DistDir 'assets')
|
||||
$prodNames = Get-AssetNames $ProdAssetsDir
|
||||
$distSet = @($distNames | Sort-Object -Unique)
|
||||
$prodSet = @($prodNames | Sort-Object -Unique)
|
||||
|
||||
$onlyDist = @($distSet | Where-Object { $_ -notin $prodSet })
|
||||
$onlyProd = @($prodSet | Where-Object { $_ -notin $distSet })
|
||||
|
||||
if ($onlyDist.Count -eq 0 -and $onlyProd.Count -eq 0) {
|
||||
Write-Host " 校验通过: assets 文件数 $($distSet.Count) 个,生产与 dist 完全一致" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host ' 校验异常:' -ForegroundColor Red
|
||||
if ($onlyDist.Count) { Write-Host " 仅在 dist : $onlyDist" -ForegroundColor Red }
|
||||
if ($onlyProd.Count) { Write-Host " 仅在生产: $onlyProd" -ForegroundColor Red }
|
||||
throw '产物校验失败,请检查!'
|
||||
}
|
||||
|
||||
# 校验 index.html 引用的入口 JS 存在
|
||||
$indexContent = Get-Content $IndexHtml -Raw
|
||||
$entryMatch = [regex]::Match($indexContent, 'src="([^"]+\.js)"')
|
||||
if ($entryMatch.Success) {
|
||||
$entryPath = Join-Path $ProdRoot ($entryMatch.Groups[1].Value.TrimStart('/'))
|
||||
if (Test-Path $entryPath) {
|
||||
Write-Host " 入口 JS 校验通过: $($entryMatch.Groups[1].Value)" -ForegroundColor Green
|
||||
} else {
|
||||
throw "index.html 引用的入口 JS 不存在: $entryPath"
|
||||
}
|
||||
} else {
|
||||
throw 'index.html 中未找到入口 JS 引用'
|
||||
}
|
||||
|
||||
Write-Host ''
|
||||
Write-Host "===== GERP 部署完成 =====" -ForegroundColor Cyan
|
||||
Write-Host '请浏览器强制刷新(Ctrl+F5)加载新产物。' -ForegroundColor Cyan
|
||||
# GERP frontend deploy script: build and sync dist to production dir (TempLate/GERP)
|
||||
#
|
||||
# IMPORTANT: keep this file pure ASCII. PS 5.1 parses BOM-less UTF-8 files
|
||||
# using the ANSI codepage, so non-ASCII text would be garbled.
|
||||
#
|
||||
# Usage:
|
||||
# 1. Clean old artifacts (dist and TempLate/GERP/assets) so no stale hashes remain
|
||||
# 2. Full rebuild (vue-tsc type check + vite build)
|
||||
# 3. Sync dist to TempLate/GERP (index.html + assets)
|
||||
# 4. Verify TempLate matches dist exactly
|
||||
#
|
||||
# Run: .\deploy.ps1
|
||||
# (if execution policy blocks: Set-ExecutionPolicy -Scope Process Bypass)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
$ProjectRoot = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
$DistDir = Join-Path $ProjectRoot 'dist'
|
||||
$ProdRoot = Join-Path (Split-Path -Parent $ProjectRoot) 'TempLate\GERP'
|
||||
$ProdAssetsDir = Join-Path $ProdRoot 'assets'
|
||||
$IndexHtml = Join-Path $ProdRoot 'index.html'
|
||||
|
||||
Write-Host "`n===== GERP DEPLOY START =====" -ForegroundColor Cyan
|
||||
Write-Host "Project dir : $ProjectRoot"
|
||||
Write-Host "Prod dir : $ProdRoot"
|
||||
Write-Host ""
|
||||
|
||||
# 1. Clean old artifacts
|
||||
Write-Host '[1/4] Cleaning old build artifacts...' -ForegroundColor Yellow
|
||||
if (Test-Path $DistDir) {
|
||||
Remove-Item -Recurse -Force $DistDir
|
||||
Write-Host " removed: $DistDir"
|
||||
}
|
||||
if (Test-Path $ProdAssetsDir) {
|
||||
Remove-Item -Recurse -Force $ProdAssetsDir
|
||||
Write-Host " removed: $ProdAssetsDir"
|
||||
}
|
||||
if (Test-Path $IndexHtml) {
|
||||
Remove-Item -Force $IndexHtml
|
||||
Write-Host " removed: $IndexHtml"
|
||||
}
|
||||
Write-Host ''
|
||||
|
||||
# 2. Full build (vue-tsc type check + vite build)
|
||||
Write-Host '[2/4] Running npm run build (type check + full build)...' -ForegroundColor Yellow
|
||||
Push-Location $ProjectRoot
|
||||
try {
|
||||
npm run build
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Build failed, exit code = $LASTEXITCODE"
|
||||
}
|
||||
} finally {
|
||||
Pop-Location
|
||||
}
|
||||
Write-Host ' Build OK'
|
||||
Write-Host ''
|
||||
|
||||
# 3. Sync artifacts to prod dir
|
||||
Write-Host '[3/4] Syncing artifacts to prod dir...' -ForegroundColor Yellow
|
||||
if (-not (Test-Path $ProdRoot)) {
|
||||
New-Item -ItemType Directory -Path $ProdRoot -Force | Out-Null
|
||||
}
|
||||
Copy-Item -Recurse -Force (Join-Path $DistDir '*') $ProdRoot
|
||||
Copy-Item -Force (Join-Path $DistDir 'index.html') $IndexHtml
|
||||
Write-Host ' Sync done'
|
||||
Write-Host ''
|
||||
|
||||
# 4. Verify prod dir matches dist (file name sets)
|
||||
Write-Host '[4/4] Verifying artifact consistency...' -ForegroundColor Yellow
|
||||
function Get-AssetNames([string]$dir) {
|
||||
if (-not (Test-Path $dir)) { return @() }
|
||||
return @(Get-ChildItem -Path $dir -Recurse -File | ForEach-Object { $_.FullName.Substring($dir.Length) })
|
||||
}
|
||||
$distNames = Get-AssetNames (Join-Path $DistDir 'assets')
|
||||
$prodNames = Get-AssetNames $ProdAssetsDir
|
||||
$distSet = @($distNames | Sort-Object -Unique)
|
||||
$prodSet = @($prodNames | Sort-Object -Unique)
|
||||
|
||||
$onlyDist = @($distSet | Where-Object { $_ -notin $prodSet })
|
||||
$onlyProd = @($prodSet | Where-Object { $_ -notin $distSet })
|
||||
|
||||
if ($onlyDist.Count -eq 0 -and $onlyProd.Count -eq 0) {
|
||||
Write-Host " OK: $($distSet.Count) assets, prod matches dist exactly" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host ' MISMATCH:' -ForegroundColor Red
|
||||
if ($onlyDist.Count) { Write-Host " only in dist: $onlyDist" -ForegroundColor Red }
|
||||
if ($onlyProd.Count) { Write-Host " only in prod: $onlyProd" -ForegroundColor Red }
|
||||
throw 'Artifact verification failed!'
|
||||
}
|
||||
|
||||
# Verify the entry JS referenced by index.html exists
|
||||
$indexContent = Get-Content $IndexHtml -Raw
|
||||
$entryMatch = [regex]::Match($indexContent, 'src="([^"]+\.js)"')
|
||||
if ($entryMatch.Success) {
|
||||
$entryPath = Join-Path $ProdRoot ($entryMatch.Groups[1].Value.TrimStart('/'))
|
||||
if (Test-Path $entryPath) {
|
||||
Write-Host " entry JS OK: $($entryMatch.Groups[1].Value)" -ForegroundColor Green
|
||||
} else {
|
||||
throw "index.html entry JS not found: $entryPath"
|
||||
}
|
||||
} else {
|
||||
throw 'No entry JS reference found in index.html'
|
||||
}
|
||||
|
||||
Write-Host ''
|
||||
Write-Host "===== GERP DEPLOY DONE =====" -ForegroundColor Cyan
|
||||
Write-Host 'Please hard-refresh the browser (Ctrl+F5) to load the new build.' -ForegroundColor Cyan
|
||||
Reference in new issue
Block a user