背景
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;
image
- Alita業内首個React Native轉微信小程式引擎;Hippy React 基本相容 React Native 文法;
- 元件标簽: alita對齊hippy react是rn标簽,taro是小程式标簽;
- 樣式規範: alita對齊hippy react是stylesheet,taro是sass,less;
-
Alita 編譯+運作時處理,(是基于元件的 template,動态 “遞歸” 渲染整棵樹), 對JSX文法限制小;
taro 2.0之前版本對JSX有諸多限制,比如暫不支援render()之外定義JSX;但2.0版本也改為了編譯+運作時;
這裡之前有輸出一篇文章:http://km.oa.com/group/38202/articles/show/415870 有興趣可以查閱;
- 包大小:alita 非常純碎,隻做了轉小程式功能;alita包更小,更有優勢;
- alita分包,原生元件,第三方元件都支援;
通過對比,alita更契合我們業務,改動最小;對項目傾入性更小;
當然如果比github start數和穩定性,taro更有優勢;但基于taro改造工程量有點大哦;
!!!基于alita進行改造,适配hippy-react;那麼如何轉呢?
整體架構
image
- 整體要有hippy-react 開發體驗;
- 元件和API對齊hippy官方API;
- 支援項目接入,優化webpack建構流程;
- 完成基礎庫同構;(此處是業務側邏輯同構,每個業務側不同);
- 支援第三方元件接入,比如trtc-room 是騰訊雲官方提供的音視訊元件,支援分平台處理;
- 性能優化;
如何做到元件/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,我們就可以完成重構);
左側是需要支援元件,右側是對應小程式元件;
image
這裡是如何做到hippy 元件 和 小程式元件對齊的呢?我大概畫了一下流程圖:
image
小程式的js檔案,無法直接在React層運作,需要提供一個上層Viewpager的代理,這個代理将代替小程式Viewpager元件在React層運作;
第一步:一般需要在對應包的package.json檔案的wxComponents 字段指定,建立聯系;
第二步:繼承自RNBaseComponent,提供上下兩層互動資料能力,diff算法拿到變更傳給小程式setData;事件回調點選事件觸發了小程式事件再傳給react運作環境;
Alita架構運作原理
官方文檔:https://areslabs.github.io/alita/
image
Alita 轉小程式整體流程:webpack打包到js檔案,js檔案經過alita-loader處理收集資訊info, 然後經過babel-loader 處理,最後通過webpack的alita-plugins(多個)生成小程式檔案(wxml/wxss等)
Alita 的整體架構借鑒了 ReactNative,其上層存在一個為小程式定制的 mini-react,底層是負責實際渲染的小程式原生代碼。而中間存在一個兩層互相聯系的 bridge。
image
mini-react 負責運作所有 React 代碼邏輯,包括遞歸的建構元件樹結構,建立元件執行個體,執行元件對應生命周期,context 計算等等。其最終将生成一份描述小程式視圖的資料。這份資料通過 bridge 子產品傳遞到底層小程式。底層小程式執行個體調用 setData 方法把資料刷給自身,完成渲染。
如何內建到項目工程呢?
項目目錄規範 - 接入友善,隻須在之前項目目錄新增打包配置檔案alita.config.js 和小程式入口檔案index.wx.js
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一樣,一般有兩種方式: 檔案内判斷和建立平台檔案
-
檔案内判斷 if (Platoform.OS === 'wx') {
return 小程式的view // <-- 直接使用小程式元件
} else {
return Hippy-React的View // <-- 使用Hippy-React元件
}
-
建立平台檔案:(建議差異比較大的)
建立平台檔案的方式,即建立單獨的小程式.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 參數即可;
image
總結:Alita是基于RN轉小程式,hippy-react和RN 的差異主要是在元件和api,站在巨人的肩膀上,我們很容易實作hippy-react轉小程式;內建到工程需要看一下源碼,做相對應改造;
目前K歌輕緣相親做了簡單嘗試,歡迎大家體驗(完整流程是下載下傳相親APP,打開相親房間,分享相親房間到微信,可以在微信内觀看直播相親哦)
image