Таро на самом деле совместим с Хунмэн!

внешний интерфейс
Таро на самом деле совместим с Хунмэн!

Для меня большая честь быть соавтором адаптации Таро к разработке Хунмэн.Вот некоторые из моих опытов во время разработки. Он также столкнулся со многими ямами, через которые нужно было перелезть.

Принцип адаптации Таро для Хунмэн

HarmonyOS — это новая распределенная операционная система эпохи Интернета всего.

Taro — это открытое кросс-энд и кросс-платформенное решение, которое поддерживает использование таких фреймворков, как React/Vue/Nerv, для разработки WeChat/JD/Baidu/Alipay/ByteDance/QQ Mini Programs/H5/RN и других приложений.

Существует три типа разработки HarmonyOS: Java, Js, Native. Развитие Hongmeng Js похоже на развитие Taro. Его можно преобразовать в код Хунмэн в соответствии с нашим кодом Таро. Основные принципы заключаются в следующем:

принцип

общий принцип

taro cli
Разбирать разные плагины по разным типам
Используйте webpack для компиляции кода с каждой стороны
Затем используйте собственную конфигурацию подключаемых модулей каждого конца, чтобы сгладить код каждого конца.
Сгенерировать код гармонии

компилировать

общий принцип

код таро
Начать компиляцию через tarojs/cli
tarojs/service определяет пакеты, используемые разными терминалами
Упаковка с тарой/мини-бегуном
Сгладить код Hongmeng через плагин plugin-platform-harmony
Сгенерировать код гармонии

Принцип @tarojs/mini-runner

код таро
Разбор АСТ
Разобрать код рендеринга
Конвертировать со скриптом
сгенерировать код

При компиляции Hongmeng CLI вызовет@tarojs/mini-runnerПакет, этот пакет в основном для компиляции кода.mini-runnerДелайте в основном следующие вещи:

  1. Отвечает за настройку конфигурации Webpack в соответствии с конфигурацией компиляции разработчика.
  2. Добавляйте пользовательские плагины PostCSS. (например, postcss-pxtransform)
  3. Вставьте пользовательский плагин Webpack.
  4. Внедрить пользовательские загрузчики Webpack. (Погрузчики находятся в@tarojs/taro-loaderв сумке)
  5. Вызовите Webpack, чтобы начать компиляцию.
  6. Измените продукт компиляции Webpack и скорректируйте окончательный результат компиляции.

Тогда согласно@tarojs/plugin-platform-harmonyВнесите коррективы для компонентов, API и маршрутов, они будут сглажены в этом плагине.

правильноmini-runnerанализировать

├── src
|   ├── config                      项目配置文件
|   ├── dependencies                项目依赖文件
|   ├── loader                      自定义loader
|   |   ├── quickappStyleLoader     快应用                      
|   |   └── miniTemplateLoader      小程序模版解析器
|   ├── plugins                     自定义插件
|   ├── prerender                   自定义的代码结构
|   ├── template                    自定义模版
|   |   ├── comp                    组件模版
|   |   ├── component               自定义组件模版
|   |   └── custom-wrapper          自定义小程序插件
|   ├── utils                       公共配置
|   ├── webpack                     webpack配置
|   |   ├── base.conf               基础配置
|   |   ├── build.conf              打包配置
|   |   ├── chain                   插件和解析器
|   |   └── postcss.conf            对css转换的配置
|   └── index                       webpack的启动
└── index                           入口文件

Примечание: Babel использует плагины

вавилонское использование инструкция
@babel/core Разберите код, чтобы получить AST
@babel/types Определения узлов AST, генерирующие узлы
@babel/traverse Рекурсивный обход AST
@babel/generator AST генерирует исходный код

исходный код --> конечный код

<View className="flex items-center h-44 pb-40">
  <SlPrice price={ price } />
  {
    tags.length !== 0 &&
    tags.map(tag =>
      <View className="px-20 py-6 mx-12 bg-red-light text-yellow text-22 rounded-20" key={ tag }>{tag}</View>
    )
  }
