A Rust transpiler that converts Babel plugins to SWC (Speedy Web Compiler) plugins.
Transpiles JavaScript Babel plugins into equivalent Rust code that uses SWC's AST, automatically handling:
- Recursive module resolution - Follows
require()calls browserify-style to inline all dependencies - Namespace management - Organizes 750+ functions across 24+ modules with zero naming collisions
- AST pattern translation - Converts Babel visitor patterns to SWC's Rust
VisitMuttrait - Code generation - Translates JavaScript code generation logic to Rust
Input: Babel Plugin (JavaScript)
├─ Detects require() calls
├─ Recursively parses all dependencies
├─ Extracts helper functions from each module
└─ Groups by source module
↓
Output: SWC Plugin (Rust)
├─ generated-plugin/
│ ├─ Cargo.toml
│ ├─ src/
│ │ ├─ lib.rs (visitor implementation)
│ │ ├─ main.rs (CLI runner)
│ │ └─ generators/
│ │ ├─ mod.rs
│ │ ├─ csharp_file.rs
│ │ ├─ component.rs
│ │ ├─ jsx.rs
│ │ ├─ expressions.rs
│ │ └─ ... (20+ modules)
Input: React/TypeScript component
// Counter.tsx
import { useState } from '@minimact/core';
export default function Counter() {
const [count, setCount] = useState(0);
const [message, setMessage] = useState("Hello");
return (
<div id="counter-root">
<span id="counter-value">{count}</span>
<span id="message">{message}</span>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}Step 1: Babel plugin (JavaScript) extracts metadata and generates C#
Step 2: This transpiler converts that Babel plugin to Rust/SWC
Step 3: Generated SWC plugin runs on Counter.tsx
Output: C# Blazor component
using Minimact.AspNetCore.Core;
using Minimact.AspNetCore.Extensions;
using MinimactHelpers = Minimact.AspNetCore.Core.Minimact;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Minimact.Components;
public class Counter : MinimactComponent
{
private int count = 0;
private string message = "Hello";
protected override MinimactNode Render()
{
// JSX translation
return MinimactHelpers.Element("div", new { id = "counter-root" },
MinimactHelpers.Element("span", new { id = "counter-value" }, count),
MinimactHelpers.Element("span", new { id = "message" }, message),
MinimactHelpers.Element("button", new {
onclick = (Action)(() => { count++; })
}, "Increment")
);
}
}- Recursive
require()module resolution (browserify-style) - Parse and analyze 750+ helper functions from 20+ modules
- Generate modular Rust project structure with proper namespacing
- Detect 15+ AST transform patterns:
ArrayPush- String building (lines.push()→code.push_str())ArrayPushSpread- Array spreading (lines.push(...other))TemplateLiteral- Template strings (`Hello ${name}`→format!())ForOfLoop- Iteration (for (const x of y)→for x in y)Conditional- If/else statementsVariableDeclaration- Variable declarationsFunctionCall- Function callsHookCapture- React hooks (useState→ state properties)- And more...
- Extract component metadata (hooks, JSX elements, props)
- Generate C# Blazor components from React/TSX
- End-to-end pipeline: Babel plugin → Rust plugin → C# output
- Code generation quality improvements (~153 compilation errors in generated code)
- Pattern translation refinements:
- LogicalChain expressions (
a && b.length > 0) - Member access translation (
.length→.len()) - Return statement handling
- Function name translation (camelCase → snake_case)
- LogicalChain expressions (
See ENHANCEMENT_PLAN.md for detailed roadmap.
- Rust toolchain (with Visual Studio C++ Build Tools on Windows)
- Node.js (for running Babel plugins)
# Windows
./build.bat
# Other platforms
cargo buildSimple plugin:
./run.bat
# Analyzes: example/simple-babel-plugin/index.jsFull production plugin:
./run.bat --full
# Analyzes: example/babel-plugin-minimact/index.cjs
# Follows all require() dependencies
# Generates 24 Rust modules with 750+ functionsCustom plugin:
./run.bat --analyze path/to/your-plugin.jscd generated-plugin
../build.bat
target/debug/extract-components.exe ../fixtures/Counter.tsxOutput: Counter.cs in the fixtures directory
babel-plugin-to-swc/
├── src/
│ └── main.rs # Transpiler implementation
├── example/
│ ├── simple-babel-plugin/ # Test case with basic patterns
│ └── babel-plugin-minimact/ # Full production plugin (600+ lines)
├── fixtures/
│ └── Counter.tsx # Test React component
├── generated-plugin/ # Auto-generated SWC plugin output
│ ├── src/
│ │ ├── lib.rs
│ │ ├── main.rs
│ │ └── generators/ # 24 modules, 750+ functions
│ └── Cargo.toml
├── build.bat / run.bat # Windows build scripts
├── CSHARP_GENERATOR_PLAN.md # C# generation implementation plan
├── ENHANCEMENT_PLAN.md # Remaining work (final 15%)
└── README.md
// Parse JavaScript using SWC
let module = parser.parse_module()?;
let mut analyzer = BabelVisitorDetector::new();
module.visit_with(&mut analyzer);// In JavaScript:
const { generateCSharpFile } = require('../generators/csharpFile.cjs');
// Transpiler detects and resolves path
// → J:\projects\rust-swc\example\babel-plugin-minimact\src\generators\csharpFile.cjsfn parse_required_modules(analyzer: &mut Analyzer, processed: &mut HashSet) {
for module_path in analyzer.required_modules {
if !processed.contains(module_path) {
// Parse module
// Extract helper functions
// Recursively process its dependencies
}
}
}// Group functions by source module
let mut modules: HashMap<String, Vec<HelperFunction>> = HashMap::new();
// csharpFile.cjs → generators/csharp_file.rs
// component.cjs → generators/component.rs
// jsx.cjs → generators/jsx.rs// For each module, generate .rs file
for (module_name, helpers) in modules {
let code = generate_module_file(helpers);
fs::write(format!("generators/{}.rs", module_name), code)?;
}
// Generate mod.rs with pub mod declarations
// Generate lib.rs with visitor implementationJavaScript:
const lines = [];
lines.push('using System;');
lines.push(`namespace ${ns};`);
return lines.join('\n');Generated Rust:
let mut code = String::new();
code.push_str("using System;\n");
code.push_str(&format!("namespace {};\n", ns));
code // Implicit returnJavaScript:
for (const component of components) {
lines.push(...generateComponent(component));
}Generated Rust:
for component in components {
code.push_str(&generate_component(&component));
}JavaScript:
if (t.isCallExpression(node) && node.callee.name === 'useState') {
const [state, setState] = node.parent.id.elements;
// Extract state and setter
}Generated Rust:
fn visit_mut_var_declarator(&mut self, node: &mut VarDeclarator) {
if let Pat::Array(array_pat) = &node.name {
if let Some(init) = &node.init {
if let Expr::Call(call) = &**init {
if let Expr::Ident(ident) = &*call.callee {
if ident.sym == "useState" {
// Extract state and setter
}
}
}
}
}
}Run individual pattern detection tests:
cargo testFull pipeline test with Counter.tsx:
./run.bat
cd generated-plugin
../build.bat
target/debug/extract-components.exe ../fixtures/Counter.tsx
cat ../fixtures/Counter.csCompare Babel output vs SWC output:
cd tests
./compare-outputs.bat| Metric | Value |
|---|---|
| Babel Plugin Size | 600+ lines (minimact) |
| Dependencies Detected | 20+ modules |
| Functions Transpiled | 750+ |
| Generated Rust Code | 24 modules |
| Parse Time | ~2 seconds |
| Generated Plugin Compile | ~3 seconds |
| Runtime (vs Node.js) | 10x faster |
Babel plugins run in Node.js, which:
- ❌ Adds Node.js as a runtime dependency
- ❌ Slower than native code
- ❌ Can't be used in Rust-only environments (like Tauri, embedded systems)
Transpile Babel plugins to native Rust/SWC:
- ✅ No Node.js dependency at runtime
- ✅ 10x faster execution
- ✅ Compile-time guarantees
- ✅ Can be embedded anywhere Rust runs
- Cactus Browser - TSX → C# Blazor compilation without Node.js
- Build tools - Fast native compilation in Tauri/Deno/Bun
- Embedded systems - Run code generators on embedded Rust
- CI/CD - Faster builds without Node.js installation
See ENHANCEMENT_PLAN.md for detailed roadmap.
Phase 1: Core Architecture ✅ COMPLETE
- Recursive module resolution
- Namespace management
- Basic pattern detection
- Module structure generation
Phase 2: Code Generation Quality
- String building patterns
- Template literals
- For-of loops
- Logical chain expressions
- Member access translation
- Return statement handling
Phase 3: JSX Translation 📋 PLANNED
- JSX → MinimactHelpers.Element() calls
- Nested children handling
- Event handler translation
- Expression interpolation
Phase 4: Production Ready 📋 PLANNED
- Error recovery and diagnostics
- Source maps
- Watch mode
- Plugin API documentation
This is currently a research project exploring Babel → SWC transpilation patterns.
Areas that need work:
- Pattern translation - Improve JavaScript → Rust code generation quality
- Error handling - Better diagnostics for unsupported patterns
- Testing - More test cases and edge case coverage
- Documentation - Document detected patterns and their translations
MIT
- Built with SWC - Speedy Web Compiler
- Inspired by Browserify - Module bundling approach
- Target use case: Minimact - React-like framework for C#
Status: Experimental - Core architecture working, code generation quality improvements in progress