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 的源代码体现了以下设计原则:

  1. 高性能:利用 Rust 和 SWC 的性能优势
  2. 生态兼容:通过 JavaScript 桥接兼容 Webpack
  3. 并发优化:原生支持多线程
  4. 易于使用:提供与 Webpack 兼容的 API

理解源代码有助于更好地使用和优化 Rspack。

参考资源

架构师AI杜公众号二维码

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