</View>
(_tarojs_components__WEBPACK_IMPORTED_MODULE_1__[/* View */ "d"], {
  className: "flex items-center h-44 pb-40",
  children: [/*#__PURE__*/Object(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__["jsx"])(_jd_selling_c_ui__WEBPACK_IMPORTED_MODULE_2__[/* SlPrice */ "e"], {
    price: price
  }), tags.length !== 0 && tags.map(function (tag) {
    return /*#__PURE__*/Object(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__["jsx"])(_tarojs_components__WEBPACK_IMPORTED_MODULE_1__[/* View */ "d"], {
      className: "px-20 py-6 mx-12 bg-red-light text-yellow text-22 rounded-20",
      children: tag
    }, tag);
  })]
})

Обработка шаблона

бегать

Чтобы такие фреймворки, как React и Vue, могли работать непосредственно на Hongmeng, нам необходимо имитировать среду браузера на логическом уровне апплета, включая реализацию DOM, BOM API и т. д.

@tarojs/runtimeЭто ядро ​​​​адаптера времени выполнения Taro, которое реализует упрощенную DOM, BOM API, систему событий, связующий уровень веб-фреймворка и фреймворка апплета и т. д. Этот пакет в основном предназначен для адаптации апплета и операции h5, поскольку ReactDOM большой и содержит много кода совместимости. Таким образом, Taro реализует собственный рендерер вместо ReactDOM с помощью react-reconciler. Рендер находится в пакете @tarojs/react.

Веб-фреймворк может визуализировать дерево DOM Taro с помощью смоделированного API Taro, но все это выполняется на логическом уровне апплета. И шаблон xml апплета нужно заранее прописать до смерти, Таро решил использовать апплет<template>могу привести другие<template>, который отображает каждый узел DOM дерева DOM Таро как соответствующий<template>. В настоящее время вам нужно только setData сериализованные данные дерева DOM Таро для запуска<template>взаимные ссылки для отображения окончательного пользовательского интерфейса.

А у Хунмэна нет<template>концепция, мы используем нестандартные компонентыelementзаменять.

Во время выполнения мы будем рассматривать DOM-дерево Taro, упомянутое выше, как целую переменную.rootдля запуска кода. Тогда согласноroot.cnСледующий массив для обхода и рекурсии нашего пользовательского компонента

содержание страницы

<element name="container" src="../../container/index.hml"></element>
<element name="navbar" src="../../container/components-harmony/navbar/index.hml"></element>
<element name="tabbar" src="../../container/components-harmony/tabbar/index.hml"></element>

<div class="container">
  <navbar title="{{taroNavBar.title}}" background="{{taroNavBar.background}}" text-style="{{taroNavBar.textStyle}}" st="{{taroNavBar.style}}"></navbar>
  <div class="body" style="padding-top: 44px;padding-bottom: {{isShowTaroTabBar ? '56px' : '0'}}">
    <refresh if="{{enablePullDownRefresh}}" type="pulldown" refreshing="{{isRefreshing}}" onrefresh="onPullDownRefresh">
      <container root="{{root}}"></container>
    </refresh>
    <container else root="{{root}}"></container>
  </div>
  <tabbar if="{{isShowTaroTabBar}}" data="{{taroTabBar}}" selected="{{selected}}"></tabbar>
</div>

корневые данные

{
  "root": {
    "cn": [
      {
        "cl": "layout bg-gray-lightbg",
        "cn": [
          {
            "cn": [
              {
                "nn": "#text",
                "v": "订单"
              }
            ],
            "nn": "view",
            "uid": "_n_885"
          },
          {
            "cl": "layout-area-slot w-full h-210 area-slot",
            "cn": [],
            "nn": "pure-view",
            "uid": "_n_888"
          }
        ],
        "nn": "pure-view",
        "uid": "_n_886"
      }
    ],
    "uid": "pages/tab-bar/order/index?$taroTimestamp=1636613920366"
  },
}

содержимое контейнера

<element name="container" src="./index.hml"></element>
<element name="taro-textarea" src="./components-harmony/textarea/index.hml"></element>


<block for="{{i in root.cn}}">

