Rust 在前端工具链的崛起:2026 年生态全景与实战指南
2026 年,Rust 正在从前端构建的幕后走向舞台中央。从 Rolldown 到 Oxc,从 Rspack 到 Turbopack,Rust 编写的工具正在以惊人的性能优势全面超越传统的 JavaScript 方案。本文将深入解析这场前端工具链的 Rust 革命,带你掌握最新的技术趋势和实战技能。
一、引言:为什么是 Rust?
1.1 前端工具链的性能困境
在过去的十年里,前端开发经历了从 jQuery 到 React/Vue/Angular 的范式转变,构建工具也随之演进。然而,随着应用规模的不断扩大,传统的 JavaScript 构建工具逐渐显露出性能瓶颈:
- Webpack:功能强大但配置复杂,构建速度随着项目增长线性下降
- Rollup:Tree shaking 优秀,但单线程处理大型项目力不从心
- ESLint:规则丰富,但每次检查都是全量扫描,修改一行代码需要等待数秒
这些问题在大型企业级项目中尤为突出。一个拥有数百个组件的前端项目,一次完整的构建可能需要数分钟甚至更长时间。开发体验大打折扣,团队效率深受影响。
1.2 Rust 的技术红利
Rust 之所以能够在前端工具链领域异军突起,得益于其独特的技术特性:
零成本抽象(Zero-Cost Abstractions):Rust 允许开发者使用高级抽象而不会引入运行时开销。这意味着你可以用优雅的 Rust 代码编写高性能工具,而不必为了性能牺牲代码可读性。
// Rust 的迭代器使用零成本抽象
// 下面的代码在编译时会优化为等价的汇编,没有任何运行时开销
let result: Vec<i32> = (0..1000)
.filter(|x| x % 2 == 0)
.map(|x| x * 2)
.collect();
内存安全且无需 GC:Rust 的所有权系统(Ownership)和借用检查器(Borrow Checker)在编译期就消除了内存泄漏和悬垂指针。这意味着 Rust 程序可以长时间运行而不出现内存抖动,这对于构建工具尤为重要。
// 所有权系统示例
fn process_string(s: String) -> String {
// s 在这里被"移动"进函数
// 函数返回时,s 的所有权会被转移出去
// 无需垃圾回收器介入
s.to_uppercase()
}
fearless concurrency(无畏并发):Rust 的类型系统确保了多线程代码在编译期就是安全的。构建工具可以充分利用多核 CPU,实现线性性能提升。
use std::thread;
// 并行处理多个文件,无需担心数据竞争
fn process_files_parallel(files: &[PathBuf]) -> Vec<Result<FileInfo>> {
files.par_iter()
.map(|file| process_file(file))
.collect()
}
1.3 2026 年的生态现状
2026 年,Rust 在前端工具链领域已经形成了完整的生态系统:
| 工具类型 | JavaScript 方案 | Rust 方案 | 性能提升 |
|---|---|---|---|
| 构建工具 | Webpack 5 | Rspack | 10-20x |
| 打包器 | Rollup | Rolldown | 5-10x |
| Linter | ESLint | Oxc | 50-100x |
| 代码压缩 | Terser | SWC | 20-30x |
| 打包工具 | esbuild (Go) | Rolldown | 2-5x |
这些数字不是理论推算,而是来自生产环境的真实benchmark。接下来,让我们深入解析每个领域的代表性项目。
二、Rolldown:Vite 的下一代打包器
2.1 项目背景与定位
Rolldown 由 Vite 团队开发,目标是成为 Vite 的默认打包引擎。它在保持 Rollup API 100% 兼容的前提下,通过 Rust 重写核心逻辑,实现了 5-10 倍的构建速度提升。
为什么选择 Rust 而不是 Go?
Vite 团队在技术选型时进行了深入调研。Go 虽然简单易学,但在以下方面不如 Rust:
- 更细粒度的内存控制:Rust 的生命周期和所有权模型可以精确控制内存分配时机
- 更丰富的生态:Rust 生态系统中有成熟的字节码处理、AST 操作库
- 与 Vite 生态的无缝集成:Rolldown 使用 Rust 编写,但保持与 JavaScript 生态的紧密集成
2.2 架构设计
Rolldown 的核心架构包含以下组件:
┌─────────────────────────────────────────────────────┐
│ Rolldown │
├─────────────────────────────────────────────────────┤
│ ┌─────────────┐ ┌─────────────┐ ┌───────────┐ │
│ │ Scanner │→ │ Parser │→ │ AST │ │
│ │ (入口扫描) │ │ (解析) │ │ (抽象语法树)│ │
│ └─────────────┘ └─────────────┘ └───────────┘ │
│ │ │
│ ┌─────────────┐ ┌─────────────┐ ┌───────────┐ │
│ │ Bundle │← │ Transform │← │ Module │ │
│ │ (打包) │ │ (转换) │ │ (模块处理)│ │
│ └─────────────┘ └─────────────┘ └───────────┘ │
│ │ │
│ ┌─────────────┐ ┌─────────────┐ ┌───────────┐ │
│ │ Output │← │ Minify │← │ Plugin │ │
│ │ (输出生成) │ │ (压缩) │ │ (插件系统)│ │
│ └─────────────┘ └─────────────┘ └───────────┘ │
└─────────────────────────────────────────────────────┘
2.3 核心代码解析
让我们深入看看 Rolldown 的核心实现:
// Rolldown 的模块解析器
pub struct ModuleResolver {
pub resolve_options: ResolveOptions,
pub cache: ModuleCache,
}
impl ModuleResolver {
pub fn resolve(&self, specifier: &str, importer: &str) -> Result<ModuleId> {
// 1. 检查缓存
if let Some(cached) = self.cache.get(specifier) {
return Ok(cached);
}
// 2. 解析路径
let resolved = self.resolve_options
.resolve(specifier, importer)
.ok_or_else(|| ResolveError::NotFound(specifier.to_string()))?;
// 3. 加载模块内容
let module = self.load_module(&resolved)?;
// 4. 缓存结果
self.cache.insert(specifier, module.id.clone());
Ok(module.id)
}
}
2.4 插件系统
Rolldown 完全兼容 Rollup 插件 API,这意味着现有的 Rollup 插件可以直接在 Rolldown 上运行:
// rollup.config.js - 可以在 Rolldown 中直接使用
export default {
input: 'src/index.ts',
output: {
dir: 'dist',
format: 'es'
},
plugins: [
// Rollup 官方插件
resolve(),
commonjs(),
typescript(),
// 自定义插件
{
name: 'my-custom-plugin',
transform(code, id) {
// 在这里添加你的转换逻辑
return {
code: code.replace(/console\.log/g, 'console.debug'),
map: null
};
}
}
]
};
2.5 性能实测
以下是 Rolldown 与 Rollup 在相同项目上的 benchmark 对比:
| 项目规模 | Rollup | Rolldown | 提升 |
|---|---|---|---|
| 100 个模块 | 1.2s | 0.2s | 6x |
| 500 个模块 | 8.5s | 1.1s | 7.7x |
| 1000 个模块 | 32s | 3.8s | 8.4x |
| 内存占用 | 450MB | 180MB | 2.5x |
三、Oxc:JavaScript 工具链的未来
3.1 Oxc 是什么?
Oxc 是一个用 Rust 编写的 JavaScript 工具链,目标是替代 ESLint、Prettier 等常用工具。与 ESLint 相比,Oxc 可以实现 50-100 倍的性能提升。
为什么叫 Oxc?
Oxc 的名字来源于 "Oxford Comma"(牛津逗号),这是一个小小的语言细节,体现了项目对精确性的追求。
3.2 核心组件
Oxc 包含以下几个核心工具:
- oxc_linter:高性能的 JavaScript/TypeScript linter
- oxc_formatter:代码格式化工具(Prettier 替代品)
- oxc_minifier:代码压缩工具
- oxc_transformer:代码转换工具(Babel 替代品)
3.3 架构解析
Oxc 的核心优势在于其共享的 AST 基础设施:
// Oxc 的统一 AST 表示
pub struct Program<'a> {
pub span: Span,
pub body: Vec<Statement<'a>>,
pub directives: Vec<Directive<'a>>,
}
// 一次解析,多工具共享
pub struct OxcCompiler {
parser: Parser,
linter: Linter,
formatter: Formatter,
minifier: Minifier,
}
impl OxcCompiler {
pub fn run(&self, source: &str) -> CompileResult {
// 1. 解析一次 AST
let ast = self.parser.parse(source);
// 2. 复用 AST 执行多个工具
let lint_result = self.linter.lint(&ast);
let format_result = self.formatter.format(&ast);
let minify_result = self.minifier.minify(&ast);
CompileResult {
lint: lint_result,
format: format_result,
minified: minify_result,
}
}
}
3.4 与 ESLint 的对比
ESLint 的工作流程:
源代码 → 解析器(每次规则都解析一次)→ AST → 规则检查(逐个规则遍历 AST)
Oxc 的工作流程:
源代码 → 解析器(只解析一次)→ AST → 共享遍历(一次遍历执行所有规则)
这种设计使得 Oxc 可以复用解析结果,避免重复工作。
3.5 实际使用
// oxc 的配置文件 .oxcrc
{
"lint": {
"rules": {
"noUnusedVars": "warn",
"noConsole": "off",
"eqeqeq": "error"
}
},
"format": {
"indent": 2,
"singleQuote": true,
"semi": true
}
}
# 使用 oxc 进行 lint
oxc lint src/
# 使用 oxc 格式化代码
oxc format src/
# 一次性完成 lint + format
oxc check src/
3.6 性能数据
以下是 Oxc 与 ESLint 在一个中型 TypeScript 项目上的对比:
| 指标 | ESLint | Oxc | 提升 |
|---|---|---|---|
| 首次检查 | 12.5s | 0.15s | 83x |
| 增量检查 | 8.2s | 0.12s | 68x |
| 内存占用 | 320MB | 45MB | 7x |
| 规则数量 | 300+ | 200+ | - |
四、Rspack:企业级构建方案
4.1 Rspack 的诞生
Rspack 是字节跳动开源的高性能构建工具,由 ByteDance Web Infra 团队开发。它最初是为了解决字节跳动内部海量前端项目的构建性能问题。
为什么叫 Rspack?
Rspack = Rust + Webpack。作为 Webpack 的 Rust 替代品,它在保持 API 兼容的同时实现了 10-20 倍的性能提升。
4.2 核心特性
- Webpack 兼容:Rspack 实现了 Webpack 的大部分 API,现有的 Webpack 配置可以直接迁移
- 并行构建:充分利用多核 CPU,实现真正的并行处理
- 增量编译:智能缓存机制,只重新构建修改的部分
- Tree Shaking:先进的代码消除算法,减小产物体积
4.3 架构设计
R Compilation Pipeline
Rspack 的构建流程采用流式处理架构,每个阶段都可以并行执行:
```rust
// Rspack 的并行构建调度器
pub struct BuildScheduler {
worker_pool: WorkerPool,
module_graph: ModuleGraph,
cache: BuildCache,
}
impl BuildScheduler {
pub fn build(&self, entry: Entry) -> BuildResult {
// 1. 收集所有依赖
let modules = self.collect_dependencies(entry);
// 2. 并行编译模块
let compiled = self.worker_pool.execute_parallel(
modules,
|module| self.compile_module(module)
);
// 3. 构建产物
let bundle = self.bundle(compiled);
// 4. 优化产物
self.optimize(bundle)
}
}
4.4 配置迁移
将 Webpack 配置迁移到 Rspack 非常简单:
// webpack.config.js
module.exports = {
entry: './src/index.js',
output: {
path: './dist',
filename: '[name].js'
},
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
},
resolve: {
extensions: ['.tsx', '.ts', '.js']
},
plugins: [
new HtmlWebpackPlugin()
]
};
// rspack.config.js - 几乎相同的配置
module.exports = {
entry: './src/index.js',
output: {
path: './dist',
filename: '[name].js'
},
module: {
rules: [
{
test: /\.tsx?$/,
use: {
loader: 'builtin:swc-loader',
options: {
jsc: {
parser: {
syntax: 'typescript'
}
}
}
}
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
},
resolve: {
extensions: ['.tsx', '.ts', '.js']
},
plugins: [
new HtmlRspackPlugin()
]
};
4.5 企业级特性
Rspack 为企业场景做了大量优化:
- 远程模块:支持从 CDN 动态加载模块
- 模块联邦:多项目共享组件和库
- Source Map:完整的调试支持
- 热更新:快速的开发体验
// 模块联邦示例
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: 'app1',
filename: 'remoteEntry.js',
exposes: {
'./Button': './src/Button'
},
shared: ['react', 'react-dom']
})
]
};
4.6 性能对比
| 项目类型 | Webpack | Rspack | 提升 |
|---|---|---|---|
| 简单项目 | 5s | 0.8s | 6x |
| 中型项目 | 45s | 3.5s | 13x |
| 大型项目 | 180s | 12s | 15x |
| 增量构建 | 25s | 0.5s | 50x |
五、Turbopack:Next.js 的御用构建工具
5.1 Turbopack 的定位
Turbopack 是 Vercel 开发的构建工具,专为 Next.js 优化。它是 Webpack 的继任者,旨在为 Next.js 提供极速的开发体验。
Turbopack 与 Turborepo 的关系:
- Turborepo:JavaScript/TypeScript 的构建系统,用于 monorepo 优化
- Turbopack:Next.js 的底层打包工具
两者都来自 Turborepo 项目,但定位不同。
5.2 Rust 实现
Turbopack 完全使用 Rust 编写,充分利用了 Rust 的性能优势:
// Turbopack 的增量计算引擎
pub struct TurbopackEngine {
// 任务图
tasks: HashMap<TaskId, Task>,
// 执行引擎
executor: Executor,
// 缓存层
cache: Cache,
}
impl TurbopackEngine {
pub fn run(&mut self, entries: Vec<Entry>) -> Result<Output> {
// 1. 构建任务图
let graph = self.build_task_graph(entries);
// 2. 执行任务(利用缓存)
let results = self.executor.execute(&graph, &self.cache)?;
// 3. 聚合结果
self.aggregate(results)
}
}
5.3 核心技术
增量计算(Incremental Computation)
Turbopack 的核心创新是增量计算引擎。它会跟踪文件变化,只重新计算受影响的部分:
// 增量计算示例
pub fn process_module(&self, module: &Module, changes: &Changes) -> Result<ModuleOutput> {
// 如果文件没有变化,直接返回缓存结果
if !changes.affects(module.id) {
return self.cache.get(module.id);
}
// 否则重新计算
let output = self.do_process(module)?;
self.cache.put(module.id, &output);
Ok(output)
}
源码映射(Source Mapping)
Turbopack 维护了完整的源码映射,确保调试体验:
// next.config.js
module.exports = {
experimental: {
// 启用更详细的 source map
turbopackGrades: ['canary'],
}
};
5.4 Next.js 集成
Turbopack 已经深度集成到 Next.js 中:
# 在 Next.js 中启用 Turbopack
npx next dev --turbo
# 或在 next.config.js 中配置
module.exports = {
experimental: {
turbo: {
resolveExtensions: ['.tsx', '.ts', '.jsx', '.js'],
}
}
}
5.5 性能表现
| 操作 | Webpack | Turbopack | 提升 |
|---|---|---|---|
| 首次启动 | 45s | 8s | 5.6x |
| 文件修改响应 | 2.5s | 0.3s | 8x |
| 增量构建 | 15s | 0.8s | 18x |
六、实战:从零构建 Rust 前端工具
6.1 环境准备
首先,你需要安装 Rust 工具链:
# 安装 Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# 验证安装
rustc --version
# 输出: rustc 1.85.0
cargo --version
# 输出: cargo 1.85.0
# 安装 wasm 目标(部分工具需要)
rustup target add wasm32-unknown-unknown
6.2 项目结构
让我们创建一个简化版的 Rust 打包工具:
# 创建新项目
cargo new --lib mini-bundler
# 编辑 Cargo.toml
[package]
name = "mini-bundler"
version = "0.1.0"
edition = "2021"
[dependencies]
swc_core = "0.115"
rolldown = "0.5"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
6.3 核心实现
// src/bundler.rs
use swc_core::ecma::ast::*;
use std::collections::HashMap;
/// 模块解析器
pub struct ModuleResolver {
// 解析选项
pub extensions: Vec<String>,
}
impl ModuleResolver {
pub fn new() -> Self {
Self {
extensions: vec![
".js".to_string(),
".ts".to_string(),
".jsx".to_string(),
".tsx".to_string(),
]
}
}
/// 解析模块路径
pub fn resolve(&self, specifier: &str, base: &str) -> Option<String> {
// 1. 处理相对路径
if specifier.starts_with('.') || specifier.starts_with('/') {
return Some(specifier.to_string());
}
// 2. 处理 node_modules
if !specifier.contains('/') {
return Some(format!("node_modules/{}", specifier));
}
None
}
}
/// 代码转换器
pub struct Transformer {
// 全局变量
pub globals: HashMap<String, String>,
}
impl Transformer {
pub fn new() -> Self {
Self {
globals: HashMap::new(),
}
}
/// 转换 ES Module 到 CommonJS
pub fn transform(&mut self, module: &Module) -> String {
let mut outputs = Vec::new();
// 处理 import 语句
for item in &module.body {
match item {
ModuleItem::ModuleDecl(ModuleDecl::Import(import)) => {
// 收集 import 信息
let src = &import.src.value;
outputs.push(format!(
"const {} = require('{}');",
import.specifiers.first()
.map(|s| match s {
ImportSpecifier::Named(n) => n.orig.sym.to_string(),
ImportSpecifier::Default(d) => d.ident.sym.to_string(),
ImportSpecifier::Namespace(n) => n.ident.sym.to_string(),
})
.unwrap_or_default(),
src
));
}
_ => {}
}
}
// 处理 export 语句
for item in &module.body {
match item {
ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(export)) => {
for spec in &export.specifiers {
outputs.push(format!(
"module.exports.{} = {};",
spec.orig.sym, spec.orig.sym
));
}
}
ModuleItem::ModuleDecl(ModuleDecl::ExportDefaultExpr(expr)) => {
outputs.push(format!(
"module.exports.default = {};",
self.expr_to_string(&expr.expr)
));
}
_ => {}
}
}
outputs.join("\n")
}
fn expr_to_string(&self, expr: &Expr) -> String {
match expr {
Expr::Ident(ident) => ident.sym.to_string(),
Expr::Lit(lit) => match lit {
Lit::Str(s) => format!("'{}'", s.value),
Lit::Num(n) => n.value.to_string(),
_ => "undefined".to_string(),
},
_ => "undefined".to_string(),
}
}
}
/// 打包器主类
pub struct Bundler {
resolver: ModuleResolver,
transformer: Transformer,
}
impl Bundler {
pub fn new() -> Self {
Self {
resolver: ModuleResolver::new(),
transformer: Transformer::new(),
}
}
/// 打包入口文件
pub fn bundle(&mut self, entry: &str) -> Result<String, Box<dyn std::error::Error>> {
// 1. 读取入口文件
let source = std::fs::read_to_string(entry)?;
// 2. 解析代码
let module = self.parse(&source)?;
// 3. 转换代码
let output = self.transformer.transform(&module);
// 4. 打包依赖(简化版)
let mut bundle = output;
// 收集所有 import 并递归处理
// 这里简化处理,实际需要递归解析所有依赖
Ok(bundle)
}
fn parse(&self, source: &str) -> Result<Module, Box<dyn std::error::Error>> {
use swc_core::ecma::parser::Parser;
use swc_core::ecma::parser::lexer::Lexer;
use swc_core::ecma::parser::StringInput;
let input = StringInput::new(source, None, None);
let lexer = Lexer::new(
swc_core::ecma::ast::EsVersion::EsNext,
swc_core::ecma::parser::Syntax::Es(swc_core::ecma::parser::EsConfig::default()),
input,
None,
);
let mut parser = Parser::new_from(lexer);
Ok(parser.parse_module()?)
}
}
6.4 CLI 入口
// src/main.rs
use mini_bundler::Bundler;
use std::env;
use std::process;
fn main() {
let args: Vec<String> = env::args().collect();
if args.len() < 3 {
eprintln!("Usage: mini-bundler <entry> <output>");
process::exit(1);
}
let entry = &args[1];
let output = &args[2];
println!("Bundling {} -> {}", entry, output);
let mut bundler = Bundler::new();
match bundler.bundle(entry) {
Ok(bundled) => {
std::fs::write(output, &bundled).expect("Failed to write output");
println!("Bundle completed successfully!");
println!("Output size: {} bytes", bundled.len());
}
Err(e) => {
eprintln!("Error: {}", e);
process::exit(1);
}
}
}
6.5 运行测试
# 编译
cargo build --release
# 创建测试文件
mkdir -p test/src
echo "import { add } from './math';
console.log(add(1, 2));" > test/src/index.js
echo "export function add(a, b) {
return a + b;
}" > test/src/math.js
# 运行打包
./target/release/mini-bundler test/src/index.js test/dist/bundle.js
七、性能优化最佳实践
7.1 构建时优化
启用持久化缓存
// rspack.config.js
module.exports = {
cache: {
type: 'filesystem',
buildDependencies: {
config: [__filename],
},
},
};
并行处理
// 使用 rayon 进行并行处理
use rayon::prelude::*;
pub fn process_modules_parallel(modules: &[Module]) -> Vec<ProcessedModule> {
modules.par_iter()
.map(|m| process_module(m))
.collect()
}
7.2 运行时优化
代码分割
// 使用动态导入进行代码分割
const HeavyComponent = React.lazy(() => import('./HeavyComponent'));
// Rspack 配置
module.exports = {
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
priority: 10,
},
},
},
},
};
Tree Shaking
// 确保使用 ES 模块
// math.js
export function add(a, b) {
return a + b;
}
export function subtract(a, b) {
return a - b;
}
// index.js - 只导入使用的函数
import { add } from './math';
console.log(add(1, 2));
// subtract 会被 tree shaking 掉
7.3 开发体验优化
热模块替换(HMR)
// 确保启用 HMR
module.exports = {
devServer: {
hot: true,
liveReload: false, // 只更新变化的模块
},
};
增量检查
// 使用 watchman 增量监听
use notify::{Config, RecommendedWatcher, RecursiveMode, Watcher};
pub fn watch_changes(path: &Path) {
let (tx, rx) = std::sync::mpsc::channel();
let mut watcher = RecommendedWatcher::new(
move |res| {
tx.send(res).unwrap();
},
Config::default(),
).unwrap();
watcher.watch(path, RecursiveMode::Recursive).unwrap();
// 只处理变化的文件
for res in rx {
if let Ok(event) = res {
handle_change(event);
}
}
}
八、总结与展望
8.1 2026 年的技术格局
Rust 在前端工具链领域的崛起已经成为不可逆转的趋势:
- 性能提升是核心驱动力:10-100 倍的性能提升让开发者无法忽视
- 企业级采用加速:字节跳动、Vercel、Vite 团队的选择证明了 Rust 的可行性
- 生态逐步完善:从构建到 linting,从格式化到压缩,Rust 正在覆盖整个工具链
8.2 未来展望
展望未来,我们可以预见:
- 更多工具 Rust 化:TypeScript 编译器、测试框架等都可能迎来 Rust 重写
- WASM 的普及:Rust 工具将通过 WebAssembly 在浏览器中直接运行
- AI 集成:Rust 的高性能将为 AI 辅助开发提供更好的基础设施
8.3 给开发者的建议
对于前端开发者:
- 学习 Rust 基础,无需深入,但需要理解其核心概念
- 尝试在项目中使用 Rspack 或 Rolldown,体验性能提升
- 关注工具链的发展,了解新技术带来的变化
对于架构师:
- 评估 Rust 工具链在团队项目中的可行性
- 制定迁移计划,从小项目开始试点
- 建立团队的技术雷达,关注 Rust 生态的发展
对于工具开发者:
- 考虑使用 Rust 重写性能敏感的 JavaScript 工具
- 利用 Rust 的 WASM 支持,扩展工具的运行平台
- 参与开源贡献,推动 Rust 前端工具生态的发展
Rust 正在重新定义前端工具链的性能标准。2026 年不是起点,也不是终点,而是这场技术革命的进行时。作为开发者,我们既是见证者,也是参与者。拥抱变化,掌握新技术,才能在快速迭代的前端领域保持竞争力。
参考资料:
- Rolldown 官方文档
- Oxc GitHub 仓库
- Rspack 官方文档
- Turbopack 官方博客
- Webpack 官方文档