Frontend Development 15 min read

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.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rax2Taro: Building a Compiler to Convert Rax Components into Taro

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.md

Automated 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.

frontendASTCompilerBabelRaxComponent ConversionTaro
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.