<block if="{{i.nn == 'view'}}">
  <div hover-class="{{i.hoverClass===undefined?'none':i.hoverClass}}" hover-stop-propagation="{{i.hoverStopPropagation===undefined?false:i.hoverStopPropagation}}" hover-start-time="{{i.hoverStartTime===undefined?50:i.hoverStartTime}}" hover-stay-time="{{i.hoverStayTime===undefined?400:i.hoverStayTime}}" @touchstart="{{eh}}" @touchmove="{{eh}}" @touchend="{{eh}}" @touchcancel="{{eh}}" @longtap="{{eh}}" animation="{{i.animation}}" @animationstart="{{eh}}" @animationiteration="{{eh}}" @animationend="{{eh}}" @transitionend="{{eh}}" style="{{i.st}}" class="{{i.cl}}" @click="{{eh}}"  id="{{i.uid}}">
    <container root="{{i}}"></container>
  </div>
</block>

<block if="{{i.nn == 'textarea'}}">
  <taro-textarea value="{{i.value}}" placeholder="{{i.placeholder}}" placeholder-style="{{i.placeholderStyle}}" placeholder-class="{{i.placeholderClass===undefined?'textarea-placeholder':i.placeholderClass}}" disabled="{{i.disabled}}" maxlength="{{i.maxlength===undefined?140:i.maxlength}}" auto-focus="{{i.autoFocus===undefined?false:i.autoFocus}}" focus="{{i.focus===undefined?false:i.focus}}" auto-height="{{i.autoHeight===undefined?false:i.autoHeight}}" fixed="{{i.fixed===undefined?false:i.fixed}}" cursor-spacing="{{i.cursorSpacing===undefined?0:i.cursorSpacing}}" cursor="{{i.cursor===undefined?-1:i.cursor}}" selection-start="{{i.selectionStart===undefined?-1:i.selectionStart}}" selection-end="{{i.selectionEnd===undefined?-1:i.selectionEnd}}" @focus="{{eh}}" @blur="{{eh}}" @linechange="{{eh}}" @input="{{eh}}" @confirm="{{eh}}" name="{{i.name}}" headericon="{{i.headericon}}" showcounter="{{i.showcounter===undefined?false:i.showcounter}}" menuoptions="{{i.menuoptions===undefined?[]:i.menuoptions}}" softkeyboardenabled="{{i.softkeyboardenabled===undefined?true:i.softkeyboardenabled}}" @translate="{{eh}}" @share="{{eh}}" @search="{{eh}}" @optionselect="{{eh}}" @selectchange="{{eh}}" style="{{i.st}}" class="{{i.cl}}" @click="{{eh}}"  id="{{i.uid}}">
    
  </taro-textarea>
</block>

...

</block>

компоненты

Taro реализует базовую библиотеку компонентов, соответствующую спецификации апплета WeChat на стороне Hongmeng.

будет использоваться по умолчанию@tarojs/componentsПредоставляет библиотеку компонентов веб-компонентов.

В настоящее время необходимо соединить библиотеку компонентов Taro с библиотекой компонентов, поставляемой с Hongmeng, и последовательно выравнивать свойства и события в компонентах. Для компонентов, которых нет у Hongmeng, разработайте пользовательское выравнивание компонентов. Поскольку теги Hongmeng аналогичны тегам в Интернете, все теги в настоящее время необходимо переупаковывать. Существуют в основном два типа ситуаций:

  1. заключается в преобразовании базового компонента в наш целевой компонент

Базовый компонент предназначен для прямой адаптации базовых компонентов Taro к библиотеке базовых компонентов Hongmeng, как показано в следующем коде:

buildStandardComponentTemplate (comp) {
  let nodeName = ''
  switch (comp.nodeName) {
    case 'slot':
    case 'slot-view':
    case 'cover-view':
    case 'view':
    case 'swiper-item':
      nodeName = 'div'
      break
    case 'static-text':
      nodeName = 'text'
      break
    case 'static-image':
      nodeName = 'image'
      break
    default:
      nodeName = comp.nodeName
      break
  }
  return this.generateComponentTemplateSrc(comp, nodeName)
}

