Taro Framework Adaptation for HarmonyOS Development
Compilation Architecture
HarmonyOS provides a distributed operating system environment, while Taro serves as a cross-platform framework enabling development with React or Vue. HarmonyOS JavaScript development aligns closely with Taro's paradigms, allowing Taro source code to be parsed and transformed into HarmonyOS-compatible code.
Compilation Workflow
The Taro CLI initiates the build process, utilizing Webpack to compile the source code. Platform-specific plugins then smooth out the differences, ultimately generating the HarmonyOS application files.
- The CLI triggers
@tarojs/mini-runnerto handle the compilation phase. mini-runneradjusts Webpack configurations based on developer settings.- Custom PostCSS plugins (e.g.,
postcss-pxtransform) and Webpack loaders are injected. - Webpack executes the build process.
- The output is modified, and
@tarojs/plugin-platform-harmonyreconciles component, API, and routing disparities.
During parsing, Babel is utilized to transform the source: @babel/core generates the AST, @babel/traverse manipulates the nodes, and @babel/generator outputs the final script.
Source Transformation Example
Input JSX structure:
<Container styleClass="flex row h-44 pb-40">
<PriceDisplay amount={cost} />
{labels.length > 0 && labels.map(item =>
<Container styleClass="px-20 py-6 mx-12 bg-red text-white rounded-20" keyId={item}>{item}</Container>
)}
</Container>Compiled output:
(components_Container, {
styleClass: "flex row h-44 pb-40",
children: [React.createElement(PriceDisplay, { amount: cost }), labels.length > 0 && labels.map(function(item) {
return React.createElement(components_Container, { styleClass: "px-20 py-6 mx-12 bg-red text-white rounded-20", children: item }, item);
})]
})Runtime Execution
To enable React or Vue execution on HarmonyOS, Taro simulates a browser environment within the logical layer, implementing essential DOM and BOM APIs. Instead of the bulky ReactDOM, @tarojs/runtime employs react-reconciler to create a custom renderer located in @tarojs/react.
Web frameworks render a virtual Taro DOM tree using these simulated APIs. Unlike mini-programs that use static XML <template> references triggered by setData, HarmonyOS replaces templates with custom <element> components. The runtime maintains a root state variable, recursively traversing root.ch (children array) to mount the UI.
Page Structure
<element name="layout-wrapper" src="../../layout/index.hml"></element>
<element name="nav-bar" src="../../layout/components-harmony/navbar/index.hml"></element>
<div class="main-view">
<nav-bar title="{{navConfig.title}}" bg="{{navConfig.bg}}"></nav-bar>
<div class="content-area" style="padding-top: 44px;">
<layout-wrapper domTree="{{root}}"></layout-wrapper>
</div>
</div>Root Data Structure
{
"root": {
"ch": [
{
"css": "layout primary-bg",
"ch": [
{
"type": "#text",
"text": "Details"
},
{
"type": "view",
"id": "n_102"
}
],
"type": "view",
"id": "n_100"
}
],
"id": "pages/detail/index"
}
}Recursive Container Template
<element name="layout-wrapper" src="./index.hml"></element>
<block for="{{node in root.ch}}">
<block if="{{node.type == 'view'}}">
<div style="{{node.st}}" class="{{node.css}}" id="{{node.id}}" @click="{{handleEvent}}">
<layout-wrapper domTree="{{node}}"></layout-wrapper>
</div>
</block>
<block if="{{node.type == 'input'}}">
<custom-input value="{{node.val}}" placeholder="{{node.hint}}" class="{{node.css}}" id="{{node.id}}"></custom-input>
</block>
</block>Component Mapping
Taro implements a base component library adhering to WeChat mini-program specifications, mapped to HarmonyOS components. This involves two primary strategies:
1. Direct Base Component Translation: Taro elements are mapped directly to native HarmonyOS tags.
function mapBaseComponent(componentDef) {
let targetTag = '';
switch (componentDef.tag) {
case 'scroll-view':
case 'wrapper':
targetTag = 'div';
break;
case 'label':
targetTag = 'text';
break;
default:
targetTag = componentDef.tag;
}
return compileComponentMarkup(componentDef, targetTag);
}
function compileComponentMarkup(def, tag) {
const innerHtml = def.isVoid ? '' : `<block for="{{node.ch}}"><layout-wrapper node="{{$item}}"></layout-wrapper></block>`;
const resolvedTag = def.isNative ? `harmony-${tag}` : tag;
return `<block if="{{node.type == '${def.tag}'}}"><${resolvedTag} ${extractAttrs(def.attrs)} id="{{node.id}}">${innerHtml}</${resolvedTag}></block>`;
}2. Custom Component Alignment: When components share functionality but differ in attributes, custom wrappers are created. Unsupported attributes are omitted, and missing HarmonyOS attributes are appended within the /components/index.ts configuration.
const platformConfig = {
target: 'harmony',
globalVar: 'globalThis',
runtimePath: `${PKG}/dist/runtime`,
componentsPath: `${PKG}/dist/components/components-react`,
extensions: {
templ: '.hml',
style: '.css',
config: '.',
script: '.js'
}
}API Integration
Developers access Taro APIs via @tarojs/taro. On HarmonyOS, this object aggregates platform-agnostic APIs from @tarojs/api and platform-specific implementations from the HarmonyOS plugin. Since API names and properties differ, the initPlatformApis method overrides default Taro methods with custom HarmonyOS implementations.
import { log, currentCtx } from './helpers';
import * as platformApis from './apis';
export function initPlatformApis(taroInstance) {
currentCtx.taro = taroInstance;
taroInstance.initPxTransform = log;
Object.assign(taroInstance, platformApis);
}Routing Configuration
Pages defined in app.config dictate the application structure. The generated code targets the default directory, requiring manual updates to the HarmonyOS project's config. to register routes correctly.
Plugin Ecosystem
| Package | Description |
|---|---|
| @tarojs/cli | Command line interface for initialization and builds |
| @tarojs/taro-loader | Webpack loaders for Taro files |
| @tarojs/helper | Utility library for CLI and compilation |
| @tarojs/shared | Shared utilities for runtime |
| @tarojs/taro | Exposes the Taro object across platforms |
| @tarojs/plugin-platform-harmony | Compilation and adaptation layer for HarmonyOS |
| @tarojs/mini-runner | Build runner for mini-program environments |
Development Setup
1. Source Compilation and Linking
Clone the Taro repository, switch to the HarmonyOS feature branch, and compile the source code. Link the necessary packages locally.
git clone git@github.com:NervJS/taro.git
git checkout feature/harmony-support
yarn install
yarn build
cd packages/taro-cli && yarn link
cd ../taro-runtime && yarn link
cd ../taro-harmony && yarn link
cd ../taro-plugin-react && yarn link
cd ../taro-mini-runner && yarn link
cd ../taro && yarn link2. Project Initialization
Create a new Taro project and link the previously compiled packages.
taro init myHarmonyApp
cd myHarmonyApp
yarn link @tarojs/runtime @tarojs/plugin-platform-harmony @tarojs/plugin-framework-react @tarojs/mini-runner @tarojs/taro3. Build Configuration
Configure the output path to point to the HarmonyOS JS FA directory and enable the platform plugin.
const config = {
harmonyOutputPath: '...', // e.g., 'MyHarmonyApp/entry/src/main/js/default'
plugins: ['@tarojs/plugin-platform-harmony'],
mini: {
useDevReconciler: true, // Required for previewer debugging
enableSourceMap: false // Disable for physical device debugging
}
}4. HarmonyOS Project Settings
Update config. to define routing modules. To disable the default system navigation bar, add the following metadata configuration:
"metaData": {
"customizeData":[
{
"name": "hwc-theme",
"value": "androidhwext:style/Theme.Emui.NoTitleBar"
}
]
}5. Build Execution
taro compile --target harmony --dev