@lhx-kit/offline把
dist/里的页面按白名单打成 zip + manifest,被 Hybrid App 容器解压后加载,完全离线运行。
| 方案 | 问题 |
|---|---|
| 浏览器缓存 | 第一次仍然慢 |
| Service Worker 预缓存 | 第一次仍然慢;SW 本身有注册延迟 |
| CDN + 预压缩 | 网络差时还是要等 |
帮你生成一个符合主流 hybrid 容器约定的离线包。具体容器实现由移动端团队负责。
offline.config.ts| 字段 | 类型 | 说明 |
|---|---|---|
enabled |
boolean |
离线开关;false 时 CLI 直接跳过 |
versions.test / versions.prod |
string |
至少一个;--hybrid-type=test|prod 决定取哪个 |
whitelistPages |
string[] |
哪些 page 进离线包 |
prefetch |
PrefetchRule[] |
容器启动后异步预热的 API 请求列表 |
rollback.strategy |
'previous' | 'none' |
校验失败时用上一版 / 直接走在线 |
metadata |
Record<string, unknown> |
透传到 manifest.metadata,运维系统读 |
outDir |
string |
输出目录,默认 <project.outDir>-offline |
buildOfflineFileFiltershared/ 目录永远被包含(否则白名单页面的 vendor chunk 就丢了):::warning 为什么默认排除 MSW
public/ 里的文件自动拷进 dist/,MSW 也被拷了:::info 为什么用流式 + 并发
| 维度 | 串行(旧) | 并发(新) |
|---|---|---|
| 单文件内存 | ~64KB(流式,OK) | ~64KB(流式,OK) |
| 100 文件总耗时 | ~500ms | ~80ms |
| 产物字节 | 恒定 | 完全一致 |
Node.js 原生 API,零新增依赖(createLimiter 是 15 行内联实现)。
hashConcurrency / copyConcurrency 两个 config 字段可调,EMFILE 敏感的环境可以往下压。
用途:
schemaVersion 保持 '1.0.0',所有新字段都是 optional
packageHash / packageSize 是整包级 SHA-256(流式算 zip 本身),和 assets[i].hash(文件级 SHA-256)分层独立:
把新字段做成 optional 而不是升 schemaVersion,是为了让现有 hybrid 容器和运维系统不做任何改动就能继续消费;需要用整包 hash 的消费方按需读取即可。
stripCdnUrlsFromHtml解决方案:
效果:
离线 WebView 加载 HTML 后,loader 发现 urls 数组空 → 直接 loadLocalFallback → dynamic import 本地 vendor chunk → 零网络请求成功。
.html.br / .html.gz(曾经的隐藏 bug)
@lhx-kit/vite-plugin 的 compress 副插件会给每个 HTML 产出 .br 和 .gz 预压副本。如果只改原 HTML 而不改副本,容器在协商 Accept-Encoding: br 时会拿到旧内容(CDN URL 没清)—— 离线环境下会卡在 DNS 超时 5 秒。
现在的 copyBuildToOffline 在 strip 完 HTML 后会自动同步重压存在的 .br / .gz 副本(仅重压已存在的,不会凭空新建)。失败时 fall back 到不重压,不阻塞构建。
| 方案 | 问题 |
|---|---|
Node 原生 zlib |
只做压缩,不能打 zip 格式 |
archiver |
流式 API,功能重 |
jszip |
浏览器设计,Node 性能一般 |
adm-zip ✅ |
纯 JS 实现,无 native binding,Docker 友好 |
性能:打一个 450KB 的包 < 200ms,完全够用。 更详细的选型对比见 🔬 打包深度剖析。
是容器运行时读 manifest 后的行为约定:
| strategy | 行为 |
|---|---|
'previous' |
当前包校验失败 / prefetch 失败 → 容器回退到上一版离线包 |
'online' |
跳过离线,直接走网络(首次启动或所有版本都坏了时用) |
lhx-kit 只负责把这个字段写进 manifest,具体执行逻辑在 hybrid 容器里(一般由移动端团队实现)。
配置校验(@lhx-kit/config::validateAgainstFilesystem):
inspect 做什么硬错误(missingFiles):manifest 声明的文件物理不存在 → valid: false → CI 非零退出。
软警告(warnings):产物结构"看起来不对"但不能 100% 判定坏了(例如 page 目录里没有 .js chunk)→ 只打印 warning,不翻转 valid。让你在 CI 里能看见可疑信号,但不会被假阳性阻塞。需要严格模式可以在上层加 --strict 开关把 warnings 也视为失败。
这条启发式是 Rolldown 迁移记 那次沉默白屏事故的直接产物。
| 依赖 | 用途 |
|---|---|
adm-zip ^0.5.16 |
纯 JS zip 打包,无原生 binding |
fs-extra ^11.2.0 |
readdir withFileTypes / copyFile / remove 等便利方法 |
zod ^3.24.1 |
OfflineConfig 运行时校验 |
:::warning 下列场景不适合
:::tip 什么时候用