天天看点

hippy-react 支持转小程序

背景

Hippy-react 官方并没有提供同构小程序的方案;

思考:我们技术栈hippy-react,其他业务也有同构小程序的需求,是否可以支持项目一键转小程序,减少重复开发;

目标:同构

项目仓库:https://git.code.oa.com/melodyren/wx_hippy

基础框架选型

这里调研了业界开源框架;最主要的区别是 DSL;大多数遵循React语法或VUE语法;

我们团队是基于Hippy-React开发,语法是react;

关于vue语法相关框架uiapp, mpvue ,wepy不在我们考虑接入范围内;

我们主要对比了二个React语法框架:alita和taro;

hippy-react 支持转小程序

image

  1. Alita业内首个React Native转微信小程序引擎;Hippy React 基本兼容 React Native 语法;
  2. 组件标签: alita对齐hippy react是rn标签,taro是小程序标签;
  3. 样式规范: alita对齐hippy react是stylesheet,taro是sass,less;
  4. Alita 编译+运行时处理,(是基于组件的 template,动态 “递归” 渲染整棵树), 对JSX语法限制小;

    taro 2.0之前版本对JSX有诸多限制,比如暂不支持render()之外定义JSX;但2.0版本也改为了编译+运行时;

    这里之前有输出一篇文章:http://km.oa.com/group/38202/articles/show/415870 有兴趣可以查阅;

  5. 包大小:alita 非常纯碎,只做了转小程序功能;alita包更小,更有优势;
  6. alita分包,原生组件,第三方组件都支持;

通过对比,alita更契合我们业务,改动最小;对项目倾入性更小;

当然如果比github start数和稳定性,taro更有优势;但基于taro改造工程量有点大哦;

!!!基于alita进行改造,适配hippy-react;那么如何转呢?

整体架构

hippy-react 支持转小程序

image

  1. 整体要有hippy-react 开发体验;
  2. 组件和API对齐hippy官方API;
  3. 支持项目接入,优化webpack构建流程;
  4. 完成基础库同构;(此处是业务侧逻辑同构,每个业务侧不同);
  5. 支持第三方组件接入,比如trtc-room 是腾讯云官方提供的音视频组件,支持分平台处理;
  6. 性能优化;

如何做到组件/API对齐呢?

Alita对Hippy组件支持情况

- [x] View

- [x] Text

- [x] Image

- [x] TextInput

- [x] ScrollView

- [ ] ListView

- [ ] Animation

- [ ] AnimationSet

- [ ] ViewPage

- [ ] Navigato

- [ ] RefreshWrappe

- [x] Modal

其中

View

,

Text

,

Image

,

TextInput

,

ScrollView

,

Modal

,Alita均有提供,属性和方法稍加修改基本可以做到支持;

ViewPager

,

ListView

,

RefreshWrapper

,

Navigator

需要额外扩展@areslabs/wx-react-native 去支持;

Animation

,

AnimationSet

是Hippy提供的动画方案。Hippy的动画则是完全由前端传入动画参数,由终端控制每一帧的计算和排版更新,减少了js端与native端的通信次数,因此也大大减少动画的卡顿。而RN动画是前端驱动,状态值由前端计算,并且通过jsbridge传入终端实现动画。API对前端入门友好,并且方便状态管理。由于二端实现差异有点大,目前还未实现同构;

通过修改后对Hippy组件支持情况

- [x] View

- [x] Text

- [x] Image

- [x] TextInput

- [x] ScrollView

- [x] ListView

- [ ] Animation

- [ ] AnimationSet

- [x] ViewPage

- [x] Navigato

- [ ] RefreshWrapper(包装在listview)

- [x] Modal

Alita对Hippy模块支持情况

常用基本已支持;平台相关的组件,均没有实现

- [x] AsyncStorage

- [ ] BackAndroid 微信小程序限制

- [ ] Clipboard

- [x] Dimensions

- [ ] NetworkModule

- [ ] NetInfo

- [x] PixelRatio

- [x] Platform

- [x] Stylesheet

- [x] Timers

修改后对Hippy模块支持情况

- [x] AsyncStorage

- [ ] BackAndroid 微信小程序限制

- [ ] Clipboard

- [x] Dimensions

- [ ] NetworkModule

- [x] NetInfo

- [x] PixelRatio

- [x] Platform

- [x] Stylesheet

- [x] Timers

由于alita提供的组件和hippy-react内置组件并不完全对齐;我们将alita 开源项目拉取下来到我们仓库地址进行维护,并对wx-react-native模块进行修改,拉齐组件和api;完成同构;

(正常情况下:只要hippy-react 组件和api 有对应的小程序组件和api,我们就可以完成重构);

左侧是需要支持组件,右侧是对应小程序组件;

hippy-react 支持转小程序

image

这里是如何做到hippy 组件 和 小程序组件对齐的呢?我大概画了一下流程图:

hippy-react 支持转小程序

image

小程序的js文件,无法直接在React层运行,需要提供一个上层Viewpager的代理,这个代理将代替小程序Viewpager组件在React层运行;

第一步:一般需要在对应包的package.json文件的wxComponents 字段指定,建立联系;

第二步:继承自RNBaseComponent,提供上下两层交互数据能力,diff算法拿到变更传给小程序setData;事件回调点击事件触发了小程序事件再传给react运行环境;

Alita框架运行原理

官方文档:https://areslabs.github.io/alita/

hippy-react 支持转小程序

image

Alita 转小程序整体流程:webpack打包到js文件,js文件经过alita-loader处理收集信息info, 然后经过babel-loader 处理,最后通过webpack的alita-plugins(多个)生成小程序文件(wxml/wxss等)

