调试
Hippy 调试原理
Hippy 是直接运行于手机的 JS 引擎中的,在 Android 上使用 WebSocket 通过 Chrome DevTools Protocol 与电脑上的 Chrome 进行通讯调试,而 iOS 上使用内置 的 JavaScriptCore 与 Safari 连接进行调试。
Hippy中运行的JS代码可以来源于本地文件(local file),或者远程服务地址(server)。
hippy-debug-server 就是为了解决调试模式下终端模式获取调试用 JS 文件,以及将 Chrome DevTools Protocol 传输回调试器而诞生。
项目初始化
运行
git clone https://github.com/Tencent/Hippy.git
!> Hippy 仓库使用 git-lfs 来管理 so,gz,otf,png,jpg 文件, 请确保你已经安装 git-lfs。
项目根目录运行命令
npm install
安装前端依赖。- 项目根目录运行命令
lerna bootstrap
安装前端每一个 package 依赖。(Hippy 采用 Lerna 管理多JS仓库,如果出现lerna command is not found
, 先执行npm install lerna -g
) - 项目根目录运行命令
npm run build
编译前端 SDK 包。 - 选择一个前端范例项目来进行编译,项目根目录运行
npm run buildexample -- [hippy-react-demo|hippy-vue-demo]
。
终端环境准备
我们推荐在终端代码中留一个后门,通过一定条件触发后进入调试模式,具体代码可以参考 iOS 和 Android,这里实现了一个 TestModule
,当前端调用它的 debug
方法时就会进入调试模式,而终端可以通过其它方式进入。
调试 Javascript
尽管 Hippy 是前端框架,但依然运行在终端中,如果终端提供了后门可以直接链接调试服务,那可以直接用终端后门连接终端进行调试。
这里仅以官方范例为准,讲述如何进行调试。
!> 需要注意的是:官方范例为测试最新功能,将 @hippy/react
和 @hippy/vue
做了个 alias 到 packages 目录,如果调试官方范例,需要先在 Hippy 项目根目录下使用 npm run build
编译前端 SDK;或者删除范例的 scripts
目录中对 packages 的 alias,Hippy-Vue 范例则需要将 vue
和 vue-router
分别映射到 @hippy/vue
和 @hippy/vue-router
iOS
因为 Hippy 需要经过网络传输调试协议,我们建议使用 iOS 模拟器进行调试,真机上虽然也可以但会要求手机和开发机在同一个网络内,并且需要在手机中配置连接获取开发机上的调试服务。
同时,本方法也可以用 Safari 进行内置包(不连接开发机上的调试 JS 包)的调试。
具体流程:
- 点击 Xcode on Mac AppStore 下载安装 Xcode。
- 使用 Xcode 打开Hippy iOS 范例工程 中的
HippyDemo.xcodeproj
工程文件,并点击运行,正常情况下应该可以启动模拟器,并运行之前内置的 Hippy 前端代码。 - 打开
examples
下的前端范例工程 hippy-react-demo 或者 hippy-vue-demo,通过npm i
安装完依赖之后,使用npm run hippy:dev
启动编译,并另开一个终端窗口,运行npm run hippy:debug
启动调试服务。 回到模拟器,点击前端工程中的调试按钮,即可进入调试状态。hippy-react 有一个单独的页面,hippy-vue 在右上角。以 hippy-react 为例:
打开 Safari,首先确保
预置
->高级
->显示开发菜单
正常勾上。然后按图打开 Safari 调试器即可开始调试工作。
当 JS 文件发生改动时,自动编译会执行,但是终端却无法获知 JS 文件已经发生改变,需要通过按
Command + R
刷新 或者Command + D
键调起 Reload 面板刷新
如果
Command + D
无法调起面板,可以点击Device
->Shake
强制调起 Reload 面板
远程调试
默认情况下,iOS使用本地服务地址进行代码调试。Hippy客户端从服务器地址获取JS代码并运行Hippy业务。但是用户可能遇到真机调试的问题,这就需要真机连接远程地址。
在TestModuel.m
文件中,打开REMOTEDEBUG
宏,并填入Hippy服务地址与业务名称,即可实现远程调试。
Android
Android 使用了 adb 的端口映射功能,解决了真机到开发机通讯问题,反而因为 ARM 模拟器运行效率问题,更加推荐使用真机进行调试。
具体流程:
- 下载安装 Android Studio。
- 通过 Android Studio 打开Hippy Android 范例工程,当提示 ToolChain 需要更新时全部选择拒绝,安装好 SDK、NDK、和 cmake 3.6.4。
- 通过数据线插上 Android 手机,并在 Android Studio 中点击运行,正常情况下手机应该已经运行起
Hippy Demo
app。编译如果出现问题请参考 #39。 - 回到手机上,首先确保手机的
USB 调试模式
已经打开 — 一般在关于手机页面里连续点击Build
可以进入开发者模式
,再进入开发者模式
界面后打开USB 调试模式
。 - 执行
adb reverse --remove-all && adb reverse tcp:38989 tcp:38989
确保 38389 端口不被占用。 - 打开前端范例工程 hippy-react-demo 或者 hippy-vue-demo,通过
npm i
安装完依赖之后,使用npm run hippy:dev
启动编译,并另开一个终端窗口,运行npm run hippy:debug
启动调试服务。 回到手机上,点击前端工程中的调试按钮,即可进入调试状态。hippy-react 有一个单独的页面,hippy-vue 在右上角。以 hippy-react 为例:
然后打开 Chrome,输入
chrome://inspect
,首先确保Discover USB devices
的复选框呈未选中状态,然后确保Discover network targets
选中,并在右侧Configure
按钮的弹窗中包含了localhost:38989
调试服务地址,下方的Remote Target
中应该会出现Hippy debug tools for V8
字样,点击下方的inspect
链接即可打开 Chrome 调试器。当 JS 文件发生改动时,自动编译会执行,但是终端却无法获知 JS 文件已经发生改变,点击界面上的
小圆点
,选择弹出菜单中的Reload
重新加载 JS 代码。
Elements 可视化审查
Hippy 实现了节点和属性从前端到终端的映射,可以在 Chrome Inspector 上进行 Elements 的可视化检查。
Android Chrome 调试
Android SDK 最低支持版本 2.9.0
Android 上我们直接使用 Chrome Inspector 调试即可看到 Elements。
iOS Chrome 调试
iOS SDK 最低支持版本 2.11.5
为实现 iOS Element 调试能力,我们也使用 Chrome Inspector 替代 Safari 进行 Elements 的可视化检查,并使用新的 hippy-debug-server 与 iOS 设备建立连接和协议适配。
npm i -D @hippy/debug-server-next@latest
!> @hippy/debug-server-next
包含 @hippy/debug-server
的所有能力,是面向 Hippy 3.0 的调试工具,目前暂时作为 Hippy 2.0 的 iOS 协议适配增强工具。若想使用 HMR 能力仍需跟随 Hippy 2.12.0 版本。
框架日志输出
无论是 hippy-react 还是 hippy-vue 都将和终端通讯的信息进行输出,包含了前终端的节点操作、事件收发。这些日志对于业务调试其实很有帮助,可以让开发了解到前端框架是如何将代码转译成终端可以理解的语法,当遇到问题时应先检查框架通信日志,基本可以定位到大部分问题。
如果需要关闭日志,可以在 hippy-react 的 new Hippy 启动参数中增加 silent: true
,或者 hippy-vue 项目的入口文件中,开启 Vue.config.silent = true;
。
HMR & Live-Reload 能力
最低支持版本 2.12.0
当开发者修改了前端代码后,我们可以通过 Hot Module Replacement (HMR)
保留状态刷新组件视图,或通过 live-reload
重载业务实例,步骤如下:
Hippy-Vue
安装热更新依赖
npm i @hippy/vue@^2.12.0
npm i -D @hippy/debug-server@^2.12.0 @hippy/hippy-hmr-plugin @hippy/vue-loader @hippy/vue-css-loader
webpack 配置示例
const HippyHMRPlugin = require('@hippy/hippy-hmr-plugin');
const VueLoaderPlugin = require('@hippy/vue-loader/lib/plugin');
const vueLoader = '@hippy/vue-loader';
module.exports = {
devServer: {
// 默认 HMR 端口为38988
host: 38988,
// 默认 hot, liveReload 都为 true,如果只想使用 live-reload 功能,请将 hot 设为 false,liveReload 设为 true
hot: true,
liveReload: true,
devMiddleware: {
writeToDisk: true,
},
client: {
// 暂不支持错误提示蒙层
overlay: false,
},
},
plugins: [
new VueLoaderPlugin(),
new HippyHMRPlugin({
// HMR [hash].hot-update.json will fetch from this path
hotManifestPublicPath: 'http://localhost:38989/',
}),
// add other plugin ...
],
module: {
rules: [
{
test: /\.vue$/,
use: [
vueLoader,
],
},
],
// add other loaders ...
}
}
package.json 配置:
{
"scripts": {
"hippy:debug": "hippy-debug",
// -c 或 --config 提供 webpack config 配置路径
"hippy:dev": "hippy-dev -c ./scripts/hippy-webpack.dev.js"
}
}
启动开发:
npm run hippy:debug
,npm run hippy:dev
如果安卓设备断连,需要手动用 adb 转发端口
# port for debug
adb reverse tcp:38989 tcp:38989
# port for HMR
adb reverse tcp:38988 tcp:38988
iOS的热更新
- iOS 设备需要代理到开发机上,或处于同一网段,才能使用 HMR 能力。对于模拟器,本就和开发机处于同一网段,ip 写
localhost
就能访问到。 修改 webpack 配置:
module.exports = {
devServer: {
host: '<your_ip_or_localhost_with_proxy>',
},
plugins: [
new HippyHMRPlugin({
// HMR [hash].hot-update.json will fetch from this path
hotManifestPublicPath: 'http://<your_ip_or_localhost_with_proxy>:38989/',
}),
],
}
- iOS 设备需要代理到开发机上,或处于同一网段,才能使用 HMR 能力。对于模拟器,本就和开发机处于同一网段,ip 写
Hippy-React
安装热更新依赖
npm i @hippy/react@^2.12.0
npm i -D @hippy/debug-server@^2.12.0 @hippy/hippy-hmr-plugin @hippy/hippy-react-refresh-webpack-plugin react-refresh
webpack 配置示例
const HippyHMRPlugin = require('@hippy/hippy-hmr-plugin');
const ReactRefreshWebpackPlugin = require('@hippy/hippy-react-refresh-webpack-plugin');
module.exports = {
devServer: {
// 默认 HMR 端口为38988
host: 38988,
// 默认 hot, liveReload 都为 true,如果只想使用 live-reload 功能,请将 hot 设为 false,liveReload 设为 true
hot: true,
liveReload: true,
devMiddleware: {
writeToDisk: true,
},
client: {
// 暂不支持错误提示蒙层
overlay: false,
},
},
plugins: [
new HippyHMRPlugin({
// HMR [hash].hot-update.json will fetch from this path
hotManifestPublicPath: 'http://localhost:38989/',
}),
new ReactRefreshWebpackPlugin({
// 暂不支持错误提示蒙层
overlay: false,
}),
],
module: {
rules: [
{
test: /\.(jsx?)$/,
use: [
{
loader: 'babel-loader',
options: {
sourceType: 'unambiguous',
presets: [
'@babel/preset-react',
[
'@babel/preset-env',
{
targets: {
chrome: 57,
ios: 9,
},
},
],
],
plugins: [
['@babel/plugin-proposal-class-properties'],
['@babel/plugin-proposal-decorators', { legacy: true }],
['@babel/plugin-transform-runtime', { regenerator: true }],
// add react-refresh babel plugin
require.resolve('react-refresh/babel'),
],
},
},
],
},
// other loader ...
],
},
};
package.json 配置:
{
"scripts": {
"hippy:debug": "hippy-debug",
// -c 或 --config 提供 webpack config 配置路径
"hippy:dev": "hippy-dev -c ./scripts/hippy-webpack.dev.js"
}
}
执行
npm run hippy:debug
和npm run hippy:dev
命令。如果安卓设备断连,需要手动用adb转发端口
# port for debug
adb reverse tcp:38989 tcp:38989
# port for HMR
adb reverse tcp:38988 tcp:38988
iOS的热更新
- iOS 设备需要代理到开发机上,或处于同一网段,才能使用 HMR 能力。对于模拟器,本就和开发机处于同一网段,ip 写
localhost
就能访问到。 修改 webpack 配置:
module.exports = {
devServer: {
host: '<your_ip_or_localhost_with_proxy>',
},
plugins: [
new HippyHMRPlugin({
// HMR [hash].hot-update.json will fetch from this path
hotManifestPublicPath: 'http://<your_ip_or_localhost_with_proxy>:38989/',
}),
],
}
- iOS 设备需要代理到开发机上,或处于同一网段,才能使用 HMR 能力。对于模拟器,本就和开发机处于同一网段,ip 写
接口
2.12.0 及以上的 @hippy/debug-server
除了提供 bin 命令 hippy-debug
和 hippy-dev
进行调试构建,还提供了接口供自定义的 CLI 工具封装时调用,使用方法如下:
const { webpack, startDebugServer } = require('@hippy/debug-server');
// 进行 webpack 开发环境带 HMR 能力的打包构建
webpack(webpackConfig, (err, stats) => {
// 处理 wepback 打包回调信息
});
// 启动调试 server
startDebugServer();