Repository navigation
AOT Compile and Runtime zh
本页记录 SPACK 当前的 compiler/runtime 拆分,以及后续仍要推进的设计方向。
从 v2.0.3 开始,SPACK 发布独立的 runtime 和 compiler 产物:
-
spack-runtime可以服务普通前端dist目录,也可以服务 compiler 生成的.spackbundle。 -
spack-compiler负责构建期优化并写入.spackbundle。 - 压缩和图片生成属于 compiler 路径,不属于生产 runtime 路径。
- runtime 不需要 libvips。
SPACK 应该把前端构建产物编译成不可变、预优化的 .spack 文件,然后由极简 runtime 提供 HTTP 静态资源交付。
前端构建产物
-> spack-compiler compile ./dist -o app.spack
-> spack-compiler verify app.spack
-> spack-runtime serve ./app.spack
-> HTTP 静态资源交付
为了兼容和简化迁移,直接目录服务能力仍然保留:
前端构建产物
-> spack-runtime serve ./dist
-> 不经过 AOT 预优化的 HTTP 静态资源交付
compiler 可以比较重。runtime 应该保持很小。
| 产物 | 职责 |
|---|---|
spack-compiler |
构建期工具。扫描资源、生成变体、写入 .spack、校验并输出报告。 |
spack-runtime |
生产 runtime。加载 .spack 或服务本地目录,选择响应计划并发送 payload。 |
spack runtime 镜像 |
默认 Debian slim runtime 镜像。 |
spack:alpine runtime 镜像 |
Alpine runtime flavor。 |
spack-compiler 镜像 |
包含 libvips 运行依赖的 Debian slim compiler 镜像。 |
静态资源交付 runtime 不应该在生产环境携带构建期图片和压缩工具链。
AOT 模型把确定性工作移动到构建期。生产环境只保留数据面:
- 不包含运行时图片流水线。
- 不包含运行时压缩流水线。
- bundle 模式不需要 source watcher。
- bundle 模式不需要 artifact cache janitor。
- 请求路径不会每次解压
.spack。
当前 bundle 使用 zstd 作为 bundle 级压缩,并包含 SPACK metadata 供 runtime 加载和校验。
app.spack
bundle header
metadata / index
compressed payload section
verification data
关键 runtime 契约不是内部容器实现,而是:
- 相同输入和配置下,compiler 写出的 bundle 应该可复现。
- bundle 发布前可以由 compiler 校验。
- runtime 启动时校验 bundle。
- runtime 启动时只解压一次 bundle 到受管临时目录。
- 请求从解压后的本地文件服务,不会每次请求都解压
.spack。
启动解压可以保持 runtime 简单,并保留高效的本地文件服务行为,同时避免把整个 bundle payload 常驻内存。
compiler 必须强制执行这些规则:
- entry path 使用 UTF-8,并统一为
/分隔。 - 拒绝绝对路径。
- 拒绝
..路径逃逸。 - 拒绝反斜杠路径。
- 拒绝符号链接。
- SPACK metadata 路径为保留路径。
- entry 按稳定顺序排序。
- 时间戳由 reproducible 模式或
SOURCE_DATE_EPOCH固定。 - 文件权限固定。
- bundle 校验必须拒绝 malformed metadata、非法路径和截断 payload。
runtime 不应该在每次请求时扫描源目录或 bundle entry。
索引应该包含:
- 字符串表。
- 路由表。
- 响应表。
- Header 表。
- 变体表。
- Blob 表。
- 完整性元数据。
响应指向 compiler 准备好的 payload,或者直接目录 catalog 中的 payload。
route path
-> route id
-> selected response id
-> selected encoding variant
-> extracted local file 或 direct source file
-> payload delivery
compiler 可以提前完成所有不依赖单个请求的工作。
compiler 负责路径归一化、重复路径检测、大小写冲突检测、SPA fallback 目标校验,并写入路由记录。
runtime 只做路由查找。
compiler 写入响应记录,包括:
- 状态码。
- Content-Type。
- Content-Length。
- ETag。
- Last-Modified 策略。
- Cache-Control。
- Vary。
- Link 资源提示。
- 安全响应头。
- Payload 引用。
runtime 只需要选择响应计划并写出。
compiler 根据预算和收益率生成 Brotli、Gzip、Zstd 变体。
runtime 根据 Accept-Encoding 查表选择变体。
图片生成属于 compiler。
compiler 使用支持 libvips 的构建或镜像生成不同宽度和格式的图片变体。runtime 不需要 libvips。
常用矩阵参数是 --image.enable、--image.widths 和 --image.formats。发布校验和 Refine AOT benchmark 会通过 SPACK_IMAGE_ENABLE、SPACK_IMAGE_WIDTHS、SPACK_IMAGE_FORMATS 透传同一组设置。
compiler 应该强制执行:
- 不放大原图。
- 最大源文件字节数。
- 最大解码像素数。
- 单资源最大变体数量。
- 最大 bundle 膨胀比例。
- 最小收益率。
- 图片格式能力检测。
当 bundle layout 支持时,compiler 对 payload 做 hash,相同内容只保存一次。
去重范围包括原始文件、压缩变体、图片变体和源目录中的重复文件。
compiler 应该把首屏热资源放在相邻位置:
-
index.html。 - 入口 CSS。
- 入口 JavaScript。
- Vendor JavaScript。
- 关键字体。
- 关键图片。
大下载文件、source map 和冷资源可以放在后面。
compiler 可以分析 index.html、Vite manifest、Webpack manifest、Rspack manifest 和自定义资源清单。
它可以校验缺失引用,并生成 resource hints。
V1 应该优先生成 Link 响应头,而不是直接改写 HTML。
compiler 提前准备 ETag、HEAD、304、Range、206、416 所需的元数据。
Range 请求优先使用 identity payload,不对预压缩变体做字节范围交付。
runtime 应该负责:
- 打开
.spack或本地源目录。 - 启动时校验 bundle metadata 和边界。
- 启动时只解压一次
.spack到受管临时目录。 - 构建或加载路由查找结构。
- 选择响应计划。
- 服务解压后的本地文件或直接源文件。
- 提供健康检查、指标、日志和优雅关闭。
默认 runtime 不应该包含:
- libvips。
- 运行时图片流水线。
- 运行时压缩流水线。
- bundle 模式的 source watcher。
- bundle 模式的 catalog rescan。
- bundle 模式的 artifact janitor。
- bundle 模式的动态 artifact cache。
- bundle 模式的运行时源文件 hash。
从 v2.0.5 之后的下一次发布开始,spack-compiler compile 支持可选 JSON 报告:
spack-compiler compile ./dist -o app.spack --report compile-report.json报告会记录:
- 输入 asset 数量。
- variant 数量。
- source sidecar 数量。
- 源文件总字节数。
- bundle 文件字节数。
- 编译耗时。
- 压缩模式。
前端构建产物里的外部压缩 sidecar 默认不直接信任。SPACK 会同时校验 HTTP content coding,以及二进制图片资源解码后的 magic。例如 hero.png.gz 必须是合法 gzip 流,并且解码后必须是 PNG 字节,才会被注册为 source sidecar variant。无效 sidecar 会被忽略,runtime 会 fallback 到真实源文件。
spack-compiler verify app.spack 应该支持完整校验。
spack-compiler decompile app.spack 应该支持为 CI 和调试提取或检查 bundle 内容。
spack-runtime serve app.spack 应该支持快速启动校验。
校验范围包括:
- Bundle path 规则。
- Metadata 格式版本。
- Section 边界。
- Route 引用。
- Response 引用。
- Blob 引用。
- Payload hash。
- Bundle hash。
| 能力 | 状态 |
|---|---|
| runtime 直接目录服务 | 已支持。 |
| compiler/runtime 拆分 | 已支持。 |
.spack bundle 编译 |
已支持。 |
.spack 校验 |
已支持。 |
| bundle 启动解压 | 已支持。 |
| runtime 每请求解压 | 不使用。 |
| runtime libvips 依赖 | 不需要。 |
| compiler libvips 依赖 | compiler 镜像需要。 |
| manifest 分析和高级 layout 优化 | 后续工作。 |
| 签名、overlay、mmap 和 offset sendfile | 后续工作。 |
生产可用的 AOT 路径应该满足:
- 相同输入和配置下,
spack-compiler compile ./dist -o app.spack产物可复现。 - 部署前
spack-compiler verify app.spack通过。 -
spack-runtime serve ./app.spack不扫描源目录即可服务资源。 - runtime 启动不执行压缩和图片生成。
- 请求不会重复解压 bundle。
- ETag、HEAD、304、Range、SPA fallback 和压缩变体选择都来自准备好的 metadata。
- 生产 runtime 不依赖 libvips。
- runtime 镜像明显小于 compiler 镜像。
- 热路径性能不低于 direct prepared filesystem mode。