generateComponentTemplateSrc (comp, nodeName?): string {
  const children = this.voidElements.has(comp.nodeName)
    ? ''
    : `<block for="{{i.cn}}">
    <container i="{{$item}}"></container>
  </block>`
  if (!nodeName) {
    nodeName = comp.nodeName
  }
  if (this.nativeComps.includes(nodeName)) {
    nodeName = `taro-${nodeName}`
  }

  const res = `
<block if="{{i.nn == '${comp.nodeName}'}}">
<${nodeName} ${this.buildAttrs(comp.attributes, comp.nodeName)} id="{{i.uid}}">
  ${children}
</${nodeName}>
</block>
`
  return res
}
  1. Хунмэн и Таро имеют одинаковый состав, но разные атрибуты. В этом случае мы переписываем компонент как пользовательский компонент.В пользовательском компоненте атрибуты компонента будут выровнены с атрибутами Hongmeng.Если Hongmeng не имеет соответствующих атрибутов, его можно отбросить. Для компонентов Hongmeng есть свойства, которых нет в Taro, в файле конфигурации компонента/components/index.tsдобавить соответствующие атрибуты.
// program.ts

platform = 'harmony'
globalObject = 'globalThis'
runtimePath = `${PACKAGE_NAME}/dist/runtime`
taroComponentsPath = `${PACKAGE_NAME}/dist/components/components-react`
fileType = {
  templ: '.hml',
  style: '.css',
  config: '.json',
  script: '.js'
}

// components-harmony文件夹下
├── components-harmony
    ├──image
    ├──input
    └──...

API

разработчик из@tarojs/taroСсылайтесь на объект Taro и используйте предоставляемый им API.

В среде Хунмэн,@tarojs/taroБудет получать независимые от платформы API из @tarojs/api, из@tarojs/plugin-platform-harmonyAPI-интерфейсы, реализованные в соответствии со спецификацией HarmonyOS, окончательно собираются в объект Taro и предоставляются разработчикам.

Для разработки системы Hongmeng функции API аналогичны API Taro, но имена и атрибуты отличаются. позвонивinitNativeApiМетод Мы напрямую заменяем методы API внутри таро и используем собственные методы API для реализации методов Hongmeng API.

// /apis/index.ts
import { noop, current } from './utils'
import * as apis from './apis'

export function initNativeApi (taro) {
  current.taro = taro
  taro.initPxTransform = noop
  Object.assign(taro, apis)
}

// apis文件夹下
├── apis
    ├── interactive
    ├── navbar
    ├── ...
    └── index.ts

маршрутизация

в соответствии сapp.configСтраницы разделены на страницы, и в настоящее время сгенерированный код используется по умолчанию. Вам нужно вручную изменить проект Hongmengconfig.jsonИсправлять

Описание плагина

публичный

дорожка инструкция
@tarojs/cli Инструменты CLI (инициализация/сборка)
@tarojs/taro-loader Webpack loaders
@tarojs/helper Библиотека инструментов, в основном для CLI, использование времени компиляции
@tarojs/runner-utils Библиотека инструментов, в основном используемая для небольших программ и инструментов компиляции H5.
@tarojs/shared Библиотека инструментов, в основном для использования во время выполнения
@tarojs/taro Раскройте предметы Таро, необходимые каждой стороне
@tarojs/api Бесконечный API Таро
babel-preset-taro Babel preset
eslint-config-taro Правила ESLint
postcss-pxtransform Плагин PostCSS для преобразования px в адаптивный размер с каждой стороны

Хунмэн

дорожка инструкция
@tarojs/plugin-platform-harmony Составление и адаптация Hongmeng
@tarojs/mini-runner компиляция апплета

развивать

Адаптация Таро к Хунмэн находится в стадии разработки и может быть выполненаfeat/harmonyРазветвите код и скомпилируйте его для использования.

1. Загрузите исходный код Taro и скомпилируйте его.

Нужно связать адаптацию Hongmeng

# 下载源码
$ git clone git@github.com:NervJS/taro.git
$ git checkout feat/harmony

# 安装依赖
$ yarn

# 编译
$ yarn build

# yarn link (harmony 基于 Taro v3.4,但 v3.4 暂时还未发布,所以需要把 3.4 改动的包都进行软链)
$ cd packages/taro-cli
$ yarn link
$ cd ../taro-runtime
$ yarn link
$ cd ../taro-harmony
$ yarn link
$ cd ../taro-plugin-react
$ yarn link
$ cd ../taro-plugin-vue2
$ yarn link
$ cd ../taro-plugin-vue3
$ yarn link
$ cd ../taro-mini-runner
$ yarn link
$ cd ../taro
$ yarn link
$ cd ../taro-api
$ yarn link
$ cd ../shared
$ yarn link
$ cd ../taro-loader
$ yarn link