Alita 的整体架构借鉴了 ReactNative,其上层存在一个为小程序定制的 mini-react,底层是负责实际渲染的小程序原生代码。而中间存在一个两层互相联系的 bridge。

hippy-react 支持转小程序

image

mini-react 负责运行所有 React 代码逻辑,包括递归的构建组件树结构,创建组件实例,执行组件对应生命周期,context 计算等等。其最终将生成一份描述小程序视图的数据。这份数据通过 bridge 模块传递到底层小程序。底层小程序实例调用 setData 方法把数据刷给自身,完成渲染。

如何集成到项目工程呢?

项目目录规范 - 接入方便,只须在之前项目目录新增打包配置文件alita.config.js 和小程序入口文件index.wx.js

hippy-react 支持转小程序

image

alita.config.js 说明:

const path = require("path");

module.exports = {
  name: "HelloWorldExpo",//生成的微信小程序项目名
  appid: "wxc88f41e36c417bff",//调试小程序的appid,由微信申请而来
  entry: "./projects/HelloWorldExpo/index.js",//定义页面的入口文件
  output: "./output/wx-dist/HelloWorldExpo",//输出目录,小程序生成代码输出目录
  include: [ //符合alita规范,直接转化的组件,alita使用的是webpack打包的方式,会使用alita-loader去解析
    path.resolve("./projects/HelloWorldExpo/"), // 指定项目
    //path.resolve("./library/components/CountPane.js"), //可以引入项目外的通用组局
    // path.resolve("node_modules", "@areslabs", "hello-rn")//可以引入npm包
  ],
  resolve: {
    alias: { //别名
      // "@tencent/hippy-react": "@areslabs/wx-react-native"
    },
    // symlinks: false
  },
  miniprogramComponents: { // 第三方组件
    // "trtc-room": "/weixin/components/trtc-room/trtc-room"
  }
};           

复制

符合alita规范,直接转化的组件,可在配置文件include 添加路径, alita使用的是webpack打包的方式,会使用alita-loader去解析;

如果是对小程序内置组件或者对小程序自定义组件的使用,都是只会在小程序平台生效,所以需要平台判断,和ReactNative一样,一般有两种方式: 文件内判断和建立平台文件

  1. 文件内判断 if (Platoform.OS === 'wx') {

    return 小程序的view // <-- 直接使用小程序组件

    } else {

    return Hippy-React的View // <-- 使用Hippy-React组件

    }

  2. 建立平台文件:(建议差异比较大的)

    建立平台文件的方式,即建立单独的小程序.wx后缀文件,比如Map.wx.js

入口文件

React 组件会被转化为 wxml/wxss/js/json 4个文件, 这里有一个例外:入口文件。入口文件里面定义了所有的页面,由于小程序的页面必须预先定义在 app.json 文件,json文件是静态的,无法在运行时处理,因此我们必须在转化的时候就识别出

所有的页面

,所以对于入口文件的文件要求是足够的静态,为了减少错误,尽量不要在入口文件处理其它逻辑,仅将入口文件用来定义路由页面。

详情请看官方文档: https://areslabs.github.io/alita/入口文件.html

import React, { PureComponent } from "react";
import { Router, Route } from "@areslabs/router";
import Room from "./pages/Room";
// import Player from "./components/Room/Player";
export default class App extends PureComponent {
  render() {
    return (
      <Router
        wxNavigationOptions={{
          // navigationBarTitleText: "",
          navigationBarBackgroundColor: "#291B54"
          // navigationBarTextStyle: "black"
        }}
        navigationOptions={{
          title: "相亲房间"
        }}
      >
        <Route key="Room" component={Room} />
        {/* <Route key="Player" component={Player} /> */}
      </Router>
    );
  }
}           

复制

项目运行:

类似wepack执行,接入了yargs,支持三种模式,最终都是用alita-core去打包;

# 开发模式 
dating run-wx —dev [projectname]
# 打包模式 
dating run-wx --build [projectname] 
# 分析包模式
dating run-wx —analyzer [projectname]           

复制

const argv = yargs
    .command(COMMAND.RUN_WX, "运行 wx 环境", function(yargs) {
      var _argv = yargs
        .reset()
        .option("dev", {
          alias: "dev",
          demand: false,
          describe: "是否开发环境",
          type: "boolean"
        })
        .option("build", {
          alias: "build",
          demand: false,
          describe: "是否编译环境",
          type: "boolean"
        })
        .option("analyzer", {
          alias: "analyzer",
          demand: false,
          describe: "分析包",
          type: "boolean"
        }).argv;
      if (_argv._ && _argv._[1]) {
        _argv.entry = _argv.e = _argv._[1];
      }
      process.argv.push("--config");
      process.argv.push("./projects/" + _argv.entry + "/alita.config.js");
      require("@tencent/alita-core/lib/index");
    })           

复制

微信小程序的体积是有限制的,“代码体积小于 2M,分包 8M”。借助webpack的BundleAnalyzerPlugin插件,只需要在执行时候添加 --analyzer 参数即可;

hippy-react 支持转小程序

image

总结:Alita是基于RN转小程序,hippy-react和RN 的差异主要是在组件和api,站在巨人的肩膀上,我们很容易实现hippy-react转小程序;集成到工程需要看一下源码,做相对应改造;

目前K歌轻缘相亲做了简单尝试,欢迎大家体验(完整流程是下载相亲APP,打开相亲房间,分享相亲房间到微信,可以在微信内观看直播相亲哦)

hippy-react 支持转小程序

image