前言 Vite 自诞生以来,凭借其”开发环境原生 ESM + 生产环境 Rollup 打包”的双轨架构,为前端开发带来了革命性的体验提升。然而,这种双轨架构也带来了一些问题:
开发/生产环境不一致 :esbuild(dev)与 Rollup(build)的行为差异可能导致线上问题
性能瓶颈 :大型项目的生产构建仍然较慢
工具链碎片化 :需要维护多个工具的配置和插件
为了解决这些问题,Vite 团队推出了新一代技术栈:
Rolldown :基于 Rust 的统一打包器,替代 esbuild + Rollup
OXC :高性能 JavaScript/TypeScript 工具集合
Vitest :与 Vite 深度集成的测试框架
背景:Void(0) 统一工具链愿景 这些技术的诞生并非孤立事件,而是 Vue 团队更宏大愿景的一部分。尤雨溪在 2023 年提出了 Void(0) 项目,一个类似 Rust Cargo 的统一前端工具链系统。
Void(0) 的核心理念:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 graph TB A[Void 0 统一工具链] --> B[Rolldown 打包器] A --> C[OXC 编译器基础设施] A --> D[Vitest 测试框架] A --> E[oxlint 代码检查] A --> F[oxc-formatter 格式化] B --> G[统一的开发体验] C --> G D --> G E --> G F --> G style A fill:#f96,stroke:#333,stroke-width:3px style G fill:#9f9,stroke:#333,stroke-width:2px
为什么需要 Void(0)?
生态碎片化 :前端工具链过于分散(Webpack、Rollup、esbuild、SWC、Babel 等)
配置地狱 :每个工具都有独立配置,维护成本高
性能瓶颈 :JavaScript 编写的工具在大型项目中性能不足
一致性问题 :开发和生产环境使用不同工具导致行为差异
Void(0) 的目标:
🎯 统一配置 :一份配置文件适用于所有工具
🎯 原生性能 :全部使用 Rust 实现,性能提升 10-100 倍
🎯 完整工具链 :覆盖开发、构建、测试、检查、格式化全流程
🎯 渐进式迁移 :兼容现有生态,平滑过渡
注 :Rolldown 由 Vue 团队主导开发,OXC 由字节跳动团队开发并与 Void(0) 深度协作,两者共同构成了新一代前端工具链的基石。
为什么需要 Rolldown 旧架构的痛点 在 Vite 6 之前,Vite 内部使用了两个打包工具:
1 2 3 4 5 6 7 8 9 graph LR A[源代码] --> B{环境} B -->|开发环境| C[esbuild] B -->|生产环境| D[Rollup] C --> E[开发服务器] D --> F[生产构建产物] style C fill:#f9f,stroke:#333 style D fill:#9ff,stroke:#333
主要问题:
行为不一致 :esbuild 和 Rollup 对模块解析、Tree-shaking、代码分割的处理逻辑不同
插件生态割裂 :需要同时维护 esbuild 插件和 Rollup 插件
性能开销 :两套工具链意味着双倍的解析、转换开销
配置复杂 :需要分别配置 optimizeDeps(esbuild)和 build(Rollup)
Rolldown 的统一愿景 Rolldown 的目标是提供单一、高性能、兼容 Rollup 的打包器 ,统一开发和生产环境:
1 2 3 4 5 6 7 8 9 graph LR A[源代码] --> B[Rolldown] B --> C{模式} C -->|开发模式| D[快速增量构建] C -->|生产模式| E[优化打包] D --> F[开发服务器] E --> G[生产构建产物] style B fill:#0f0,stroke:#333
核心优势:
✅ 统一行为 :开发和生产使用同一套代码路径
✅ 原生性能 :Rust 实现,比 Rollup 快 3-16 倍
✅ 插件兼容 :支持大部分 Rollup 插件
✅ 内存优化 :内存使用减少高达 100 倍
Rolldown:基于 Rust 的统一打包器 核心架构 Rolldown 采用 Rust 编写,基于 OXC 工具链构建,架构如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 graph TB A[入口文件] --> B[OXC Parser] B --> C[AST] C --> D[OXC Transformer] D --> E[转换后的 AST] E --> F[模块图构建] F --> G[Tree-shaking] G --> H[代码分割] H --> I[OXC Minifier] I --> J[输出产物] style B fill:#ff9 style D fill:#ff9 style I fill:#ff9
底层原理详解 模块图构建(Module Graph) Rolldown 的核心是构建一个高效的模块依赖图,这是所有后续优化的基础。
模块图数据结构:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 pub struct ModuleGraph { modules: HashMap<ModuleId, Module>, dependencies: HashMap<ModuleId, Vec <ModuleId>>, entries: Vec <ModuleId>, } pub struct Module { id: ModuleId, path: PathBuf, ast: Program, exports: Vec <Export>, imports: Vec <Import>, has_side_effects: bool , }
构建流程:
1 2 3 4 5 6 7 8 9 10 11 12 graph TB A[入口模块] --> B[解析模块] B --> C[提取 import/export] C --> D{是否有新依赖?} D -->|是| E[解析依赖模块] E --> B D -->|否| F[构建完成] B --> G[缓存模块 AST] C --> H[记录依赖关系] style F fill:#9f9
关键优化:
并行解析 :利用 Rust 的并发能力,多线程解析模块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 pub async fn parse_modules_parallel ( paths: Vec <PathBuf> ) -> Result <Vec <Module>> { let tasks : Vec <_> = paths .into_iter () .map (|path| { tokio::spawn (async move { parse_module (path).await }) }) .collect (); let results = futures::future::join_all (tasks).await ; }
增量更新 :HMR 时只重新解析变化的模块
1 2 3 4 5 6 7 8 9 10 11 12 pub fn update_module (&mut self , id: ModuleId, new_ast: Program) { if let Some (module) = self .modules.get_mut (&id) { module.ast = new_ast; module.exports = extract_exports (&new_ast); module.imports = extract_imports (&new_ast); } self .mark_affected_modules (id); }
Tree-shaking Rolldown 实现了比传统工具更激进的 Tree-shaking,基于 标记-清除(Mark-Sweep) 算法。
算法流程:
1 2 3 4 5 6 7 8 9 10 11 12 13 graph TB A[入口模块] --> B[标记阶段 Mark] B --> C[从入口开始遍历] C --> D[标记使用的导出] D --> E[递归标记依赖] E --> F{还有未访问的依赖?} F -->|是| E F -->|否| G[清除阶段 Sweep] G --> H[移除未标记的代码] H --> I[生成最终产物] style B fill:#ff9 style G fill:#f96
核心实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 pub struct TreeShaker { module_graph: ModuleGraph, used_symbols: HashSet<SymbolId>, } impl TreeShaker { pub fn mark_phase (&mut self , entry: ModuleId) { let mut queue = VecDeque::new (); queue.push_back (entry); while let Some (module_id) = queue.pop_front () { let module = &self .module_graph.modules[&module_id]; for stmt in &module.ast.body { match stmt { Stmt::Import (import) => { for specifier in &import.specifiers { self .mark_symbol (specifier.local); if let Some (source_module) = self .resolve_import (&import.source) { queue.push_back (source_module); } } } Stmt::Expr (expr) => { self .mark_used_identifiers (expr); } _ => {} } } } } pub fn sweep_phase (&mut self ) -> Program { let mut new_program = Program::new (); for module in self .module_graph.modules.values () { for stmt in &module.ast.body { if self .is_statement_used (stmt) { new_program.body.push (stmt.clone ()); } } } new_program } fn is_statement_used (&self , stmt: &Stmt) -> bool { match stmt { Stmt::ExportDecl (export) => { self .used_symbols.contains (&export.symbol_id) } Stmt::FnDecl (func) => { self .used_symbols.contains (&func.ident.symbol_id) } Stmt::Expr (_) => true , _ => false , } } }
高级优化:
副作用分析 :识别纯函数和有副作用的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 pub fn analyze_side_effects (expr: &Expr) -> bool { match expr { Expr::Lit (_) => false , Expr::Call (call) => { if is_pure_function (&call.callee) { false } else { true } } Expr::Assign (_) => true , _ => false , } }
跨模块优化 :内联小型模块
1 2 3 4 5 6 7 8 9 10 pub fn inline_small_modules (&mut self ) { for module in &self .module_graph.modules { if module.size < 1000 && module.import_count == 1 { self .inline_module (module.id); } } }
代码分割(Code Splitting) Rolldown 的代码分割算法基于 模块依赖图分析 和 启发式规则 。
分割策略:
1 2 3 4 5 6 7 8 9 10 11 12 13 graph TB A[分析模块依赖] --> B[识别共享模块] B --> C[计算模块权重] C --> D[应用分割规则] D --> E{是否满足条件?} E -->|是| F[创建新 Chunk] E -->|否| G[合并到现有 Chunk] F --> H[优化 Chunk 大小] G --> H H --> I[生成最终 Chunks] style F fill:#9f9 style I fill:#9f9
核心算法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 pub struct ChunkGraph { chunks: Vec <Chunk>, module_to_chunk: HashMap<ModuleId, ChunkId>, } pub struct Chunk { id: ChunkId, modules: Vec <ModuleId>, size: usize , dependencies: Vec <ChunkId>, } impl ChunkGraph { pub fn create_chunks (&mut self , config: &ChunkConfig) { for entry in &self .module_graph.entries { let chunk = Chunk::new (*entry); self .chunks.push (chunk); } let shared_modules = self .find_shared_modules (); for (module_id, import_count) in shared_modules { if import_count >= config.min_shared_count { let vendor_chunk = self .create_vendor_chunk (module_id); self .chunks.push (vendor_chunk); } } self .split_large_chunks (config.max_chunk_size); } fn find_shared_modules (&self ) -> HashMap<ModuleId, usize > { let mut shared_count = HashMap::new (); for module in self .module_graph.modules.values () { for dep in &module.dependencies { *shared_count.entry (*dep).or_insert (0 ) += 1 ; } } shared_count .into_iter () .filter (|(_, count)| *count > 1 ) .collect () } fn split_large_chunks (&mut self , max_size: usize ) { let mut new_chunks = Vec ::new (); for chunk in &mut self .chunks { if chunk.size > max_size { chunk.modules.sort_by_key (|m| { self .module_graph.modules[m].size }); let mut current_chunk = Chunk::new (chunk.id); let mut current_size = 0 ; for module_id in &chunk.modules { let module_size = self .module_graph.modules[module_id].size; if current_size + module_size > max_size { new_chunks.push (current_chunk); current_chunk = Chunk::new (ChunkId::new ()); current_size = 0 ; } current_chunk.modules.push (*module_id); current_size += module_size; } new_chunks.push (current_chunk); } } self .chunks.extend (new_chunks); } }
并行编译 Rolldown 充分利用 Rust 的并发特性,实现多阶段并行编译。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 use rayon::prelude::*;pub async fn parallel_build ( module_graph: &ModuleGraph ) -> Result <Vec <Chunk>> { let modules : Vec <_> = module_graph .modules .par_iter () .map (|(id, module)| { parse_and_transform (module) }) .collect (); let shaken_modules : Vec <_> = modules .par_iter () .map (|module| { tree_shake (module) }) .collect (); let chunks : Vec <_> = shaken_modules .par_chunks (100 ) .map (|batch| { generate_chunk (batch) }) .collect (); Ok (chunks) }
内存优化 Rolldown 使用多种技术减少内存占用:
零拷贝字符串:
1 2 3 4 5 6 7 8 9 use std::borrow::Cow;pub struct Module <'a > { source: Cow<'a , str >, imports: Vec <&'a Import>, }
Arena 分配器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 use bumpalo::Bump;pub struct Parser <'a > { allocator: &'a Bump, } impl <'a > Parser<'a > { pub fn parse (&self , source: &'a str ) -> &'a Program { let program = self .allocator.alloc (Program::new ()); program } }
关键特性:
与 Rollup 的兼容性 Rolldown 提供与 Rollup 兼容的 API 和插件接口:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import { defineConfig } from 'vite' ;export default defineConfig ({ build : { rollupOptions : { output : { manualChunks : { 'vendor' : ['react' , 'react-dom' ], }, }, plugins : [ ], }, }, });
高级代码分割:advancedChunks Rolldown 引入了比 Rollup 更强大的代码分割配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 export default defineConfig ({ build : { rollupOptions : { output : { advancedChunks : { groups : [ { name : 'react-vendor' , test : /[\\/]node_modules[\\/](react|react-dom)[\\/]/ , priority : 10 , }, { name : 'ui-components' , test : /[\\/]src[\\/]components[\\/]/ , minSize : 20000 , priority : 5 , }, ], minSize : 10000 , maxSize : 500000 , }, }, }, }, });
Hook 过滤优化 Rolldown 通过 Hook 过滤 减少 Rust 和 JavaScript 运行时之间的通信开销:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 export default { plugins : [ { name : 'my-plugin' , resolveId : { filter : /\.custom$/ , handler (id ) { return { id : id + '.resolved' }; }, }, }, ], };
性能基准测试 根据官方测试数据,Rolldown 在各个维度都有显著提升:
项目
规模
Rollup
Rolldown
提升倍数
内存减少
GitLab
大型
45s
17s
2.6x
100x
Excalidraw
中型
8s
0.5s
16x
50x
Vue 3
中型
12s
4s
3x
30x
React Admin
大型
38s
11s
3.5x
60x
性能提升来源:
Rust 原生性能 :相比 JavaScript,Rust 编译后的机器码执行效率高 10-100 倍
并行处理 :充分利用多核 CPU,解析、转换、压缩全部并行化
零拷贝优化 :减少内存分配和数据复制
增量编译 :HMR 时只重新处理变化的模块
统一 AST :OXC 提供的统一 AST 避免重复解析
实际项目对比:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 $ time npm run build real 1m 23s user 2m 15s sys 0m 8s Memory: 1.2GB $ time npm run build real 0m 18s user 0m 45s sys 0m 3s Memory: 180MB
迁移到 Rolldown 使用 rolldown-vite(推荐) rolldown-vite 是 Vite 7 的 Rolldown 版本,作为过渡方案:
1 2 3 4 5 npm install rolldown-vite --save-dev pnpm add -D rolldown-vite
1 2 3 4 5 6 7 8 9 import { defineConfig } from 'rolldown-vite' ;export default defineConfig ({ plugins : [ ], });
等待 Vite 8 正式版 Vite 8 将默认使用 Rolldown,届时可直接升级。
OXC 工具集合
Rust 驱动的编译器基础设施
什么是 OXC? OXC (Oxidation Compiler)是由字节跳动团队开发的高性能 JavaScript/TypeScript 工具链,旨在提供统一的编译器基础设施。
OXC 核心组件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 graph TB A[源代码] --> B[OXC Parser] B --> C[统一 AST] C --> D1[OXC Linter] C --> D2[OXC Transformer] C --> D3[OXC Minifier] C --> D4[OXC Resolver] C --> D5[OXC Formatter] D1 --> E1[Lint 结果] D2 --> E2[转换后的代码] D3 --> E3[压缩后的代码] D4 --> E4[模块路径] D5 --> E5[格式化的代码] style C fill:#f96
OXC Parser
支持 :ES2024、TypeScript、JSX、Flow
性能 :比 SWC 快 3 倍
特性 :零拷贝、增量解析
1 2 3 4 5 6 7 pub struct Parser <'a > { source: &'a str , allocator: &'a Allocator, tokens: Vec <Token<'a >>, }
功能 :TypeScript 类型擦除、JSX 转换、语法降级
性能 :比 Babel 快 40-70 倍
1 2 3 4 5 6 7 8 9 10 11 import { transform } from '@oxc-transform/core' ;const result = transform (code, { jsx : { runtime : 'automatic' , }, typescript : { onlyRemoveTypeImports : true , }, });
OXC Minifier
性能 :比 SWC 快 8 倍 ,比 esbuild 快 50%
特性 :保留语义的激进优化
1 2 3 4 5 6 export default defineConfig ({ build : { minify : 'oxc' , }, });
OXC Linter
性能 :比 ESLint 快 50-100 倍
兼容性 :支持大部分 ESLint 规则
1 2 3 4 5 npm install oxlint --save-dev npx oxlint src/
1 2 3 4 5 6 7 8 { "rules" : { "no-unused-vars" : "error" , "no-console" : "warn" }, "extends" : ["eslint:recommended" ] }
OXC Resolver
性能 :比 webpack 快 28 倍
功能 :支持 exports、imports、条件导出
统一 AST 的价值 OXC 的核心优势在于统一 AST :
1 2 3 4 5 6 7 8 9 graph LR A[源代码] --> B[OXC Parser] B --> C[统一 AST] C --> D[Linter] C --> E[Transformer] C --> F[Minifier] C --> G[Bundler] style C fill:#f66
好处:
零序列化开销 :各工具共享同一份 AST,无需重复解析
内存效率 :单次解析,多次使用
一致性 :所有工具看到的代码结构完全一致
OXC 在 Rolldown 中的应用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 async function bundle (entry ) { const ast = oxc.parse (code); const transformed = oxc.transform (ast, options); const graph = buildModuleGraph (transformed); const shaken = treeShake (graph); const minified = oxc.minify (shaken); return minified; }
Vitest
与 Vite 深度集成的测试框架
为什么选择 Vitest? 传统测试框架(如 Jest)存在以下问题:
❌ 需要单独的配置文件
❌ 不支持 ESM(或支持不完善)
❌ 启动慢(需要预编译)
❌ 与 Vite 配置不一致
Vitest 的优势:
✅ 复用 Vite 配置和插件
✅ 原生 ESM 支持
✅ 极速启动(利用 Vite 的 HMR)
✅ 兼容 Jest API
核心架构 1 2 3 4 5 6 7 8 9 10 11 12 13 graph TB A[测试文件] --> B[Vitest Runner] B --> C[Vite Dev Server] C --> D[模块图] D --> E[HMR] E --> F[增量测试] B --> G[测试上下文] G --> H[断言] G --> I[Mock] G --> J[覆盖率] style C fill:#9f9
快速开始 安装
配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 import { defineConfig } from 'vite' ;export default defineConfig ({ test : { environment : 'jsdom' , globals : true , coverage : { provider : 'v8' , reporter : ['text' , 'json' , 'html' ], exclude : [ 'node_modules/' , 'dist/' , '**/*.spec.ts' , ], }, browser : { enabled : false , name : 'chrome' , }, }, });
编写测试 1 2 3 4 5 6 7 8 9 10 11 12 13 import { describe, it, expect } from 'vitest' ;import { sum } from './sum' ;describe ('sum' , () => { it ('should add two numbers' , () => { expect (sum (1 , 2 )).toBe (3 ); }); it ('should handle negative numbers' , () => { expect (sum (-1 , -2 )).toBe (-3 ); }); });
运行测试 1 2 3 4 5 6 7 8 9 10 11 npx vitest npx vitest --watch npx vitest run npx vitest --coverage
高级特性 Workspace 模式 对于 Monorepo 项目:
1 2 3 4 5 6 7 8 9 10 export default [ 'packages/*/vitest.config.ts' , { test : { name : 'integration' , include : ['tests/integration/**/*.test.ts' ], }, }, ];
浏览器模式 1 2 3 4 5 6 7 8 9 10 11 export default defineConfig ({ test : { browser : { enabled : true , name : 'chrome' , headless : true , provider : 'playwright' , }, }, });
1 2 3 4 5 6 7 8 import { test, expect } from 'vitest' ;test ('should render button' , async () => { document .body .innerHTML = '<button>Click me</button>' ; const button = document .querySelector ('button' ); expect (button?.textContent ).toBe ('Click me' ); });
快照测试 1 2 3 4 5 6 7 8 9 10 11 import { test, expect } from 'vitest' ;test ('should match snapshot' , () => { const data = { name : 'John' , age : 30 , hobbies : ['reading' , 'coding' ], }; expect (data).toMatchSnapshot (); });
Mock 和 Spy 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import { vi, test, expect } from 'vitest' ;test ('should mock fetch' , async () => { global .fetch = vi.fn (() => Promise .resolve ({ json : () => Promise .resolve ({ data : 'mocked' }), }) ); const response = await fetch ('/api/data' ); const data = await response.json (); expect (data).toEqual ({ data : 'mocked' }); expect (fetch).toHaveBeenCalledWith ('/api/data' ); });
性能对比
项目规模
Jest
Vitest
提升
小型(50 测试)
3.2s
0.8s
4x
中型(500 测试)
18s
6.3s
2.9x
大型(2000 测试)
65s
22s
3x
内存占用:
Jest:~400MB
Vitest:~240MB(减少 40% )
迁移到新版 Vite 生态 迁移前准备
[ ] 确认 Node.js 版本 >= 18
[ ] 备份现有配置文件
[ ] 检查插件兼容性
[ ] 运行现有测试套件
Rolldown 迁移
[ ] 安装 rolldown-vite
[ ] 更新 vite.config.js
[ ] 测试开发环境
[ ] 测试生产构建
[ ] 验证插件功能
OXC 工具迁移
[ ] 替换 ESLint 为 oxlint(可选)
[ ] 配置 OXC Minifier
[ ] 测试代码压缩效果
Vitest 迁移
[ ] 安装 Vitest
[ ] 迁移 Jest 配置
[ ] 更新测试脚本
[ ] 运行测试验证
[ ] 配置 CI/CD
完整配置示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 import { defineConfig } from 'vite' ;import react from '@vitejs/plugin-react' ;export default defineConfig ({ plugins : [react ()], build : { minify : 'oxc' , rollupOptions : { output : { advancedChunks : { groups : [ { name : 'vendor' , test : /[\\/]node_modules[\\/]/ , priority : 10 , }, ], }, }, }, }, test : { globals : true , environment : 'jsdom' , setupFiles : './tests/setup.ts' , coverage : { provider : 'v8' , reporter : ['text' , 'json' , 'html' ], include : ['src/**/*.{ts,tsx}' ], exclude : [ 'src/**/*.test.{ts,tsx}' , 'src/**/*.spec.{ts,tsx}' , ], }, }, });
package.json 脚本 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 { "scripts" : { "dev" : "vite" , "build" : "vite build" , "preview" : "vite preview" , "test" : "vitest" , "test:ui" : "vitest --ui" , "test:run" : "vitest run" , "test:coverage" : "vitest --coverage" , "lint" : "oxlint src/" } , "devDependencies" : { "vite" : "^6.0.0" , "vitest" : "^2.0.0" , "oxlint" : "^0.10.0" , "@vitest/ui" : "^2.0.0" , "@vitest/coverage-v8" : "^2.0.0" } }
CI/CD 配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 name: CI on: [push , pull_request ]jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' cache: 'npm' - name: Install dependencies run: npm ci - name: Lint run: npm run lint - name: Test run: npm run test:run - name: Coverage run: npm run test:coverage - name: Build run: npm run build - name: Upload coverage uses: codecov/codecov-action@v4 with: files: ./coverage/coverage-final.json
性能对比与最佳实践 代码分割策略 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 export default defineConfig ({ build : { rollupOptions : { output : { advancedChunks : { groups : [ { name : 'framework' , test : /[\\/]node_modules[\\/](react|react-dom|vue)[\\/]/ , priority : 20 , }, { name : 'ui' , test : /[\\/]node_modules[\\/](antd|@mui)[\\/]/ , priority : 15 , }, { name : 'components' , test : /[\\/]src[\\/]components[\\/]/ , minSize : 20000 , priority : 10 , }, { name : 'utils' , test : /[\\/]src[\\/]utils[\\/]/ , minSize : 10000 , priority : 5 , }, ], }, }, }, }, });
测试优化 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 export default defineConfig ({ test : { pool : 'threads' , poolOptions : { threads : { singleThread : false , maxThreads : 4 , }, }, watchExclude : [ '**/node_modules/**' , '**/dist/**' , '**/.git/**' , ], isolate : true , coverage : { provider : 'v8' , reportsDirectory : './coverage' , clean : true , }, }, });
Lint 优化 1 2 3 4 5 npx oxlint src/ --fix npx eslint src/ --cache --max-warnings 0
总结与展望 核心要点
Rolldown 统一了开发和生产环境,解决了双轨架构的不一致问题
OXC 提供了高性能的编译器基础设施,显著提升了构建速度
Vitest 与 Vite 深度集成,提供了极速的测试体验
技术栈对比
工具
旧方案
新方案
核心优势
打包器
esbuild + Rollup
Rolldown
统一、快 3-16 倍
解析器
esbuild
OXC Parser
快 3 倍
转换器
esbuild/Babel
OXC Transformer
快 40-70 倍
压缩器
esbuild/Terser
OXC Minifier
快 8 倍
Linter
ESLint
oxlint
快 50-100 倍
测试框架
Jest
Vitest
快 3-4 倍
参考资料 官方文档
GitHub 仓库
技术文章
性能基准