Skip to content

Rspack 源代码导览

项目结构

rspack-course/
├── 04-core-feature/          # 核心功能实现
│   ├── src/
│   │   ├── compiler.rs      # Rust 编译器
│   │   ├── parser.rs        # Rust 解析器
│   │   └── bridge.js        # JavaScript 桥接
│   ├── test/
│   │   ├── compiler.test.js
│   │   ├── parser.test.js
│   │   └── bridge.test.js
│   ├── Cargo.toml
│   ├── package.json
│   └── README.md
├── 05-lesson-plan.md         # 课程计划
├── 01-intro.md              # 背景研究
├── 02-arch.md              # 架构分析
└── 03-code-walkthrough.md   # 源代码导览

核心文件解析

1. compiler.rs - Rust 编译器

文件路径: src/compiler.rs

核心功能: 编译 JavaScript/TypeScript,优化代码,生成输出。

关键代码:

rust
use swc_common::SourceMap;
use swc_ecma_parser::{Parser, StringInput, Syntax};
use swc_ecma_transforms_typescript::strip;
use swc_ecma_codegen::{text_writer::JsWriter, Emitter};

// 编译器
pub struct Compiler {
    cm: SourceMap,
}

impl Compiler {
    pub fn new() -> Self {
        Compiler {
            cm: SourceMap::default(),
        }
    }
    
    // 编译源代码
    pub fn compile(&self, source: &str) -> Result<String, Error> {
        // 解析
        let fm = self.cm.new_source_file(
            FileName::Custom("input.js".into()),
            source.into()
        );
        
        let mut parser = Parser::new(
            Syntax::Es(Default::default()),
            StringInput::from(&*fm),
            None
        );
        
        let module = parser.parse_module().map_err(|e| {
            Error::ParseError(e.to_string())
        })?;
        
        // 转换
        let module = strip(Default::default(), module);
        
        // 生成代码
        let mut buf = Vec::new();
        {
            let writer = JsWriter::new(self.cm.clone(), "\n", &mut buf, None);
            let mut emitter = Emitter {
                cfg: Default::default(),
                cm: self.cm.clone(),
                comments: None,
                writer: writer,
            };
            emitter.emit_module(&module).map_err(|e| {
                Error::EmitError(e.to_string())
            })?;
        }
        
        Ok(String::from_utf8(buf).unwrap())
    }
}

设计要点: 使用 SWC 解析和转换,支持 TypeScript,高性能编译。

2. parser.rs - Rust 解析器

文件路径: src/parser.rs

核心功能: 解析 JavaScript/TypeScript,生成 AST,提取依赖。

关键代码:

rust
use swc_common::SourceMap;
use swc_ecma_parser::{Parser, StringInput, Syntax};
use swc_ecma_visit::{Visit, VisitWith};

// 解析器
pub struct Parser {
    cm: SourceMap,
}

impl Parser {
    pub fn new() -> Self {
        Parser {
            cm: SourceMap::default(),
        }
    }
    
    // 解析源代码
    pub fn parse(&self, source: &str) -> Result<Module, Error> {
        let fm = self.cm.new_source_file(
            FileName::Custom("input.js".into()),
            source.into()
        );
        
        let mut parser = Parser::new(
            Syntax::Es(Default::default()),
            StringInput::from(&*fm),
            None
        );
        
        let module = parser.parse_module().map_err(|e| {
            Error::ParseError(e.to_string())
        })?;
        
        Ok(module)
    }
}

// 依赖提取器
struct DependencyExtractor {
    dependencies: Vec<String>,
}

impl Visit for DependencyExtractor {
    fn visit_import_decl(&mut self, node: &ImportDecl) {
        self.dependencies.push(node.src.value.to_string());
        node.visit_children_with(self);
    }
    
    fn visit_call_expr(&mut self, node: &CallExpr) {
        if let Callee::Expr(expr) = &node.callee {
            if let Expr::Ident(ident) = expr.as_ref() {
                if ident.sym == "require" {
                    if let Some(arg) = node.args.first() {
                        if let Expr::Lit(Lit::Str(s)) = &*arg.expr {
                            self.dependencies.push(s.value.to_string());
                        }
                    }
                }
            }
        }
        node.visit_children_with(self);
    }
}

