diff --git a/docs/api/_sidebar.md b/docs/api/_sidebar.md index e3f5b9ca36c..9d174cd59a0 100644 --- a/docs/api/_sidebar.md +++ b/docs/api/_sidebar.md @@ -8,6 +8,7 @@ * [手势系统](api/hippy-react/gesture.md) * [自定义组件和模块](api/hippy-react/customize.md) * [转 Web](api/hippy-react/web.md) + * [React 常见反馈](api/hippy-react/feedback.md) * hippy-vue * [介绍](api/hippy-vue/introduction.md) * [核心组件](api/hippy-vue/components.md) @@ -19,12 +20,15 @@ * [路由](api/hippy-vue/router.md) * [转 Web](api/hippy-vue/web.md) * [Vue 3.x](api/hippy-vue/vue3.md) + * [Vue 常见反馈](api/hippy-vue/feedback.md) * 样式 * [布局](api/style/layout.md) * [外观](api/style/appearance.md) * [颜色](api/style/color.md) * [变形](api/style/transform.md) * [更改终端属性](api/style/setNativeProps.md) + * [样式常见反馈](api/style/feedback.md) * [网络请求](api/network-request.md) * [性能监控](api/performance.md) * [定时器](api/timer.md) +* [常见反馈](api/feedback.md) diff --git a/docs/api/feedback.md b/docs/api/feedback.md new file mode 100644 index 00000000000..56591147dab --- /dev/null +++ b/docs/api/feedback.md @@ -0,0 +1,92 @@ +# 常见反馈 + +## 1. Hippy提供了@hippy/react-web和Web Renderer两套方案,哪一套方案转web的能力更完整一些呢?Hippy后续会重点支持哪一个方向? + +两套方案都有一些业务在用, 组件和属性支持可以参考这两个文档 + +https://iwiki.woa.com/p/1478044741 + +https://iwiki.woa.com/p/1410007954 + +Hippy 会继续维护 Web Renderer,基于 Web Render,更容易对接 kbone 等来扩展小程序 + +## 2. Hippy 如何支持小程序 + +可以Hippy 对接 Kbone、taro、uniapp 等框架,腾讯内部业务可参考其他[业务方案](https://doc.weixin.qq.com/doc/w3_ANsAsgZ1ACcxxR1G3KPR0K85XYnmP?scode=AJEAIQdfAAoD1a4bp0ANsAsgZ1ACc): + +## 3. Hippy 的组件库有推荐吗 + +[开源仓库](https://github.com/hippy-contrib) + +[腾讯内部仓库](https://raftx.woa.com/hippy) + +## 4. Hippy 如何做曝光上报 + +目前 Hippy 还没有对外的曝光上报方案,腾讯内部的业务,可以使用大同来做曝光上报 + +### 方案 + +hippy本质上使用的还是客户端原生组件 以及一部分自绘组件。客户端已集成的的大同sdk能够对原生组件、Activity等做检测上报,自然也可以对hippy的组件做检测上报。重点处理上报id绑定到组件的逻辑就可以。 + +### 接入指引 + +[Hippy Android 曝光上报指引](https://iwiki.woa.com/p/956352478) + +[Hippy iOS 曝光上报指引](https://iwiki.woa.com/p/589637144) + +有疑问可以咨询企业微信 TDF小助手 + + +## 5. 启动时, Hippy 如何从终端获取参数 + +React 通过根节点的 props 获取启动参数 + +Vue 通过 Vue.$start 回调获取启动参数 + +## 6. Hippy 页面支持 width: auto 吗 + +不支持的,可以用imageloader加载读图片尺寸,https://hippyjs.org/#/hippy-vue/vue-native?id=imageloader + +## 7. Hippy 背景透明是否支持毛玻璃效果呢 + +腾讯业务可参考[社区组件](https://raftx.woa.com/hippy/detail/578) + +## 8. Hippy 如何实现暗黑模式 + +有两种方案: + +方案一:设置2套css属性,然后切换时整体切换,性能较差 + +方案二:初始化节点时,把两套属性都带下去,然后终端渲染时切换 + +## 9. Hippy 有提供类似 IntersectionObserver 方法吗 + +react 还不支持,vue有封装了一个,可以参考封装下 [hippy-vue-intersection-observer](https://www.npmjs.com/package/hippy-vue-intersection-observer) 不过这个库是基于hippy的Measure API实现的,对bridge通信性能会有一定性能影响,使用时注意评估下 + +## 10. Hippy 有 Clipboard 的复制剪切功能吗 + +剪切板相关的能力应该是在3.2移出的,其他版本可以参考文档:https://github.com/Tencent/Hippy/blob/v2.15.x/docs/hippy-react/modules.md#clipboard + +## 11. 我们现在前端用的是React技术栈,我们想一部分业务用Vue,一部分业务用React,Hippy支持这种用法吗 + +支持的,但是react 和 vue得是不同的hippy引擎实例 + +## 12. Hippy 如何判断横屏 + +进入app后,横屏切换会触发 onSizeChanged 事件 + +进入app前已经横屏,这个可以读 Vue.Native.Dimensions ,获取当前窗口长宽来计算,可以参考这个帖子 https://mk.woa.com/q/293192?ADTAG=search + +## 13. Hippy 图片必须要设定宽高吗?希望宽度和父级view一样,高度自适应怎么写呢 + +可以用 ImageLoaderModule.getSize 这个接口先获取图片大小 https://hippyjs.org/#/hippy-react/modules?id=imageloadermodule + +## 14. 执行报错 startBatch is not a function, 可能是什么原因 + +startBatch是 Hippy2 才有的版本,如果前端使用 Hippy2 终端使用 Hippy3 会不兼容,检查下@hippy/hippy-vue 的版本,确保和终端版本一致 + +## 15. Hippy 是否支持动态加载 + +支持,参考 https://doc.openhippy.com/#/feature/feature2.0/dynamic-import + + diff --git a/docs/api/hippy-react/_sidebar.md b/docs/api/hippy-react/_sidebar.md index e3f5b9ca36c..9d174cd59a0 100644 --- a/docs/api/hippy-react/_sidebar.md +++ b/docs/api/hippy-react/_sidebar.md @@ -8,6 +8,7 @@ * [手势系统](api/hippy-react/gesture.md) * [自定义组件和模块](api/hippy-react/customize.md) * [转 Web](api/hippy-react/web.md) + * [React 常见反馈](api/hippy-react/feedback.md) * hippy-vue * [介绍](api/hippy-vue/introduction.md) * [核心组件](api/hippy-vue/components.md) @@ -19,12 +20,15 @@ * [路由](api/hippy-vue/router.md) * [转 Web](api/hippy-vue/web.md) * [Vue 3.x](api/hippy-vue/vue3.md) + * [Vue 常见反馈](api/hippy-vue/feedback.md) * 样式 * [布局](api/style/layout.md) * [外观](api/style/appearance.md) * [颜色](api/style/color.md) * [变形](api/style/transform.md) * [更改终端属性](api/style/setNativeProps.md) + * [样式常见反馈](api/style/feedback.md) * [网络请求](api/network-request.md) * [性能监控](api/performance.md) * [定时器](api/timer.md) +* [常见反馈](api/feedback.md) diff --git a/docs/api/hippy-react/customize.md b/docs/api/hippy-react/customize.md index ed30972d492..971c9aa40aa 100644 --- a/docs/api/hippy-react/customize.md +++ b/docs/api/hippy-react/customize.md @@ -36,14 +36,20 @@ export class MyView extends React.Component { # 自定义模块 -> 该范例仅可以在 Android 下运行。 - 前端扩展模块分为三步: 1. 第一步导入 callNative 或者 callNativeWithPromise 接口 2. 封装调用接口 3. 导出模块 +注: callNative 代表前端调用客户端接口,无需返回 +callNativeWithPromise 代表前端调用客户端接口,需要返回,返回一个 Promise 对象 + +callNtive/callNativeWithPromise 参数含义: +moduleName: 代表和终端约定的模块名字,为 string 类型 +functionName: 代表和终端约定的模块函数名字,为 string 类型 +params: 实际携带参数, 为 Object 类型 + ```javascript // TestModule.js import { callNative, callNativeWithPromise } from "@hippy/react" diff --git a/docs/api/hippy-react/feedback.md b/docs/api/hippy-react/feedback.md new file mode 100644 index 00000000000..7e18764aa64 --- /dev/null +++ b/docs/api/hippy-react/feedback.md @@ -0,0 +1,18 @@ +# Hippy-React 常见反馈 + +## 1. 如何开始一个hippy react 项目 + +可以先参考我们的文档 和 demo + +https://hippyjs.org/#/hippy-react/introduction + +https://github.com/Tencent/Hippy/tree/master/examples/hippy-react-demo + +## 2. Hippy 是否支持 React 函数式写法 + +目前 Hippy 已适配 React 17,已支持函数式写法,未来会持续 React 18、9 + +## 3. Hippy-React支持class吗,就向下面这样传统react开发一样 + +Hippy-React 不支持 classname, 只能通过内联 Style + diff --git a/docs/api/hippy-react/modules.md b/docs/api/hippy-react/modules.md index e274261698d..d7a5e8de5a6 100644 --- a/docs/api/hippy-react/modules.md +++ b/docs/api/hippy-react/modules.md @@ -449,6 +449,10 @@ AsyncStorage 是一个简单的、异步的、持久化的 Key-Value 存储系 > - method:方法名称,如 ListView 的 `scrollToIndex` > - options: 需传递的数据,如 ListView 的 `[xIndex, yIndex, animated]`,空时显式写 `[]` +注: 也可以传入 callback 参数,这个是 Hippy 内部 API, 不推荐使用,源码可参考: + +[callUIFunction接口实现源码](https://github.com/Tencent/Hippy/blob/main/driver/js/packages/hippy-react/src/modules/ui-manager-module.ts) + ### UIManagerModule.getElementFromFiberRef 获取元素 Ref 对应的 Element(类似DOM)。`hippy-react-web` 不支持。 diff --git a/docs/api/hippy-vue/_sidebar.md b/docs/api/hippy-vue/_sidebar.md index e3f5b9ca36c..c25dfe608ae 100644 --- a/docs/api/hippy-vue/_sidebar.md +++ b/docs/api/hippy-vue/_sidebar.md @@ -8,6 +8,7 @@ * [手势系统](api/hippy-react/gesture.md) * [自定义组件和模块](api/hippy-react/customize.md) * [转 Web](api/hippy-react/web.md) + * [常见反馈](api/hippy-react/feedback.md) * hippy-vue * [介绍](api/hippy-vue/introduction.md) * [核心组件](api/hippy-vue/components.md) @@ -19,12 +20,14 @@ * [路由](api/hippy-vue/router.md) * [转 Web](api/hippy-vue/web.md) * [Vue 3.x](api/hippy-vue/vue3.md) + * [常见反馈](api/hippy-vue/feedback.md) * 样式 * [布局](api/style/layout.md) * [外观](api/style/appearance.md) * [颜色](api/style/color.md) * [变形](api/style/transform.md) * [更改终端属性](api/style/setNativeProps.md) + * [常见反馈](api/style/feedback.md) * [网络请求](api/network-request.md) * [性能监控](api/performance.md) * [定时器](api/timer.md) diff --git a/docs/api/hippy-vue/customize.md b/docs/api/hippy-vue/customize.md index a8e04624fcb..8ac9c16f575 100644 --- a/docs/api/hippy-vue/customize.md +++ b/docs/api/hippy-vue/customize.md @@ -124,10 +124,16 @@ component: { # 自定义模块 -> 该范例仅可以在 Android 下运行。 - hippy-vue 的模块其实只是一个 `Vue.Native.callNative` 调用,写个 `function` 即可。 +注: callNative 代表前端调用客户端接口,无需返回 +callNativeWithPromise 代表前端调用客户端接口,需要返回,返回一个 Promise 对象 + +callNtive/callNativeWithPromise 参数含义: +moduleName: 代表和终端约定的模块名字,为 string 类型 +functionName: 代表和终端约定的模块函数名字,为 string 类型 +params: 实际携带参数, 为 Object 类型 + ```js import Vue from 'vue'; diff --git a/docs/api/hippy-vue/feedback.md b/docs/api/hippy-vue/feedback.md new file mode 100644 index 00000000000..3cf187d0600 --- /dev/null +++ b/docs/api/hippy-vue/feedback.md @@ -0,0 +1,28 @@ +# Hippy-Vue 常见反馈 + +## 1. 如何开始一个hippy vue 项目 + +可以先参考我们的文档 和 demo + +https://hippyjs.org/#/hippy-vue/introduction +https://github.com/Tencent/Hippy/tree/master/examples/hippy-vue-demo + +## 2. Hippy Vue中span的换行符会被 trim + +3.x hippy-vue的版本,Hippy默认开启了 Vue.config.trimWhitespace 这个参数。而 hippy-vue 2.x的版本是不开的, 这个也是为了和未来 vue3 版本的规划对齐 +https://github.com/vuejs/core/pull/1600 + +方案建议: +a. 在 hippy.js 文件加一句 Vue.config.trimWhitespace = false,这样配置就和安卓版本完全对齐了。这个参数会对产物有一些影响,也可以让你们前端同事再重新评估一下。 + +b. 因为现在 hippy 没有提供换行组件 br标签 或者 white-space 的 css,如果需要换行,则不适用span,而是重新创建一个 text文本组件 + +## 3. hippy-vue-next-style-parser,这个包的作用 + +这个包用于处理 vue-next 的 css parse 和 match 逻辑 + +## 4. Hippy 是否支持 Vite 构建 + +已支持,目前只有腾讯内部版,腾讯业务可联系 TDF小助手 + + diff --git a/docs/api/hippy-vue/vue-native.md b/docs/api/hippy-vue/vue-native.md index 7403f72dba5..cffa04ab28d 100644 --- a/docs/api/hippy-vue/vue-native.md +++ b/docs/api/hippy-vue/vue-native.md @@ -194,6 +194,10 @@ Vue.Native.AsyncStorage.getItem('itemKey'); > * method:方法名称,如 ListView 的 `scrollToIndex` > * options: 需传递的数据,如 ListView 的 `[xIndex, yIndex, animated]` +注: 也可以传入 callback 参数,这个是 Hippy 内部 API, 不推荐使用,源码可参考: + +[callUIFunction接口实现源码](https://github.com/Tencent/Hippy/blob/main/driver/js/packages/hippy-vue/src/runtime/native.ts) + --- # Clipboard diff --git a/docs/api/hippy-vue/web.md b/docs/api/hippy-vue/web.md index 046700833aa..8f58ee928f6 100644 --- a/docs/api/hippy-vue/web.md +++ b/docs/api/hippy-vue/web.md @@ -2,4 +2,4 @@ ## WebRenderer 方案 -Hippy 全新 [`WebRenderer`](web/integration.md) 方案,增加基于公共通信协议的转换层,业务开发者可以使用同一套 Hippy 语法开发的业务代码,映射成 JS 实现的组件和模块,上层无论使用 React,Vue 或者其他第三方框架,都可以实现兼容,可参考。 +Hippy 全新 [`WebRenderer`](development/web-integration-guidelines.md) 方案,增加基于公共通信协议的转换层,业务开发者可以使用同一套 Hippy 语法开发的业务代码,映射成 JS 实现的组件和模块,上层无论使用 React,Vue 或者其他第三方框架,都可以实现兼容,可参考。 diff --git a/docs/api/performance.md b/docs/api/performance.md index 4a8c51a744a..60b72a92873 100755 --- a/docs/api/performance.md +++ b/docs/api/performance.md @@ -1,22 +1,759 @@ -# 性能监控 +# **Hippy 业务冷启动性能优化指引** -提供全局 `performance` 对象,用于获取性能数据。 +## **背景** ---- +经常有业务咨询 Hippy 有哪些优化手段,以及业务性能问题应该怎么分析,有哪些监控工具,本篇文档则系统的介绍了 Hippy 冷启动的性能优化的最佳实践。 -# memory -`performance.memory` 返回 js 引擎中内存的统计数据(仅 Android 支持,iOS 将返回 `undefined` )。 -> 最低支持版本 `2.15.0` -```javascript +## **冷启动阶段:** -global.performance.memory = undefined || { - jsHeapSizeLimit: 4096, // 堆内存大小限制 - totalJSHeapSize: 2048, // 可使用的堆内存 - usedJSHeapSize: 1024, // 已使用的堆内存 - jsNumberOfNativeContexts: 1, // 当前活动的顶层上下文的数量(随着时间的推移,此数字的增加表示内存泄漏) - jsNumberOfDetachedContexts: 0, // 已分离但尚未回收垃圾的上下文数(该数字不为零表示潜在的内存泄漏) +介绍一下Hippy应用冷启动有哪些阶段 + +​ 1. Hippy 运行环境启动 - 终端耗时 (启动) + +​ 2. 加载 Bundle的 JS 文件 - JS 引擎耗时 (自执行) + +​ 3. 应用实例的执行 - JS 引擎耗时(JS运行) + +​ a. 业务代码逻辑执行 + +​ b. 业务 IO(网络、JS API)等待 + +​ c. React/Vue 框架 DIFF 耗时 + +​ d. Hippy JS SDK计算耗时 + +​ 4. 上屏显示 - 终端耗时 (渲染) + +​ a. Hippy DOM 构建、排版耗时 + +​ b. Hippy 渲染上屏耗时 + +详细介绍参考:[Hippy冷启动核心逻辑和数据梳理](https://doc.weixin.qq.com/doc/w3_AJcAmQbdAFwmCbIe8OPScGUN6amkw?scode=AJEAIQdfAAo1QKXNGAAJcAmQbdAFw) + +我们把启动阶段分为 4个阶段:Hippy 启动、Bundle加载、**应用实例执行**、渲染上屏。 + +不同规模的 Hippy 业务,这些阶段耗时不尽相同,大家可以先测试各阶段耗时占比,再针对性的来分析。 + + + +Hippy 团队过去有一些经验可供参考: + +​ 1. 一般耗时大头是阶段 3 (一半耗时占比超过 50%) + +业务可重点排查 **业务 JS 执行耗时**、**IO(网络、JS API)等待耗时。**此外,**节点数过多、CSS 属性比较复杂**,也会影响 Hippy SDK的计算耗时 + +​ 2. JS Bundle包过大,会影响阶段 2 的耗时 + +​ 3. 节点数过多,节点层级比较深,渲染样式比较复杂,会影响阶段 3 的耗时 + + + +## **如何监控定位:** + +### **1.** **线上监控:** + +​在 Hippy 3.0,我们设计了用于性能分析的 Performance API: + +[Hippy 性能监控设计文档](https://doc.weixin.qq.com/doc/w3_ANsAsgZ1ACcBlbHY905RpW7Qj1vij?scode=AJEAIQdfAAosjxQAlNANsAsgZ1ACc) + + + +Performance API 冷启动打点指标: + +| **指标** | **对应 Key** | +| -------------------- | ------------------------ | +| Hippy 引擎加载开始 | hippyNativeInitStart | +| JS 引擎加载开始 | hippyJsEngineInitStart | +| JS 引擎加载结束 | hippyJsEngineInitEnd | +| Hippy 引擎加载结束 | hippyNativeInitEnd | +| JS Bundle 自执行耗时 | bundleInfo[] | +| 业务入口执行开始 | hippyRunApplicationStart | +| 业务入口执行结束 | hippyRunApplicationEnd | +| 首帧绘制开始 | hippyFirstFrameStart | +| 首帧绘制结束 | hippyFirstFrameEnd | +| 启动耗时 | duration | + + + +监控方式: + +​ 1. Hippy 3.x版本:可以接入最新 aegis-sdk (咨询 TDF小助手),已经基于 performance api,可以直接获取打点数据 + + + +​ 2. Hippy 2.x 版本可以基于业务代码打点,获取启动阶段的近似耗时数据。可参考:https://km.woa.com/articles/show/557810?kmref=search&from_page=1&no=1 + + + +### **2.** **Profile 工具:** + +​ 1. Perfdog + +​ a. 可查看 FPS, CPU, GPU, 内存等变化情况 + +​ 2. 安卓系统自带工具: + +​ a. GPU 渲染模式分析: 通过在 Android 设备的设置 APP 的开发者选项里打开 “ GPU 渲染模式分析” 选项,选择 ” 在屏幕上显示为条形图 “ 。 + +​ b. 过度绘制:Android 设备的设置 APP 的开发者选项里打开 “ 调试 GPU 过度绘制 ” + +​ c. 查看界面边界:系统设置 – 开发者选项 – 绘图 --显示布局边界 + +​ 3. iOS系统 simulator 模拟器 + +​ a. Debug 下自带分析工具 Color Blended Layers 图层绘制 Color Off-screen Rendered 离屏渲染 + +​ 4. Profile工具 + +​ a. Android Studio Profiler + +​ b. Xcode Instruments + +​ **c.** **Hippy Devtools (也在进一步完善中,欢迎大家提需求),如下示例:** + + + +**如何优化:** + +定位到耗时点,接下来就可以针对性分析。 + +先简单介绍常用的优化: + +​ 1. 预加载:大幅降低 1-2 阶段耗时 + +​ 2. 预渲染/SSR/Native-Vue:大幅降低 1-3阶段耗时 + +​ 3. 数据预拉取:降低 3阶段 IO 等待耗时 + +​ 4. JSI、动态加载、节点数优化:降低 3 阶段耗时 + +​ 5. 节点缓存/渲染优化/图片缓存:降低 4 阶段耗时 + +​ 6. 骨架屏优化/Loading:优化交互体验 + +... + + + +接下来详细介绍这些优化点: + + + +### **1.** **预加载** + +通过提前执行1+2阶段逻辑优化首屏耗时。 + +这两个阶段耗时主要被封装在HippyBridge中,因此可以通过提前初始化HippyBridge达成目的。 + + + +iOS 代码示例: + +``` javascript +HippyBridge *bridge = [[HippyBridge alloc] initWithDelegate:nil bundleURL:url moduleProvider:^NSArray> * { + return nil; // 或返回希望替换的module实例 +} launchOptions:option executorKey:nil]; + +// 将bridge保存起来 +``` + +安卓代码示例: + +``` javascript +mHippyEngine.initEngine(new HippyEngine.EngineListener() { + @Override + public void onInitialized(EngineInitStatus statusCode, String msg) { + if (statusCode == EngineInitStatus.STATUS_OK) { + HippyBundleLoader loader = ...; + // e.g.: + // new HippyAssetBundleLoader(context, assetName, true, "demo"); + // new HippyFileBundleLoader(filePath, true, "demo"); + mHippyEngine.preloadModule(loader); + } + } } +``` + + +优点: + +​ 1. 不依赖页面数据,在任何页面都可考虑使用预加载 + +​ 2. 前端也可以在预加载时提前fetch数据 + +缺点: + +​ 1. 优化效果相对预渲染不够明显 + + + +### **2.** **预渲染** + +如果还希望在预加载基础上继续优化体验,还可以进一步提前执行步骤 3 的逻辑。 + +优点: + +​ 1. 优化效果十分明显 + +缺点: + +​ 1. 内存开销大 + +​ 2. 无法对动态数据的页面使用 + +​ 3. 页面发版会导致命中率降低 + +​ 4. 预渲染时的Dimension可能与访问时不一致,导致布局异常 +​ 5. 在Android上预渲染只能使用AppContext,导致页面打开后也无法使用依赖Activity的能力,例如Modal(Dialog)组件 + + + +接入代码示例: + +iOS 代码示例 + + + +``` javascript +HippyRootView *hippyRootView = [[HippyRootView alloc] + initWithBridge:bridge + businessURL:businessURL + moduleName:appName + initialProperties:properties + delegate:delegate]; +// 将hippyRootView保存起来 ``` + + + + + +执行这一步后,HippyRootView内部将会执行实例的加载,但由于rootView未被真正挂在到VC的UI树上,所以暂时不可见。 + +当需要显示的时候可以在VC的view上将hippyRootView加为子view。 + + + +``` javascript +[parent addSubview:hippyRootView]; + +// 必要时可以更新一下frame +hippyRootView.frame = newFrame; + +// 如果在addSubview后还有其他的subview的添加,可以考虑通过bringSubviewToFront将hippyRootView改为最前方显示 +[parent bringSubviewToFront:hippyRootView]; +``` + + + + + + + +安卓代码示例: + +除了需要把 ModuleLoadParams.context 设置为 AppContext 外,其余步骤和常规加载一致。 + + + +``` javascript +HippyEngine.ModuleLoadParams loadParams = new HippyEngine.ModuleLoadParams(); +loadParams.context = getApplicationContext(); +... +mHippyView = mHippyEngine.loadModule(loadParams, listener, null); +``` + + + + + +### **3.** **SSR** + +SSR 代替预渲染方案的另一选择。 + +方案原理:把 1-3 阶段放在服务端执行,解析成最终的 Hippy指令 的字符串,启动时直接反序列化 Hippy指令,下发Hippy终端执行渲染。 + +优化效果:性能数据与预渲染接近 + +详见QQ游戏中心优化 https://km.woa.com/articles/show/564026?kmref=search&from_page=1&no=1 + + + +优点: + +​ 1. 可不依赖终端方案方案,前端执行 + +​ 2. 相比预渲染方案更节省内存 + +缺点: + +​ 1. 需要执行事件挂载逻辑,可交互时间会延迟 + +​ 2. 会带来服务器的运营成本 + + +### **4.** **数据预请求:** + +在不方便应用 预渲染/SSR/Native-Vue的场景。可以考虑提前下载数据,节省 3阶段 网络 IO 耗时: + +​ 1. 可以在终端预请求,在启动Hippy后,把数据传给前端 + +​ 2. 可以结合预加载,在前端 JS 自执行阶段,前端预请求数据。等待组件渲染时直接使用。 + + + +### **5.** **节点缓存** + +​ 1. Dom Node 缓存(安卓) + +接入方案详见:https://doc.openhippy.com/#/feature/feature2.0/dom-cache + +​ 2. RenderNode 缓存(3.0 安卓) + +接入方案详见:https://doc.openhippy.com/#/feature/feature3.0/render-node-snapshot + + + + + +### **6.** **JS 引擎优化** + +在不方便做 JS 预加载的场景,如果要优化 JS 自执行耗时,可以考虑对 JS 引擎本身做优化: + +#### **6.1.** **V8 编译开启 Code Cache** + +把编译和解析的结果缓存下来,等到下次遇到相同的文件,直接跳过这个过程,把直接缓存好的数据拿来使用; + +​Hippy 2.0: Hermes 接入指引文档:https://iwiki.woa.com/p/4007348225 + +​Hippy 3.0 Hermes会直接集成,文档待补充。 + + + + + +### **7.** **bundle 包动态加载** + +接入文档指引:https://iwiki.woa.com/p/491739348 + +Hippy 打包插件只支持一个jsbundle包的生成。随着业务逻辑越来越复杂,jsbundle越来越大、包的加载时间越来越长。为了解决这个问题,Hippy 在 2.2.0 版本增添了动态加载能力,Hippy 的开发人员可以按照业务需求来动态引入 JS。 + +Hippy 在 2.5.5 版本增加了远程网络加载模式的支持,业务可对每个bundle自定义不同的加载模式。 + + + +webpack打包脚本中引入插件:HippyDynamicImportPlugin + + + +``` javascript +const HippyDynamicImportPlugin = require('@hippy/hippy-dynamic-import-plugin'); + +module.exports = { + ... + plugins: [ + new HippyDynamicImportPlugin(), + ], +}; +``` + + + + + + + +​ (1)加载本地 JS 包: + +​ 与 Web 开发动态加载能力一样,直接使用 import() 语法即可 + + + +​ (2)加载远程 JS 包: + + i. webpack打包脚本配置全局 publicPath(可选) + + + +``` javascript + // webpack output 配置 + output: { + ... + publicPath: 'https://xxxx/hippy/hippyVueDemo/', +}, +``` + + + + + +ii. 在业务代码引用分包的入口配置 magic comment的 webpackChunkName(必须) 和 customChunkPath(可选),如果没有配置customChunkPath,会默认使用全局 publicPath; 以 Hippy-Vue 为例: + + + +``` javascript + // Hippy-Vue 配置 + AsyncComponentFromHttp: () => import(/* customChunkPath: "https://xxx/hippy/hippyVueDemo/", webpackChunkName: "asyncComponentFromHttp" */'./dynamicImport/async-component-http.vue') + .then(res => res) + .catch(err => console.error('import async remote component error', err)) +``` + + + + + + + + + +### **8.** **JS API 优化** + +#### **8.1.** **JS Bridge -> JSI** + +​接入方案详见:https://doc.openhippy.com/#/feature/feature2.0/jsi + +​优化效果: + +Android 代码示例: + + + +``` javascript +// 初始化引擎开启 enableTurbo +val initParams = HippyEngine.EngineInitParams() +initParams.enableTurbo = true + +// 定义 module +@HippyNativeModule(name = "demoTurbo") +class DemoTurboModule(context: HippyEngineContext?) : HippyNativeModuleBase(context) { + ... + @HippyMethod(isSync = true) + fun getNum(num: Double): Double = num + ... +} +``` + + + + + +​iOS 代码示例: + + + +``` javascript +// 方式一:bridge初始化时通过配置参数设置生效 +NSDictionary *launchOptions = @{@"EnableTurbo": @(DEMO_ENABLE_TURBO)}; +HippyBridge *bridge = [[HippyBridge alloc] initWithDelegate:self + bundleURL:[NSURL fileURLWithPath:commonBundlePath] + moduleProvider:nil + launchOptions:launchOptions + executorKey:@"demoTurbo"]; + +// 方式二:bridge初始化完成后,设置属性生效 +HippyRootView *rootView = [[HippyRootView alloc] initWithBridge:nil + businessURL:nil + moduleName:@"demoTurbo" + initialProperties:@{@"isSimulator": @(isSimulator)} + launchOptions:nil + shareOptions:nil + debugMode:YES + delegate:nil]; +rootView.bridge.enableTurbo = YES; +``` + + + + + + + +``` javascript +@implementation TurboConfig + +... + +// 注册模块 +HIPPY_EXPORT_TURBO_MODULE(TurboConfig) + +// 注册交互函数 +HIPPY_EXPORT_TURBO_METHOD(getInfo) { + return self.strInfo; +} +HIPPY_EXPORT_TURBO_METHOD(setInfo:(NSString *)string) { + self.strInfo = string; + return @(YES); +} + +... + +@end +``` + + + + + + + +Hippy-React 代码示例: + +https://github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/src/externals/Turbo/demoTurbo.js + +Hippy-Vue 代码示例: + +https://github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/src/components/demos/demoTurbo.js + + + +#### **8.2.** **减少首屏 JS API 调用次数** + + + +### **9.** **Hippy-Vue 优化** + +​ 1. 减少 getElemCss 方法的调用 + + + +``` javascript +Vue.Native.getElemCss() +``` + + + + + +​ 2. 减少 scoped 的使用 + +vue scoped 能力是 2.15.0 版本引入,scoped会转换为 属性选择器,因此解析性能会比较差; + +在 Hippy 3.0 版本,我们使用 css-module的方案优化了 scoped的解析方式,性能得到提升。 + +​ 3. 减少 CSS 属性选择器、伪类等样式的使用 + +​ 4. 升级 Hippy-Vue-Next(Vue3) + +Vue3 升级指引:https://hippyjs.org/#/hippy-vue/vue3 + +Vue3 相比 Vue2 做了 Diff算法优化、静态提升、事件缓存等优化,从Vue框架层面会带来性能提升。实测了 Vue3 和 Vue2 在Hippy框架下的数据对比: + + + +### **10. Hippy-React 优化** + +​ 1. Hippy React节点更新优化: + +https://iwiki.woa.com/p/1335183393 + +@hippy/react 在 2.12.0 版本应用上了最新的渲染优化,针对 react 16 和 react 17,先删除原来的 react-reconciler 包依赖,再分别引入 + + + +``` javascript +"@hippy/react-reconciler": "react16" +"@hippy/react-reconciler": "react17" +``` + + + + + +​ + +### **11.** **渲染优化:** + +#### 1. 减少首屏节点数、节点层级 + +- 可以借助客户端 IDE 来直观地查看 "DOM" 树,使用前端的 DevTools 的 View 树来检查冗余节点。 + +#### 2. 减少节点重复渲染的次数 + +- 可以在高频渲染节点的 `render` 函数中打点统计。 +- 使用 `shouldComponentUpdate`、`PureComponent` 等优化重复渲染。 + +#### 3. 节点优化:节点合并,扁平化(触发 Hippy 引擎优化) + +- 减少冗余事件挂载。 + +#### 4. 圆角、裁剪、描边等渲染性能较差,尽量减少使用 + +#### 5. 减少过度绘制 + +- 移除重复的背景色。 +- 减少图层覆盖。 + +#### 6. ListView + +- 尽量使用 `ListView` 代替 `ScrollView`,`ListView` 通过 View 的缓存与重用大大提升渲染性能。 +- 使用 `getRowType`,将 item 按类型合理拆分,同一类型的 item 的 `RowType` 相同,可复用。 +- 严格保持 `ListView` item 的 DOM 结构一致: + - **hippy-vue**:item 中的节点可以用 `v-show`,不要用 `v-if`。 + - **hippy-react**:item 中的节点尽量不要用 `if` 条件来改变节点结构。 + +#### 7. ViewPager + +- `ViewPager` 的子节点尽量不要全加载,实现懒加载。 + +#### 8. Image + +- 图片压缩。 +- 图片按需加载。 +- 避免同时使用 `src` 和 `background`。 +- 大图放 CDN。 +- 减少 base64 图片使用。 +- 图片缓存(内存缓存、磁盘缓存)。 + +​ 代码示例:在自定义ImageLoader中实现自己的缓存逻辑,也可使用第三方图片加载库,如 slide 等。 + + + +``` javascript +HippyEngine.EngineInitParams initParams = new HippyEngine.EngineInitParams(); +// 必须:宿主(Hippy的使用者)的Context +// 若存在多个Activity加载多个业务jsbundle的情况,则这里初始化引擎时建议使用Application的Context +initParams.context = this; +... +// 必须:图片加载器 +initParams.imageLoader = new MyImageLoader(this.getApplicationContext()); +``` + + + + + + + +### **12.** **业务逻辑执行优化** + +此外,也要检查业务代码自身的耗时,并做针对性优化。 + +​ 1. 防抖节流:对滚动事件、数据上报等进行防抖节流,避免频繁触发计算 + +​ 2. 耗时逻辑检查是否可以放在首屏后执行 + + + +### **13.** **交互优化** + +除了上面的优化手段,交互优化在一些场景也是十分重要的,可以提升打开体验,让页面视觉上更流畅。 + +​ 1. 骨架屏优化 + +​ 2. Loading + +​ 3. 切换动画 + + + +## **总结:** + +优化总结、是否需要 终端/前端 同学支持。 + +| 优化方案 | 方案介绍 | 接入成本 | 优化效果 | 终端/前端工作 | +| -------------------- | ------------------------------ | -------- | ---------- | -------------- | +| 预加载 | 优化 JS Bundle包加载 | 中 | 中 | 终端工作 | +| 预渲染 | 基于预加载,进一步优化渲染耗时 | 中 | 好 | 终端工作 | +| SSR | 预渲染的替代方案 | 中 | 好 | 前端工作 | +| Native-Vue | 预渲染的另一种替代方案 | 高 | 好 | 前端工作 | +| 数据预请求 | 节省 IO 耗时 | 低 | 中 | 终端或前端工作 | +| 节点缓存 | 仅安卓支持,优化渲染耗时明显 | 低 | 中 | 终端工作 | +| JS引擎优化(Hermes) | 性能比JSC优化明显 | 高 | 好 | 终端工作 | +| Bundle动态加载 | 分包加载,节省 JS 执行耗时 | 中 | 中 | 前端工作 | +| JS API优化(JSI) | JSI 接口同步调用,等待耗时降低 | 低 | 中 | 前端工作 | +| Hippy-Vue 逻辑优化 | 优化 css 解析耗时 | 低 | 好 | 前端工作 | +| Hippy-React 逻辑优化 | 渲染队列优化 | 低 | 中 | 前端工作 | +| 渲染优化 | 组件使用的渲染耗时优化 | 低 | 中 | 前端工作 | +| 业务逻辑优化 | 业务自身逻辑优化 | 无 | 中 | 前端工作 | +| 交互优化 | 业务自身优化交互 | 无 | 体验上优化 | 前端工作 | + + + +## **参考资料:** + +​ 1. K歌 Hippy性能优化分享(一) + +https://km.woa.com/articles/show/511822?kmref=search&from_page=1&no=7 + +​ 2. k歌 Hippy性能优化分享(二) + +https://km.woa.com/articles/show/484172?kmref=search&from_page=1&no=5 + +​ 3. k歌 Hippy性能优化分享 (三) + +https://km.woa.com/articles/show/504866?kmref=search&from_page=1&no=3 + +​ 4. k歌渲染优化 + +https://km.woa.com/articles/show/465625?kmref=search&from_page=1&no=2 + +​ 5. 小说 Hippy性能优化 + +https://km.woa.com/articles/show/484172?kmref=search&from_page=1&no=5 + +​ 6. 浏览器小说阅读器内存优化 + +https://km.woa.com/articles/show/468088?kmref=search&from_page=1&no=6 + +​ 7. QQ 增值Hippy性能优化 + +https://km.woa.com/articles/show/516658?kmref=search&from_page=1&no=4 + +​ 8. QQ直播Hippy性能优化 + +https://km.woa.com/articles/show/557810?kmref=search&from_page=1&no=1 + +​ 9. QQ游戏中心Hippy SSR优化 + +https://km.woa.com/articles/show/564026?kmref=search&from_page=1&no=1 + +​ 10. QQ 音乐Hippy性能监控工具建设 + +https://km.woa.com/articles/show/494153?kmref=search&from_page=1&no=6 + +​ 11. 浏览器 Hermes 引擎优化性能 + +https://km.woa.com/articles/show/567715?kmref=search&from_page=1&no=4 + +​ 12. QB长视频业务优化-接入Hermes引擎 + +https://km.woa.com/articles/show/564575?kmref=search&from_page=1&no=7 + +​ 13. Hippy 内存、CPU性能优化 + +https://km.woa.com/articles/show/484158?kmref=search&from_page=1&no=8 + +​ 14. 闪现社区首屏优化 + +https://km.woa.com/articles/show/474636?kmref=search&from_page=1&no=9 + +​ 15. NativeVue:解决Hippy等类RN框架首屏白屏的极致方案 + +https://km.woa.com/articles/show/527262?kmref=search&from_page=1&no=10 + +​ 16. Hippy profile工具实现的思考 + +https://km.woa.com/articles/show/397231?kmref=search&from_page=1&no=6 + +https://km.woa.com/articles/show/445938 + +​ 17. 记一次Hippy-React优化 + +https://km.woa.com/articles/show/431695?kmref=search&from_page=1&no=9 + +​ 18. Flutter性能优化最佳实践 + +[Flutter 应用性能优化最佳实践 - Flutter 中文文档 - Flutter 中文开发者网站 - Flutter](https://flutter.cn/docs/perf/best-practices) + +​ 19. React Native 性能综述 + +[性能综述 · React Native 中文网](https://reactnative.cn/docs/performance) + +​ 20. 营地性能优化 + +https://km.woa.com/articles/show/599930?kmref=search&from_page=1&no=10 + + diff --git a/docs/api/style/_sidebar.md b/docs/api/style/_sidebar.md index 31e08a29e76..dda9aa7c24b 100644 --- a/docs/api/style/_sidebar.md +++ b/docs/api/style/_sidebar.md @@ -9,6 +9,7 @@ * [手势系统](api/hippy-react/gesture.md) * [自定义组件和模块](api/hippy-react/customize.md) * [转 Web](api/hippy-react/web.md) + * [常见反馈](api/hippy-react/feedback.md) * hippy-vue * [介绍](api/hippy-vue/introduction.md) * [核心组件](api/hippy-vue/components.md) @@ -20,12 +21,14 @@ * [路由](api/hippy-vue/router.md) * [转 Web](api/hippy-vue/web.md) * [Vue 3.x](api/hippy-vue/vue3.md) + * [常见反馈](api/hippy-vue/feedback.md) * 样式 * [布局](api/style/layout.md) * [外观](api/style/appearance.md) * [颜色](api/style/color.md) * [变形](api/style/transform.md) * [更改终端属性](api/style/setNativeProps.md) + * [常见反馈](api/style/feedback.md) * [网络请求](api/network-request.md) * [性能监控](api/performance.md) * [定时器](api/timer.md) diff --git a/docs/api/style/feedback.md b/docs/api/style/feedback.md new file mode 100644 index 00000000000..e8b37e03db5 --- /dev/null +++ b/docs/api/style/feedback.md @@ -0,0 +1,22 @@ +# CSS 样式常见反馈 + +## 1. Hippy 设置百分比失效 + +Hippy 自研了排版引擎 [Taitank](https://github.com/Tencent/taitank), 为了追求极致的性能, 阉割了百分比的实现。 +常见场景实现方案参考: + +> 需要设置高度 100% + +可设置 flex: 1 + +> 需要设置宽度 50% + +可通过 Dimensions.screen 接口获取屏幕尺寸大小,然后计算相应百分比值 + +> 需要百分比实现 + +可以终端修改编译设置,把排版引擎切换为 [Yoga](https://doc.openhippy.com/#/feature/feature3.0/layout) + +## 2. hippy支持 css var 的写法吗 + +可以先用 postcss 相关的插件来支持 diff --git a/docs/development/native-component.md b/docs/development/native-component.md index 2bbf6c68c64..3d242874b6c 100644 --- a/docs/development/native-component.md +++ b/docs/development/native-component.md @@ -632,14 +632,14 @@ Widget build(BuildContext context) { 扩展组件主要包括: -1. 扩展 `HippyView` +1. 扩展 `HippyWebView` 2. 实现构造方法 3. 实现设置自定义组件的 `tagName` 4. 实现构造自定义组件的 `dom` 5. 实现自定义组件的 `API 能力` 6. 实现自定义组件的属性 -其中 `HippyView` 类,实现了一些 HippyBaseView 的接口和属性定义,在一个自定义组件中有几个比较重要的属性: +其中 `HippyWebView` 类,实现了一些 HippyBaseView 的接口和属性定义,在一个自定义组件中有几个比较重要的属性: - id: 每一个实例化 component 的唯一标识,默认会赋值给组件 dom 的 id 属性 - pId: 每一个实例化 component 的父组件标识 @@ -647,6 +647,16 @@ Widget build(BuildContext context) { - dom: 真正挂载到document上的节点 - props: 承载了从业务侧传递过来的属性和style的记录 +注: tagName 用来和 React/Vue 注册的自定义组件的 nativeName 关联,可参考: + +### 如果您使用的是`hippy-vue` + +可以参考 [hippy-vue/customize](api/hippy-vue/customize) + +### 如果您是用的是`hippy-react` + +可以参考 [hippy-react/customize](api/hippy-react/customize) + ### 例子 下面这个例子中,我们创建了 `CustomView` 的自定义组件,用来显示一个视频 @@ -655,10 +665,10 @@ Widget build(BuildContext context) { ```javascript -import { HippyView, HippyWebEngine, HippyWebModule } from '@hippy/web-renderer'; +import { HippyWebView, HippyWebEngine, HippyWebModule } from '@hippy/web-renderer'; -// 继承自 `HippyView` -class CustomView extends HippyView { +// 继承自 `HippyWebView` +class CustomView extends HippyWebView { // 实现构造方法 constructor(context, id, pId) { super(context, id, pId); @@ -682,9 +692,9 @@ class CustomView extends HippyView { ```javascript -import { HippyView, HippyWebEngine, HippyWebModule } from '@hippy/web-renderer'; +import { HippyWebView, HippyWebEngine, HippyWebModule } from '@hippy/web-renderer'; -class CustomView extends HippyView { +class CustomView extends HippyWebView { set src(value) { this.dom.src = value; @@ -735,7 +745,7 @@ Node.removeChild(child: T): T; - 如果组件不希望以这种默认的形式来实现,可以自行通过 `insertChild` 和 `removeChild` 方法管理节点的插入和移除逻辑。 ```javascript -class CustomView extends HippyView{ +class CustomView extends HippyWebView{ insertChild (child: HippyBaseView, childPosition: number) { // ... } @@ -750,7 +760,7 @@ class CustomView extends HippyView{ > 例子中,`data` 是组件本次更新的 `props` 数据信息,`defaultProcess()` 是 `HippyWebRenderer` 默认处理 `props` 更新的方法,开发者可以在这里拦截修改更新的数据后,依然使用默认的 `props` 进行更新,也可以不用默认的方法自行进行属性更新的遍历操作。 ```javascript -class CustomView extends HippyView{ +class CustomView extends HippyWebView{ updateProps (data: UIProps, defaultProcess: (component: HippyBaseView, data: UIProps) => void) { // ... diff --git a/docs/development/report.md b/docs/development/report.md index c5262bf1a20..2adda06e1ed 100644 --- a/docs/development/report.md +++ b/docs/development/report.md @@ -13,6 +13,7 @@ hippy本质上使用的还是客户端原生组件 以及一部分自绘组件 ## 接入指引 [Hippy Android 曝光上报指引](https://iwiki.woa.com/p/956352478) + [Hippy iOS 曝光上报指引](https://iwiki.woa.com/p/589637144) 有疑问可以咨询企业微信 TDF小助手