2. Установите @tarojs/cli, создайте проект Taro и создайте мягкую цепочку.

Установите @tarojs/cli (если он был установлен локально, вы можете пропустить этот шаг)

# 使用 npm 安装 CLI
$ npm install -g @tarojs/cli

# OR 使用 yarn 安装 CLI
$ yarn global add @tarojs/cli

# OR 安装了 cnpm,使用 cnpm 安装 CLI
$ cnpm install -g @tarojs/cli

Создайте проект Таро и постройте мягкую цепочку

taro init myApp
cd myApp
yarn link @tarojs/runtime
yarn link @tarojs/plugin-platform-harmony
yarn link @tarojs/plugin-framework-react
yarn link @tarojs/plugin-framework-vue2
yarn link @tarojs/plugin-framework-vue3
yarn link @tarojs/mini-runner
yarn link @tarojs/taro
yarn link @tarojs/api
yarn link @tarojs/shared
yarn link @tarojs/taro-loader

# OR
yarn link @tarojs/runtime @tarojs/plugin-platform-harmony @tarojs/plugin-framework-react @tarojs/plugin-framework-vue2 @tarojs/plugin-framework-vue3 @tarojs/mini-runner @tarojs/taro @tarojs/api @tarojs/shared @tarojs/taro-loader

3. Скомпилируйте конфигурацию

// config/index.js
config = {
  // 配置输出路径,输出到鸿蒙 JS FA 的对应目录下。(支持绝对路径、相对路径)
  // 例如鸿蒙应用名称为 MyApplication,JS FA 名称为默认的 default,那么 outputRoot 需要设置为:
  // 'MyApplication/entry/src/main/js/default'
  outputRoot: '...',
  // 配置使用插件
  plugins: ['@tarojs/plugin-platform-harmony'],
  mini: {
    // 如果使用开发者工具的预览器(previewer)进行预览的话,需要使用 development 版本的 react-reconciler。
    // 因为 previewer 对长串的压缩文本解析有问题。(真机/远程真机没有此问题)
    debugReact: true,
    // 如果需要真机断点调试,需要关闭 sourcemap 的生成
    enableSourceMap: false
  }
}

4. Конфигурация проекта Хунмэн

Подробная документация файла конфигурации Hongmeng:Элементы файла конфигурации

4.1 Настройка маршрутизации

Предполагая, что существует проект Hongmeng MyApplication, если вам нужно настроить маршрутизацию, вы можете изменитьMyApplication/entry/src/main/config.jsonизmodules.jsконфигурация.

4.2 Закройте верхнюю панель навигации, которая поставляется вместе с системой

ИсправлятьMyApplication/entry/src/main/config.jsonизmodulesКонфигурация, добавьте следующее:

"metaData": {
  "customizeData":[
    {
      "name": "hwc-theme",
      "value": "androidhwext:style/Theme.Emui.NoTitleBar"
    }
  ]
}

5. Скомпилируйте

taro build --type harmony --watch

6. Беги

6.1 Создайте проект Hongmeng JS, например MyApplication

Инструменты разработчика Huawei:developer.harmony OS.com/talent/develop/…Документация по разработке Hongmeng:developer.harmony OS.com/talent/document…

6.2 Используйте средство предварительного просмотра, реальную машину и удаленную реальную машину инструментов разработчика Hongmeng для предварительного просмотра

документация по предварительному просмотру:developer.harmony OS.com/talent/docs/doc…

sudo launchctl unload /Library/LaunchDaemons/com.terminal.plist 
关掉公司电脑自动删除 adb 服务的启动项

安装 adb 工具:
brew install android-platform-tools 

demo

Проект Хунмэн Таро:содержание

Я хотел бы поблагодарить авторов Таро за их помощь и внимательное обучение. Разрабатываемая версия Таро, адаптированная к Хунмэн, будет выпущена в конце этого месяца, надеюсь, вы меня поправите.