支持 SlimHost 轻量模块打包

This commit is contained in:
meoacgx committed 2026-01-04 01:52:01 +08:00
1 parent 38b9f47659
commit 83562fe074
3 files changed
+118 -4

No files matched your search

+23
View File
@@ -119,6 +119,29 @@ powershell tools/package-module.ps1 -Project "src/YourModule/YourModule.csproj"
> 说明:该脚本依赖 Docker(会拉取/使用 `mcr.microsoft.com/dotnet/sdk:8.0` 镜像)。首次执行会比较慢属正常现象。
### 轻量打包(推荐)
模块运行时会与宿主共享一批“边界程序集”(例如 `TelegramPanel.*`、`Microsoft.Extensions.*`、`Microsoft.AspNetCore.*`、`MudBlazor` 等)。
这些程序集即使被打进模块包里,宿主也会强制从 Default ALC 解析(避免类型身份不一致),因此**携带它们只会徒增包体积**。
打包时可加 `-Slim` 开关自动剔除这类共享程序集:
```powershell
powershell tools/package-module.ps1 -Project "src/YourModule/YourModule.csproj" -Manifest "src/YourModule/manifest.json" -Slim
```
### 更激进的轻量打包(仅限 TelegramPanel 宿主)
如果确定目标宿主就是 TelegramPanel 主程序(必带 EFCore/Sqlite/WTelegramClient 等依赖),并且你希望把模块包做到尽可能小,可以使用 `-SlimHost`:
- 额外剔除:`Microsoft.EntityFrameworkCore*`、`Microsoft.Data.Sqlite`、`SQLitePCLRaw*`、`WTelegramClient`、`SixLabors.ImageSharp`、`PhoneNumbers` 等宿主内置依赖
- 剔除 `runtimes/`(多平台 SQLite native,体积占比很高)
- 剔除 `wwwroot/_content/MudBlazor`(静态资源由宿主提供)
```powershell
powershell tools/package-module.ps1 -Project "src/YourModule/YourModule.csproj" -Manifest "src/YourModule/manifest.json" -SlimHost
```
## manifest.json(示例)
```json
@@ -32,7 +32,14 @@ public sealed class ModuleLoadContext : AssemblyLoadContext
|| name.StartsWith("Microsoft.AspNetCore.", StringComparison.OrdinalIgnoreCase)
|| name.StartsWith("Microsoft.JSInterop", StringComparison.OrdinalIgnoreCase)
|| name.StartsWith("TelegramPanel.", StringComparison.OrdinalIgnoreCase)
|| string.Equals(name, "MudBlazor", StringComparison.OrdinalIgnoreCase))
|| string.Equals(name, "MudBlazor", StringComparison.OrdinalIgnoreCase)
// TelegramPanel 宿主内置依赖:模块可直接复用宿主版本,避免重复携带导致包体积膨胀。
|| string.Equals(name, "WTelegramClient", StringComparison.OrdinalIgnoreCase)
|| string.Equals(name, "PhoneNumbers", StringComparison.OrdinalIgnoreCase)
|| string.Equals(name, "SixLabors.ImageSharp", StringComparison.OrdinalIgnoreCase)
|| string.Equals(name, "Microsoft.Data.Sqlite", StringComparison.OrdinalIgnoreCase)
|| name.StartsWith("Microsoft.EntityFrameworkCore", StringComparison.OrdinalIgnoreCase)
|| name.StartsWith("SQLitePCLRaw", StringComparison.OrdinalIgnoreCase))
return null;
// 2) 其次:如果宿主已经加载过同名程序集,则同样交给 Default ALC(避免重复加载)。
+87 -3
View File
@@ -6,7 +6,17 @@ param(
[string]$Manifest,
[Parameter(Mandatory = $false)]
[string]$OutDir = "artifacts/modules"
[string]$OutDir = "artifacts/modules",
# 轻量打包:剔除会由宿主共享加载的程序集(减少包体积)。
# 说明:宿主的 ModuleLoadContext 会强制让这些程序集由 Default ALC 解析,模块包携带它们只会徒增体积。
[Parameter(Mandatory = $false)]
[switch]$Slim,
# 更激进的轻量打包:额外剔除宿主已内置的第三方依赖(EFCore/Sqlite/WTelegramClient 等)与多平台 native runtimes。
# 适用场景:目标宿主就是 TelegramPanel 主程序(必带这些依赖),并且部署环境固定(例如 Docker linux-x64)。
[Parameter(Mandatory = $false)]
[switch]$SlimHost
)
$ErrorActionPreference = "Stop"
@@ -28,10 +38,18 @@ $moduleId = $moduleId.Trim()
$version = $version.Trim()
if ([string]::IsNullOrWhiteSpace($moduleId)) { throw "manifest.json 缺少 id" }
if ([string]::IsNullOrWhiteSpace($version)) { throw "manifest.json 缺少 version" }
$entryAssembly = ""
try {
if ($null -ne $manifestObj.entry -and $null -ne $manifestObj.entry.assembly) { $entryAssembly = [string]$manifestObj.entry.assembly }
} catch { }
$entryAssembly = [string]$entryAssembly
$entryAssembly = $entryAssembly.Trim()
if ([string]::IsNullOrWhiteSpace($entryAssembly)) { throw "manifest.json 缺少 entry.assembly" }
$buildRootRel = "artifacts/_modulebuild/$moduleId/$version"
$publishRel = "$buildRootRel/publish"
$stagingRel = "$buildRootRel/staging"
$runId = ([Guid]::NewGuid().ToString("N"))
$publishRel = "$buildRootRel/publish/$runId"
$stagingRel = "$buildRootRel/staging/$runId"
$publishHost = Join-Path $repoRoot $publishRel
$stagingHost = Join-Path $repoRoot $stagingRel
@@ -56,6 +74,72 @@ New-Item -ItemType Directory -Force -Path $stagingLib | Out-Null
Copy-Item -Path $manifestPath -Destination (Join-Path $stagingHost "manifest.json") -Force
Copy-Item -Path (Join-Path $publishHost "*") -Destination $stagingLib -Recurse -Force
if ($Slim -or $SlimHost)
{
# 与宿主共享的“边界程序集”(见 src/TelegramPanel.Web/Modules/ModuleLoadContext.cs)。
# 模块包携带这些 dll 会导致体积膨胀(同时也容易造成类型身份不一致的风险),因此在打包阶段直接剔除。
$sharedPatterns = @(
"Microsoft.AspNetCore.*.dll",
"Microsoft.Extensions.*.dll",
"Microsoft.JSInterop*.dll",
"TelegramPanel.*.dll",
"MudBlazor*.dll"
)
foreach ($pattern in $sharedPatterns)
{
Get-ChildItem -Path $stagingLib -Filter $pattern -File -ErrorAction SilentlyContinue | ForEach-Object {
if ($_.Name -ieq $entryAssembly) { return }
try { Remove-Item -Path $_.FullName -Force -ErrorAction Stop } catch { }
}
$pdbPattern = [System.IO.Path]::ChangeExtension($pattern, ".pdb")
Get-ChildItem -Path $stagingLib -Filter $pdbPattern -File -ErrorAction SilentlyContinue | ForEach-Object {
try { Remove-Item -Path $_.FullName -Force -ErrorAction Stop } catch { }
}
}
}
if ($SlimHost)
{
# 宿主已内置且通常在启动早期加载的依赖:把这些也剔除可大幅减小体积(尤其是 SQLitePCL 的多平台 runtimes/native)。
$hostBuiltInPatterns = @(
"Microsoft.EntityFrameworkCore*.dll",
"Microsoft.Data.Sqlite*.dll",
"SQLitePCLRaw*.dll",
"WTelegramClient*.dll",
"SixLabors.ImageSharp*.dll",
"PhoneNumbers*.dll"
)
foreach ($pattern in $hostBuiltInPatterns)
{
Get-ChildItem -Path $stagingLib -Filter $pattern -File -ErrorAction SilentlyContinue | ForEach-Object {
if ($_.Name -ieq $entryAssembly) { return }
try { Remove-Item -Path $_.FullName -Force -ErrorAction Stop } catch { }
}
$pdbPattern = [System.IO.Path]::ChangeExtension($pattern, ".pdb")
Get-ChildItem -Path $stagingLib -Filter $pdbPattern -File -ErrorAction SilentlyContinue | ForEach-Object {
try { Remove-Item -Path $_.FullName -Force -ErrorAction Stop } catch { }
}
}
# 多平台 native runtimes(SQLite)体积很大;TelegramPanel 宿主自身已携带,这里直接剔除。
$runtimesDir = Join-Path $stagingLib "runtimes"
if (Test-Path -Path $runtimesDir)
{
try { Remove-Item -Path $runtimesDir -Recurse -Force -ErrorAction Stop } catch { }
}
# MudBlazor 静态资源由宿主提供;模块包里携带的这份没有实际用途,顺手剔除。
$mudWwwroot = Join-Path $stagingLib "wwwroot/_content/MudBlazor"
if (Test-Path -Path $mudWwwroot)
{
try { Remove-Item -Path $mudWwwroot -Recurse -Force -ErrorAction Stop } catch { }
}
}
New-Item -ItemType Directory -Force -Path $outRoot | Out-Null
$dest = Join-Path $outRoot "$moduleId-$version.tpm"
if (Test-Path -Path $dest) { Remove-Item -Path $dest -Force }