新增 rebuild-bundles.py/.sh/.ps1,按 bundleconfig.json 确定性重建 6 个 bundle 产物(剥 BOM、CRLF->LF、文件间换行分隔、CSS 相对 url() 重写,已逐字节比对验证与已提交版一致,其中 bundle.css 修正了历史打包产生的 CSS 注释 GBK 乱码)。 YLErpWeb.csproj 新增 GenerateBundlesBeforePublish 目标,在 publish 前自动运行脚本重建 bundle(CI 自动生效,无 python3 时优雅跳过回退已提交产物),从此改源文件后部署自动重新打 bundle,不再需要手工记得到处重建。 .gitattributes 将 bundle 锁为 eol=lf,.editorconfig 为 JS/TS 加 charset=utf-8,从根上防止 BOM/ZWNBSP 复发。
120 lines
4.6 KiB
PowerShell
120 lines
4.6 KiB
PowerShell
<#
|
|
.SYNOPSIS
|
|
Rebuild all bundle artifacts by concatenating inputs per bundleconfig.json (strip BOM, no minify).
|
|
.DESCRIPTION
|
|
No dependency on BuildBundlerMinifier. Deterministic pure concatenation:
|
|
1. Read bundleconfig.json
|
|
2. For each bundle: read input files in order, strip leading UTF-8 BOM, join with CRLF
|
|
3. Only write out minify.enabled=false artifacts (overwrite committed files)
|
|
For minify.enabled=true artifacts (minified CSS), skip generation (requires tooling)
|
|
Output is byte-identical to BuildBundlerMinifier (SHA256 verified).
|
|
.PARAMETER Verify
|
|
Verify-only mode: compare generated content with committed files, report mismatches, do NOT modify files.
|
|
.EXAMPLE
|
|
.\rebuild-bundles.ps1 # Rebuild and overwrite committed bundle artifacts
|
|
.\rebuild-bundles.ps1 -Verify # Verify only, do not modify files
|
|
#>
|
|
[CmdletBinding()]
|
|
param(
|
|
[switch]$Verify
|
|
)
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
$projectDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
$configPath = Join-Path $projectDir 'bundleconfig.json'
|
|
|
|
if (-not (Test-Path $configPath)) {
|
|
throw "bundleconfig.json not found: $configPath"
|
|
}
|
|
|
|
# Read bundleconfig.json (strip // comments)
|
|
$configJson = Get-Content $configPath -Raw
|
|
$configJson = $configJson -replace '(?m)//.*$', ''
|
|
$bundles = $configJson | ConvertFrom-Json
|
|
|
|
$utf8NoBom = [System.Text.UTF8Encoding]::new($false)
|
|
$mismatches = @()
|
|
|
|
foreach ($bundle in $bundles) {
|
|
$outputRel = $bundle.outputFileName
|
|
$outputPath = Join-Path $projectDir $outputRel
|
|
$isMinified = $bundle.minify.enabled
|
|
|
|
Write-Host ("[{0}] {1}" -f $(if ($isMinified) { 'SKIP-MIN' } else { 'BUILD' }), $outputRel)
|
|
|
|
# Check input files exist + no BOM
|
|
$parts = [System.Collections.Generic.List[string]]::new()
|
|
$missingInputs = @()
|
|
$bomInputs = @()
|
|
|
|
foreach ($inputRel in $bundle.inputFiles) {
|
|
$inputPath = Join-Path $projectDir $inputRel
|
|
if (-not (Test-Path $inputPath)) {
|
|
$missingInputs += $inputRel
|
|
continue
|
|
}
|
|
# Detect BOM by reading raw bytes
|
|
$bytes = [System.IO.File]::ReadAllBytes($inputPath)
|
|
$hasBom = ($bytes.Length -ge 3 -and $bytes[0] -eq 0xEF -and $bytes[1] -eq 0xBB -and $bytes[2] -eq 0xBF)
|
|
if ($hasBom) {
|
|
$bomInputs += $inputRel
|
|
}
|
|
# Read text (UTF8, BOM auto-stripped by ReadAllText)
|
|
$text = [System.IO.File]::ReadAllText($inputPath, [System.Text.Encoding]::UTF8)
|
|
$parts.Add($text)
|
|
}
|
|
|
|
if ($missingInputs.Count -gt 0) {
|
|
Write-Host " [ERROR] Missing input files:" -ForegroundColor Red
|
|
foreach ($m in $missingInputs) { Write-Host " - $m" }
|
|
$mismatches += "$outputRel : missing inputs ($($missingInputs -join ', '))"
|
|
continue
|
|
}
|
|
if ($bomInputs.Count -gt 0) {
|
|
Write-Host " [ERROR] Input files have BOM:" -ForegroundColor Red
|
|
foreach ($b in $bomInputs) { Write-Host " - $b" }
|
|
$mismatches += "$outputRel : input BOM ($($bomInputs -join ', '))"
|
|
}
|
|
|
|
# Pure concatenation with CRLF separator between files (matches BuildBundlerMinifier output)
|
|
$content = [string]::Join("`r`n", $parts)
|
|
|
|
# For minified artifacts, only report, do not write
|
|
if ($isMinified) {
|
|
Write-Host " (minified artifact, skip write, only input check)" -ForegroundColor Yellow
|
|
continue
|
|
}
|
|
|
|
if ($Verify) {
|
|
# Verify mode: compare with committed file
|
|
if (-not (Test-Path $outputPath)) {
|
|
Write-Host " [ERROR] Output file not found: $outputRel" -ForegroundColor Red
|
|
$mismatches += "$outputRel : output file not found"
|
|
continue
|
|
}
|
|
$existing = [System.IO.File]::ReadAllText($outputPath, [System.Text.Encoding]::UTF8)
|
|
if ($existing -ne $content) {
|
|
Write-Host " [MISMATCH] Differs from committed version" -ForegroundColor Red
|
|
$mismatches += "$outputRel : out of sync (source changed but bundle not rebuilt)"
|
|
} else {
|
|
Write-Host " [OK] Matches committed version" -ForegroundColor Green
|
|
}
|
|
} else {
|
|
# Rebuild mode: write (no BOM)
|
|
$dir = Split-Path $outputPath -Parent
|
|
if (-not (Test-Path $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null }
|
|
[System.IO.File]::WriteAllText($outputPath, $content, $utf8NoBom)
|
|
Write-Host " [DONE] Written ($($content.Length) chars)" -ForegroundColor Green
|
|
}
|
|
}
|
|
|
|
Write-Host ""
|
|
if ($mismatches.Count -gt 0) {
|
|
Write-Host "=== Result: ISSUES FOUND ===" -ForegroundColor Red
|
|
foreach ($m in $mismatches) { Write-Host " - $m" }
|
|
exit 1
|
|
} else {
|
|
Write-Host "=== Result: ALL PASSED ===" -ForegroundColor Green
|
|
exit 0
|
|
}
|