设计要点: 使用 SWC 解析器,支持 CommonJS 和 ES6 模块,提取依赖关系。

3. bridge.js - JavaScript 桥接

文件路径: src/bridge.js

核心功能: 连接 Rust 和 JavaScript,提供插件 API,加载 JavaScript 插件。

关键代码:

javascript
import { loadBinding } from '@node-rs/helper'

// 加载 Rust 原生模块
const native = loadBinding(__dirname, 'rspack')

// 编译器桥接
export class Compiler {
  constructor(options = {}) {
    this.options = options
    this.native = new native.Compiler()
  }
  
  // 编译源代码
  compile(source) {
    return this.native.compile(source)
  }
}

// 解析器桥接
export class Parser {
  constructor(options = {}) {
    this.options = options
    this.native = new native.Parser()
  }
  
  // 解析源代码
  parse(source) {
    return this.native.parse(source)
  }
}

// 插件系统
export class PluginSystem {
  constructor(compiler) {
    this.compiler = compiler
    this.plugins = []
  }
  
  // 注册插件
  register(plugin) {
    if (plugin.apply) {
      plugin.apply(this.compiler)
    }
    this.plugins.push(plugin)
  }
}

设计要点: 使用 NAPI 连接 Rust 和 JavaScript,提供与 Webpack 兼容的 API,支持插件系统。

关键设计决策

1. 使用 SWC

原因: SWC 是用 Rust 编写的超快编译器,支持 TypeScript 和 JSX,与 Webpack 生态兼容。

实现:

rust
use swc_ecma_parser::Parser;
use swc_ecma_transforms_typescript::strip;

2. 使用 NAPI

原因: NAPI 是 Rust 和 Node.js 的标准互操作接口,提供高性能的互操作,支持异步操作。

实现:

rust
#[napi]
pub fn compile_js(source: String) -> Result<String, Error> {
    // Rust 编译逻辑
    Ok(compiled_code)
}

3. 兼容 Webpack API

原因: 最小化迁移成本,支持现有插件,降低学习曲线。

实现:

javascript
class Compiler {
  constructor(options) {
    this.options = options
    this.hooks = {
      run: new AsyncSeriesHook(['compiler']),
      compile: new SyncHook(['params'])
    }
  }
}

测试策略

Rust 测试

rust
#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_compile() {
        let compiler = Compiler::new();
        let source = "const x = 1;";
        let result = compiler.compile(source);
        assert!(result.is_ok());
    }
}

JavaScript 测试

javascript
import { describe, it } from 'node:test'
import assert from 'node:assert'
import { Compiler } from '../src/bridge.js'

describe('Compiler 测试', () => {
  it('应该编译 JavaScript', () => {
    const compiler = new Compiler()
    const source = 'const x = 1'
    const result = compiler.compile(source)
    assert.ok(result)
  })
})

性能优化

1. 并行编译

rust
use rayon::prelude::*;

fn compile_modules(modules: Vec<Module>) -> Vec<CompiledModule> {
    modules.par_iter()
        .map(|module| compile_module(module))
        .collect()
}

2. 增量编译

rust
fn incremental_compile(
    old_graph: &ModuleGraph,
    changed_files: Vec<PathBuf>
) -> ModuleGraph {
    let mut new_graph = old_graph.clone();
    
    for file in changed_files {
        let module = compile_module(file);
        new_graph.update_module(module);
    }
    
    new_graph
}

总结

Rspack 的源代码体现了四个核心设计原则:高性能利用 Rust 和 SWC 的性能优势,实现极快的构建速度;生态兼容通过 JavaScript 桥接机制兼容 Webpack 的 loader 和 plugin;并发优化原生支持多线程,充分利用多核 CPU;易于使用提供与 Webpack 兼容的 API,降低学习成本。理解源代码有助于更好地使用和优化 Rspack。

参考资源

Rspack 源码SWC 源码NAPI 文档

架构师AI杜公众号二维码

扫描二维码关注"架构师AI杜"公众号,获取更多技术内容和最新动态