Ionify vs Vite:你的构建工具内部到底发生了什么
Source: Dev.to
大多数开发者使用 Vite 并信任它。它速度快、设计良好,而且不干扰开发。
但 Vite 的架构——以及所有其他主流构建工具——都内置了一个根本性的假设,而 Ionify 对此提出了挑战。
假设: 每次构建都从零开始。
无状态构建问题
当你运行 vite build 时,大致会发生以下过程:
Vite 启动 esbuild/Rollup(现在常常由 Rolldown + Oxc 提供动力)。
每个文件独立地经过其插件链
main.tsx → TS plugin → JSX plugin → output utils.ts → TS plugin → output index.css → CSS plugin → output所有内容被打包。
下次再运行时,同样的过程会再次执行。系统并不会记住已经执行过的内容;TS 插件并不知道 JSX 插件已经处理过某个文件,打包器也不知道哪些文件发生了变化。该流水线 天生无状态。这不是 bug——这是为了简化和可预测性而做出的刻意选择,但在大规模项目中会带来真实的性能成本。
Ionify 对此的不同思考方式
与其反复转换文件,Ionify 直接处理它们。
内容可寻址存储 (CAS)
每个模块都会获得一个内容哈希:
SHA-256(source content + config version) → CAS key结果存放在 CAS 目录中:
.ionify/
cas/
/
/
transformed.js
transformed.js.map相同的内容 + 相同的配置 → 相同的哈希 → 完全跳过转换。未更改的模块根本不进行转换。
持久化图
Vite 在每次启动开发服务器时都会重新构建模块图。Ionify 持久化 该图:
.ionify/
graph.db ← sled‑backed embedded KV store (Rust)当文件发生变化时,Ionify 会在逆向依赖索引上执行 BFS,精确找出受影响的模块。在一个拥有 500 个模块的项目中,修改一个工具文件可能只会使 12 个模块失效,而不是全部 500 个。
版本隔离:配置更改使所有缓存失效
持久缓存必须处理配置更改。Ionify 通过从配置计算出的确定性 版本哈希 来解决此问题,确保任何配置修改都会使相关缓存失效。
四层 CAS 架构
随着系统的演进,Ionify 引入了四个不同的缓存层,每个层解决不同的问题。
第 1 层 — 模块转换缓存
按内容哈希键存储已转换的模块输出。
第 2 层 — 依赖制品存储
缓存已编译的第三方依赖。
第 3 层 — 压缩 CAS
对构建产出进行预压缩(Brotli‑11、gzip‑9),一次压缩后永久提供。
第 4 层 — 块输出 CAS
缓存由打包器生成的最终块文件。
实际配置:从 Vite 迁移
以下是一个来自已从 Vite 切换的生产项目的 ionify.config.ts 示例:
import { defineConfig } from 'ionify'
export default defineConfig({
entry: '/src/main.tsx',
server: {
https: true,
},
resolve: {
// Same aliases as tsconfig — Ionify reads these natively
// Note: if your tsconfig.json is JSONC (comments/trailing commas),
// auto‑alias parsing currently fails — specify manually here
alias: {
'@@': '/',
'@@/Core': '/Core/src',
'@': '/src',
},
extensions: ['.mjs', '.js', '.mts', '.ts', '.jsx', '.tsx', '.json'],
conditions: ['import', 'module', 'browser', 'default'],
mainFields: ['module', 'jsnext:main', 'jsnext', 'main'],
},
optimizeDeps: {
include: ['moment-hijri'], // pre‑warm known‑problem deps
sharedChunks: 'auto',
packSlimming: 'auto',
vendorPacks: 'auto',
},
build: {
target: 'esnext',
},
})该项目包含超过 10 k 个模块。迁移到 Ionify 后:
- 冷构建: 3.2 秒(比 Vite 的 3.7 秒更快)
- 热构建: 2.2 秒(比 Vite 的 3.7 秒更快)
根本区别
| 构建工具 | 核心假设 |
|---|---|
| Vite | 每次构建都是独立的。 |
| Ionify | 上一次构建的大部分工作仍然有效。 |
这两种假设都合理。Vite 的方式导致系统更简单、更可预测。Ionify 的方法让第二次、第十次以及 CI 构建都能受益于之前的工作,使得图中 “transform” 部分大多为空——这不是因为复杂性被隐藏,而是因为大多数转换根本没有执行。
Ionify 目前已在生产环境中使用。