29 KiB
Debug
Hippy Debugging Principles
Hippy runs directly in real device's JS engine, using WebSocket on Android to communicate with Chrome on the computer via Chrome DevTools Protocol debugging, while iOS uses the built-in JavaScriptCore to connect with Safari for debugging, and in the newer Hippy versions of iOS, it can also be debugged using Chrome DevTools.
The JS code running in Hippy can originate from a local file, or from a remote server.
The @hippy/debug-server-next is aimed to solve the problem of getting the JS file for debugging in native debug mode, and send the Chrome DevTools Protocol back to the debugger.
Project Initialization
-
run
git clone https://github.com/Tencent/Hippy.git! > Hippy repository uses git-lfs to manage so, gz, otf, png, jpg files, please make sure you have git-lfs installed.
-
Run the command
npm installat project root to install front-end dependencies. -
Run the command
npx lerna bootstrapat project root to install each package dependency of the front-end. (Hippy uses Lerna to manage multiple JS repositories, iflerna command is not found, first executenpm install lerna -g) -
Run the command
npm run buildat project root to compile the front-end SDK package. -
Select a front-end sample project to compile, run
npm run buildexample -- [hippy-react-demo|hippy-vue-demo]in project root.
Native Environment Preparation
We recommend leaving a backdoor in the native code to enter debug mode after being triggered by certain conditions, the specific code can be found in iOS and Android, where a TestModule is implemented and the front-end enters debug mode when its debug or remoteDebug methods are called. The native can be accessed by other means. The native opens the Hippy Debug page with the following code.
-
Android.
// Initialize the hippy engine HippyEngine.EngineInitParams initParams = new HippyEngine.EngineInitParams(); // optional: whether to set to debug mode, default DebugMode.None. set DebugMode.Dev for debug mode, all jsbundle are downloaded from the debug server initParams.debugMode = HippyEngine.DebugMode.Dev; // debugMode still uses boolean type below 2.16.0 versions => initParams.debugMode = true; initParams.debugServerHost = "localhost:38989"; initParams.debugBundleName = "index.bundle"; -
iOS.
- (void)viewDidLoad { // Enable debugging NSDictionary *launchOptions = @{@"DebugMode": @(YES)}; // Use the default http://localhost:38989/index.bundle NSString *bundleStr = [HippyBundleURLProvider sharedInstance].bundleURLString; NSURL *bundleUrl = [NSURL URLWithString:bundleStr]; HippyBridge *bridge = [[HippyBridge alloc] initWithDelegate:self bundleURL:bundleUrl moduleProvider:nil launchOptions:launchOptions executorKey:@"Demo"]; } - (BOOL)shouldStartInspector:(HippyBridge *)bridge { return bridge.debugMode; } - (NSURL *)inspectorSourceURLForBridge:(HippyBridge *)bridge { return bridge.bundleURL; }
Front-end Environment Preparation
-
install the next generation of debugging tools:
npm i -D @hippy/debug-server-next@latest -
Modify the Webpack configuration to add the debug service address, the default is
http://localhost:38989module.exports = { devServer: { // debug service address remote: { protocol: 'http', // Local LAN IP for real iOS device debugging // localhost for iOS emulator and real Android device debugging // configured as remote server IP or domain name for remote debugging host: '192.168.1.100', // debug service port port: 38989, }, // default false, set to true debugging service supports multiple projects debugging at the same time without interfering with each other multiple: false, // default false, hippy vue projects can be manually enabled vueDevtools: false, // default hot/liveReload both true, if you only want to use live-reload function, please set hot to false and liveReload to true hot: true, liveReload: true, client: { overlay: false, }, }, // ... other config } -
Modify the start build command in
package.json. If the business is started with a custom cli, refer to package build API for configuration{ "scripts": { // -c or --config provides the webpack config path "hippy:dev": "node ./scripts/env-polyfill.js hippy-dev -c ./scripts/hippy-webpack.dev.js" } } -
Run
npm run hippy:devto start building and turn on the Dev Server forHMRandLive-Reloadas needed, and print out the bundleUrl and debug home address when the build is finished
-
paste bundleUrl and click start button
-
Start debugging with the debugger
-
Safari DevTools: Open Safari's development menu on a Mac (
Preferences->Advanced->Show Development Menu) and follow the instructions below to start debugging. The Safari debugger supports iOS devices and supportsHMR & Live-Reload, Log, Sources, Memoryand other capabilities.
-
Chrome DevTools: Visit the debug home address printed in step 4 to start debugging. Chrome debugger supports Android & iOS devices with
HMR & Live-Reload, Elements, Log, Sources, Memorycapabilities.
If you don't use our debug homepage, you can also actively open DevTools at
chrome://inspectby first making sure that theDiscover USB devicescheckbox isunchecked, then making sure thatDiscover network targetsis checked, and that theConfigurebutton popup contains thelocalhost:38989debug service address, and the wordsHippy debug tools for V8should appear in theRemote Targetbelow, click theinspectlink below to open the Chrome debugger. -
@hippy/debug-server-nextcontains all the capabilities of@hippy/debug-server, a debugging tool for Hippy 3.0 that is fully backward compatible.
Debugging Javascript
Although Hippy is a front-end framework, it still runs in the native. If the native provides a backdoor to directly link to the debugging service, you can directly use the native backdoor to connect to the native for debugging.
Here, take the official example to describe how to debug.
!> Note that the official example makes @hippy/react and @hippy/vue an alias to the packages directory. In order to debug the official example, you need to first use npm run build in the Hippy project root to compile the front-end SDK; or remove the alias to packages in example's scripts directory.
iOS
iOS debugging supports both emulator and real iOS device. Since JSBundle and debugging protocols depend on network transfer, you need to make sure your device is on the same LAN as the development machine when debugging on real device. Therefore, we recommend using the emulator.
Emulator Debugging
- Click Xcode on Mac AppStore to download and install Xcode.
- use Xcode to open
HippyDemo.xcodeprojproject file in Hippy iOS example project, and click run. Under normal circumstances, you should be able to start simulator and run the built-in Hippy front-end code, - open project hippy-react-demo or hippy-vue-demo under
examples. after installing the dependencies vianpm i, usenpm run hippy:devto start building and debugging, - Go back to the simulator, paste bundleUrl and start debugging
- If HMR or Live-Reload is enabled when the JS source file is changed, it will be refreshed automatically after compilation; otherwise, you need to press
Command + RorCommand + Dto bring up the Reload panel to refresh it.
If
Command + Dcannot bring up the panel, you can clickDevice->Shaketo force open the Reload panel
Real iOS device debugging
-
Real iOS device debugging only supports XCode compiled apps, and the JavaScript debugging and web inspector options need to be enabled on iOS devices
-
Make sure the iOS device and debug service are on the same LAN
-
Compile App,paste bundleUrl and start debugging
!> Note: You must ensure that the development machine and the device are on the same LAN when debugging on the real device, otherwise the JSBundle will fail to load. Neither of the following is satisfied:
(a) The development machine and the real iOS device are connected to different network environments.
(b) The development machine is connected to the network cable and the mobile device is connected to WiFi.
Android
Android uses the adb port mapping feature to solve the communication problem between the real Android device and the development machine, but because of the efficiency of the ARM simulator, it is more recommended to use the real device for debugging.
Specific procedure:
- Download and install Android Studio
- Using Android Studio to open
Hippy Reporoot directory, which will load Hippy Android example project. - Plug in your real Android device via the data cable and click Run in Android Studio. Normally, the device should already be running the
Hippy Demoapp. - Go back to your device and make sure that
USB debug modeis turned on - you can enterDeveloper mode' by clickingBuildin succession on the About page, and then turn onUSB debug modeafter you enter theDeveloper modescreen. - Run
adb reverse --remove-all && adb reverse tcp:38989 tcp:38989to make sure port 38389 is not occupied. - Open the front-end example project hippy-react-demo or hippy-vue-demo, use npm run hippy:dev to start building and debugging service.
- Back to your device, paste bundleUrl and start debugging
- If HMR or Live-Reload is enabled when the JS source file is changed, it will be refreshed automatically after compilation; otherwise, you need to press
Command + RorCommand + Dto bring up the Reload panel.
Elements Visualization Inspection
Android SDK min support version 2.9.0 iOS SDK min support version 2.11.5
Hippy implements node and property mapping from front-end to native, allowing visual inspection of Elements on Chrome DevTools.
Operate Mobile Phone Interface
Android SDK min supported version 2.16.0
Hippy implements the Input interface of the Chrome DevTools Protocol . You can directly operate the mobile phone interface on Chrome DevTools without switching back and forth during debugging.
HMR & Live-Reload
min support version 2.12.0
hippy-react-demo config script
!> Please don't import HMR-related configuration in production environment.
After the developer has modified the front-end code, we can refresh the component view by Hot Module Replacement (HMR) retaining state, or reload the business instance by live-reload, as follows.
Hippy-Vue
-
Install live-reload dependencies
npm i @hippy/vue@^2.12.0 npm i -D @hippy/debug-server-next@latest @hippy/vue-loader @hippy/vue-css-loader -
Webpack config demo
const VueLoaderPlugin = require('@hippy/vue-loader/lib/plugin'); const vueLoader = '@hippy/vue-loader'; module.exports = { devServer: { // default hot/liveReload set to true. If you only want to use live-reload, set hot to false and liveReload to true hot: true, liveReload: true, client: { // Error masks are not supported at the moment overlay: false, }, }, plugins: [ new VueLoaderPlugin(), // add other plugin ... ], module: { rules: [ { test: /\.vue$/, use: [ vueLoader, ], }, ], // add other loaders ... } } -
package.json configuration.
{ "scripts": { // -c or --config provides webpack config path "hippy:dev": "node ./scripts/env-polyfill.js hippy-dev -c ./scripts/hippy-webpack.dev.js" } } -
start development:
npm run hippy:dev -
If the Android device is disconnected, you need to manually forward the port with adb:
adb reverse tcp:38989 tcp:38989. -
iOS hot update: iOS devices need to be proxied to the development machine or on the same network segment to use the HMR capability. Webpack configuration is modified as shown below, for the emulator, which is on the same network segment as the development machine, the IP is accessible by setting to
localhost.module.exports = { devServer: { host: '<your_ip_or_localhost_with_proxy>', }, }
Hippy-React
-
install HMR
npm i @hippy/react@^2.12.0 npm i -D @hippy/debug-server-next@latest @hippy/hippy-react-refresh-webpack-plugin react-refresh -
Webpack configuration example
const ReactRefreshWebpackPlugin = require('@hippy/hippy-react-refresh-webpack-plugin'); module.exports = { devServer: { // default hot, liveReload are true, if you only want to use live-reload function, please set hot to false and liveReload to true hot: true, liveReload: true, client: { // Error masks are not supported at the moment overlay: false, }, }, plugins: [ new ReactRefreshWebpackPlugin({ // Error masks are not supported at this time 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 configuration.
{ "scripts": { // -c or --config provide Webpack config path "hippy:dev": "node ./scripts/env-polyfill.js hippy-dev -c ./scripts/hippy-webpack.dev.js" } } -
Run the
npm run hippy:devcommands. -
If the Android device is disconnected, you need to manually forward the port with adb:
adb reverse tcp:38989 tcp:38989. -
iOS hot update: iOS devices need to be proxied to the development machine or on the same network segment to use the HMR capability. Webpack configuration is modified as shown below, for the emulator, which is on the same network segment as the development machine, the IP is accessible by writing
localhost.module.exports = { devServer: { host: '<your_ip_or_localhost_with_proxy>', }, }
Vue Devtools
Minimum supported version 2.13.7
Support for debugging Vue component trees, component state, routes, store, and event performance
-
install vue-devtools dependencies.
npm i @hippy/vue@^2.13.7 @hippy/vue-router@^2.13.7 npm i @hippy/debug-server-next@latest -D -
open vue devtools
module.exports = { devServer: { remote: { protocol: 'https', host: 'devtools.qq.com', port: 443, }, // default is false, when enabled, vue debugging commands will be distributed via the remote debugging service specified in the remote field vueDevtools: true },
! > Vue Devtools configuration will inject debugging code at runtime, which may have some performance impact, please do not introduce it in the production environment.
React Devtools
Min support client version 2.13.7
Min support front-end version 2.14.0
Support for debugging React component tree, component state, route, performance, etc.
Configuration
-
Install react devtools dependencies:
npm i @hippy/react@^2.14.0 npm i @hippy/debug-server-next@latest -D -
Open react devtools
module.exports = { devServer: { remote: { protocol: 'https', host: 'devtools.qq.com', port: 443, }, // default false, which will distribute react debugging commands through the remote debugging service specified by the `remote` field. reactDevtools: true }, module: { rules: [ { test: /\. (jsx?)$/, // must add the following line. to make babel ignore react-devtools plugin exclude: /@hippy\/hippy-react-devtools-plugin/, 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 }], require.resolve('react-refresh/babel'), ], }, }, ], }, ], }, }
!> React Devtools configuration injects debugging code at runtime, which may have some performance impact, please do not introduce it in production environment.
Translated with www.DeepL.com/Translator (free version)
Build & Compile API
@hippy/debug-server-next provides command hippy-debug and hippy-dev to debug and compile. In addition, it provides interface for custom CLI tools to call.:
const { webpack } = require('@hippy/debug-server-next');
// start webpack compiling, supports HMR and other ability
webpack(webpackConfig, (err, stats) => {
// handle webpack callbacks
});
Remote Debugging
Remote Debugging currently supports two modes, including Development Remote Debugging and Production Remote Debugging mode
- Development Remote Debugging mode needs to load bundle from remote server for debug
- Production Remote Debugging mode uses local cached bundle instead of remote, which is more suitable for production environment. If no such requirement, you can also use the above Development Remote Debugging mode
Development Remote Debugging
Local debugging has two pain points.
- unable to cover all models and difficult in locating problems from user feedback.
- unable to get rid of the data cable.
Then we can consider using remote debugging for these scenarios, with the following preview.
Front-end Usage Configuration
-
Install the next generation debugging tool:
npm i -D @hippy/debug-server-next@latest. -
Modify the Webpack configuration and add
remotefield to configure the compilation product upload address and debug service address (default http://127.0.0.1:38989). For security reasons, the official remote debugging service is not available on the public network, you need to deploy it privately by yourself.module.exports = { devServer: { // The remote debug address, configured as the address of your private debug service remote: { protocol: 'https', host: 'devtools.qq.com', port: 443, // Configure the scheme for the host app to scan and load, if you don't need to scan, you may not configure it qrcode: (bundleUrl) => { // must specify business bundleName const bundleName = 'QQGroupGameRank'; return `mqqapi://hippy/remoteDebug?bundleName=${bundleName}&bundleUrl=${encodeURIComponent(bundleUrl)}`; } }, client: { overlay: false, }, }, // other config ... }!> Configure that the compilation product will be uploaded to the remote end when debugging remotely and deleted after debugging is finished. As a precaution, make sure that the code does not contain sensitive information (e.g. keys, etc.).
!> When debugging remotely,
publicPathwill be set to{protocol}://${host}:${port}/<hash>/to distinguish between different business.!> when business loads remote js sub-bundles, if
customChunkPathis not configured, the address ofpublicPathwill be used by default, please make sure the remote subpackage is also uploaded to the debug server at the same time. -
Start the build:
npm run hippy:dev, and the debug message will be printed when the build is finished:
where the three printed fields are:
- bundleUrl: the address of the JSBundle for remote debugging, filled in the
remoteServerUrlfield of the host App - debug page: the debugging home page of the PC side
- bundleUrl scheme: scheme of the host App's code scanning
- bundleUrl: the address of the JSBundle for remote debugging, filled in the
Host App Configuration
Set Host App debugMode to true and pass in the bundleUrl generated by front-end Webpack for remote wireless debugging, we recommend the host to use input box or scan QR code to pass in.
-
Android
// initialize hippy engine HippyEngine.EngineInitParams initParams = new HippyEngine.EngineInitParams(); initParams.debugMode = HippyEngine.DebugMode.Dev; // debugMode still uses boolean type below 2.16.0 versions => initParams.debugMode = true; initParams.remoteServerUrl = ""; // remote debug bundleUrl -
iOS
- (void)viewDidLoad { // Enable debugging NSDictionary *launchOptions = @{@"DebugMode": @(YES)}; NSString *bundleStr = ""; // remote debug bundleUrl NSURL *bundleUrl = [NSURL URLWithString:bundleStr]; HippyBridge *bridge = [[HippyBridge alloc] initWithDelegate:self bundleURL:bundleUrl moduleProvider:nil launchOptions:launchOptions executorKey:@"Demo"]; } - (BOOL)shouldStartInspector:(HippyBridge *)bridge { return bridge.debugMode; } - (NSURL *)inspectorSourceURLForBridge:(HippyBridge *)bridge { return bridge.bundleURL; }
Production Remote Debugging
In the production environment, developers can directly debug the local bundle, restore the scene of online users, and improve the efficiency for fixing problem
Front-end Usage
no need
Host App
- Android:
Minimum supported version 2.16.0
The type of debugMode is changed from boolean type to enumeration type
public enum DebugMode {
None, // Production
Dev, // Development
UserLocal, // directly use local bundle to debug instead of from remote server
}
Step One:
// hippy engine initialized
HippyEngine.EngineInitParams initParams = new HippyEngine.EngineInitParams();
initParams.debugMode = HippyEngine.DebugMode.UserLocal; // open debug in production
Step two:
Sometimes engine startup and business are separated in many business, so we separate the debugging option startup and debug server connection, which is better for usage.
// connect debug server before or after business startup
mHippyEngine.getEngineContext().getBridgeManager().connectDebugUrl("ws://${ip}:${port}/debugger-proxy");
mHippyView = mHippyEngine.loadModule(loadParams, new HippyEngine.ModuleListener() {
@Override
public void onLoadCompleted(ModuleLoadStatus statusCode, String msg, HippyRootView hippyRootView) {
if (statusCode != ModuleLoadStatus.STATUS_OK) {
LogUtils.e("MyActivity", "loadModule failed code:" + statusCode + ", msg=" + msg);
}
}
@Override
public boolean onJsException(HippyJsException exception) {
return true;
}
});
2.iOS
(coming soon)
List of supported capabilities for remote debugging
min support version 2.13.1
| Platform | HMR & Live-Reload | Elements | Log | Sources | Memory |
|---|---|---|---|---|---|
| Android | ✅ | ✅ | ✅ | ✅ | ✅ |
| iOS | ✅ | ✅ | ❌ | ❌ | ❌ |
Framework Log
Both hippy-react and hippy-vue will output the information of communicating with native, including the js-native node operations, events sent/received. These logs are actually very helpful for business debugging, allowing developers to understand how the front-end framework translates code into a syntax that the native can understand. When you encounter problems, please first check the framework communication logs, as they can basically locate most of the problems.
If you need to turn off the logs, you can add silent: true to hippy-react's new Hippy startup parameters, or turn on Vue.config.silent = true; in hippy-vue project entry file, or add silent: true to hippy-vue-next's createApp init options.
