Rax2Taro: Building a Compiler to Convert Rax Components into Taro
This article walks through the design and implementation of a compiler that automatically transforms Rax components into Taro components, covering the background, Babel‑based AST processing, import rewriting, component attribute mapping, project structure, automated end‑to‑end testing, and future enhancements.
Background
The author regularly uses the Rax framework for frontend development but needs to migrate existing Rax components to Taro to support cross‑platform scenarios without rewriting code.
The goal is to create a one‑click tool that converts Rax components into Taro components, reducing development effort.
Compiler Overview
A compiler translates high‑level source code into a form that another platform can understand. In this context, it converts Rax JSX into Taro JSX using Babel.
1 | Babel: JavaScript Compiler
Babel parses source code into an Abstract Syntax Tree (AST), traverses it, transforms nodes, and generates new code.
Key Babel packages used:
@babel/parser – parses code to AST.
@babel/traverse – walks the AST.
@babel/types – creates and manipulates AST nodes.
@babel/generator – generates code from the transformed AST.
2 | Basic Usage Example
Convert const a = 1 to var a = 1 to illustrate the parse‑transform‑generate flow.
i. Parse
Use @babel/parser to obtain an AST.
ii. Transform
Traverse the AST with @babel/traverse and replace VariableDeclaration nodes where kind === 'const' with var .
iii. Generate
Generate the transformed source code using @babel/generator .
Rax2Taro Specific Transformations
Component Import Rewriting
Rax imports components individually (e.g., import View from "rax-view" ) while Taro imports them from @tarojs/components . The transformer removes Rax imports, records the needed Taro components, and adds a consolidated import statement.
const componentImportMap = {
"rax-view": { source: "@tarojs/components", importName: "View" },
"rax-text": { source: "@tarojs/components", importName: "Text" }
// ...add more mappings
};The same logic also removes the unnecessary createElement import from Rax.
View Component Transformation
Attributes differ between Rax and Taro. For example, onClick becomes onTap and onLongpress becomes onLongTap . The transformer walks JSX View elements and renames these attributes.
function transformViewElement(path) {
if (path.node.openingElement && path.node.openingElement.name.name === "View") {
path.node.openingElement.attributes.forEach(attribute => {
if (t.isJSXAttribute(attribute) && attribute.name) {
switch (attribute.name.name) {
case "onClick":
attribute.name.name = "onTap";
break;
case "onLongpress":
attribute.name.name = "onLongTap";
break;
}
}
});
}
}Similar transformers are created for the other six basic components.
Project Structure
/Rax2Taro
|-- node_modules # dependencies
|-- src
| |-- index.js # entry point, coordinates the transformation
| |-- parser.js # parses source to AST
| |-- generator.js # generates code from AST
|-- Transformers
| |-- index.js # aggregates individual component transformers
| |-- FunctionTransformer.js
| |-- JSXElementsTransformer
| |-- index.js
| |-- ...
|-- Input # Rax source files
|-- Output # generated Taro files
|-- package.json
|-- README.mdAutomated End‑to‑End Testing
A Jest test reads a Rax source file, parses it, runs the transformation, generates Taro code, and writes the result to the Taro project directory.
const fs = require("fs");
const path = require("path");
const { transform } = require("../src/Transformers");
const parser = require("@babel/parser");
const generator = require("@babel/generator").default;
const raxSourcePath = path.join(__dirname, "../../rax-test-demo/src/index.js");
const taroOutputPath = path.join(__dirname, "../../TaroTestDemo/src/pages/index/index.jsx");
describe("End-to-End Transformation", () => {
it("reads Rax source and outputs Taro component", () => {
const raxSourceCode = fs.readFileSync(raxSourcePath, "utf8");
const raxAst = parser.parse(raxSourceCode, { sourceType: "module", plugins: ["jsx"] });
transform(raxAst);
const taroOutput = generator(raxAst, {});
fs.writeFileSync(taroOutputPath, taroOutput.code);
});
});Setup scripts for both Rax and Taro projects are provided, followed by Jest configuration and execution commands.
Conclusion
The article demonstrates how to build a practical Rax‑to‑Taro compiler, covering AST manipulation, import handling, attribute mapping, project scaffolding, and automated testing. Future work includes custom scaffolding, CSS style reconciliation, and bilingual documentation.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.