Write Once
Stop maintaining duplicate Babel and SWC plugins. Write your AST transformation logic once in clean, Rust-inspired syntax.
Write AST transformations once. Compile to Babel, SWC, and beyond. One .lux file. Infinite possibilities.

# Install ReluxScript
cargo install reluxscript
# Create your first plugin
relux new my-plugin
# Build to Babel
relux build my-plugin.lux --target babel
# Build to SWC
relux build my-plugin.lux --target swcWrite once in ReluxScript:
/// Remove console.log statements
plugin RemoveConsole {
fn visit_call_expression(node: &mut CallExpression, ctx: &Context) {
if let Callee::MemberExpression(ref member) = node.callee {
if let Expression::Identifier(ref obj) = *member.object {
if obj.name == "console" {
if let Expression::Identifier(ref prop) = *member.property {
if prop.name == "log" {
ctx.remove();
}
}
}
}
}
}
}Compiles to both:
Babel (JavaScript)
module.exports = function({ types: t }) {
return {
visitor: {
CallExpression(path) {
const node = path.node;
const __iflet_0 = node.callee;
if (__iflet_0 !== null) {
const member = __iflet_0;
const __iflet_1 = member.object;
if (__iflet_1 !== null) {
const obj = __iflet_1;
if (obj.name === "console") {
const __iflet_2 = member.property;
if (__iflet_2 !== null) {
const prop = __iflet_2;
if (prop.name === "log") {
path.remove();
}
}
}
}
}
}
}
};
};SWC (Rust)
pub struct RemoveConsole {}
impl VisitMut for RemoveConsole {
fn visit_mut_call_expr(&mut self, node: &mut CallExpr) {
if let Callee::Expr(__callee_expr) = &node.callee {
if let Expr::Member(member) = __callee_expr.as_ref() {
if let Expr::Ident(obj) = &*member.obj.as_ref() {
if (&*obj.sym.to_string() == "console") {
if let MemberProp::Ident(prop) = &member.prop {
if (&*prop.sym.to_string() == "log") {
node.callee = Callee::Expr(Box::new(
Expr::Ident(Ident::new(
"undefined".into(),
DUMMY_SP,
SyntaxContext::empty()
))
))
}
}
}
}
}
}
}
}Building AST transformation plugins is hard:
ReluxScript is a domain-specific language that compiles to both Babel and SWC:
For Plugin Authors: Stop maintaining duplicate codebases. Write once, target both ecosystems.
For Tool Builders: Use ReluxScript as your plugin format. Let users write once, deploy everywhere.
For Framework Teams: Build custom transpilers from TypeScript/JSX to your target language (C#, Go, etc).
ReluxScript follows the Vector Intersection principle:
We only support features that work identically in both Babel and SWC.
This means:
We choose correctness over coverage. Better to support 80% of use cases perfectly than 100% with edge case bugs.
/ˈreɪ.lʌks.skrɪpt/ • ray-lucks-script
ReluxScript = Reay + Lux + Script
"Light, light, write!" ☀️