Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Taro Framework Adaptation for HarmonyOS Development

Tech 1

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.

  1. The CLI triggers @tarojs/mini-runner to handle the compilation phase.
  2. mini-runner adjusts Webpack configurations based on developer settings.
  3. Custom PostCSS plugins (e.g., postcss-pxtransform) and Webpack loaders are injected.
  4. Webpack executes the build process.
  5. The output is modified, and @tarojs/plugin-platform-harmony reconciles 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

PackageDescription
@tarojs/cliCommand line interface for initialization and builds
@tarojs/taro-loaderWebpack loaders for Taro files
@tarojs/helperUtility library for CLI and compilation
@tarojs/sharedShared utilities for runtime
@tarojs/taroExposes the Taro object across platforms
@tarojs/plugin-platform-harmonyCompilation and adaptation layer for HarmonyOS
@tarojs/mini-runnerBuild 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 link

2. 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/taro

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

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.