PageSpy
repository·main·Indexed 43 days ago
https://github.com/huolalatech/page-spyA developer platform for remote web page debugging consisting of client-side SDKs and a web-based dashboard. It provides diagnostic data collection and visualization for various environments, including Web, HarmonyOS, Lynx, and miniprogram frameworks such as Alipay, UniAPP, and Taro.
What's inside PageSpy
- PageSpy is a developer platform designed for remote debugging of web pages. This repository contains the SDKs used to collect information from client environments. The collected data is sent to the [page-spy-web][page-spy-web] platform, which consumes, filters, organizes, and converts the information into a standardized format for visualization and debugging.
Overview of Page Spy SDKs
mainPage Spy is a tool for remote debugging of web pages. This repository contains the SDKs used to collect page information. The collected data is then consumed by the page-spy-web project, which filters, organizes, and presents the data in a standardized format on a web interface.
To use Page Spy, you typically need both the SDK (to collect data from your application) and the web dashboard (to view the collected data).
What is DataHarborPlugin and how does it work?
mainThe
DataHarborPluginprovides offline caching and data downloading capabilities for PageSpy in browser environments.Historically, remote debugging required both the client and the debugging server to be online simultaneously.
DataHarborPluginbreaks this requirement by listening for thepublic-dataevent to cache data locally on the client. When an issue is identified, users can export the cached data manually.Data Lifecycle:
- Data collection starts when
new PageSpy()is called. - Data is stored in client-side memory.
- When the accumulated data reaches the
maximumthreshold (defaulting to 10MB), the plugin generates an Object URL viaURL.createObjectUrl()to temporarily store the data, and collection continues.
- Data collection starts when
What is DataHarborPlugin
mainThe
DataHarborPluginis a PageSpy plugin designed for browser environments that enables offline data caching and downloading.Traditionally, remote debugging requires both the client and the debugging end to be online simultaneously.
DataHarborPluginbreaks this requirement by listening topublic-dataevents and storing data in the client's memory. When the accumulated data reaches a specific threshold (defaulting to 10MB), the plugin generates an Object URL viaURL.createObjectUrl()to temporarily store the data, allowing users to export logs even after the session has ended or the connection is lost.Use MPEvalPlugin to run dynamic scripts in mini programs
mainThe
MPEvalPluginis a plugin for the PageSpy mini program SDKs. It enables the execution of dynamic scripts within the mini program environment.This plugin is compatible with the following mini program SDKs:
@huolala-tech/page-spy-wechat@huolala-tech/page-spy-alipay@huolala-tech/page-spy-uniapp@huolala-tech/page-spy-taro
CAUTION You must remove this plugin from your code before submitting your mini program for official review, otherwise the review process will fail.
import PageSpy from '@huolala-tech/page-spy-wechat'; import MPEvalPlugin from '@huolala-tech/page-spy-plugin-mp-eval'; // Register plugin PageSpy.registerPlugin(new MPEvalPlugin()); // Init PageSpy const pageSpy = new PageSpy();Use PageSpy in offline mode
mainBy settingoffline: truein theInitConfig, the SDK enters "offline mode". In this mode, PageSpy will not attempt to create rooms or establish WebSocket connections with the debugger. This is useful for scenarios where you want to capture data without immediate real-time transmission (e.g., for later replay).Implement a custom PageSpyPlugin
mainTo extend PageSpy, you can implement the
PageSpyPluginabstract class. A plugin is identified by itsnameproperty and can control its execution order using theenforceproperty.Plugin Lifecycle Methods
onInit(params: OnInitParams): Called whennew PageSpy()is instantiated. Use this to set up data collection or listeners.onMounted(params: OnMountedParams): Called after PageSpy has rendered (if applicable). Use this to inject UI elements into the PageSpy interface.onReset(): Called when the user calls$pageSpy.abort(). Use this to clean up resources or UI elements added by the plugin.
Execution Order
Plugins are executed based on the
enforceproperty:enforce: "pre"(runs first)- No
enforceproperty (runs second) enforce: "post"(runs last)
import { PageSpyPlugin, OnInitParams, OnMountedParams } from '@huolala-tech/page-spy-types'; export default class MyPlugin implements PageSpyPlugin { name = 'MyPlugin'; enforce?: 'pre' | 'post'; // Optional execution order onInit(params: OnInitParams) { // Setup logic } onMounted(params: OnMountedParams) { // UI injection logic } onReset() { // Cleanup logic } }Understand RRWebPlugin data dispatching and playback
mainBecauserrwebdata can become very large due to complex DOM structures or high user interaction, this plugin is optimized to reduce network overhead. Instead of streaming all raw data, it dispatches'public-data'events. This allows statistical plugins (likeDataHarborPlugin) to collect the data efficiently without burdening the network during real-time debugging.How RRWeb data is dispatched
mainBecause
rrweb-eventdata can be significantly large due to complex webpage structures and high interaction frequency, this plugin is optimized to reduce network overhead.Instead of real-time transmission of every mutation, the plugin only dispatches the
public-dataevent for statistical plugins to collect. This prevents real-time transmission from imposing a heavy burden on the network during debugging.Communicate with the debugger via socketStore
mainPlugins interact with the PageSpy debugger/API using the
socketStoreprovided inonInitandonMounted.Broadcasting Data
To send data from the client to the debugger, use
socketStore.broadcastMessage(message).Behavioral Convention: If a plugin collects platform behavior data that it wants to make available for statistics or persistence, it should also dispatch a
"public-data"internal event usingsocketStore.dispatchEvent('public-data', message). This allows other plugins to intercept and collect this data.Handling Debugger Messages
To listen for specific messages sent from the debugger, use
socketStore.addListener(eventName, callback). The callback provides areplyfunction which, when called, sends a unicast response back to the specific debugger instance that initiated the request.Message Format
A typical message item follows the
SpyMessage.MessageItemshape:type: The message type (e.g.,'rrweb-event').role: The sender role (e.g.,'client').data: The actual payload.
Built-in PageSpy Plugins
mainThe Lynx SDK includes several built-in plugins that automatically detect runtime availability:
ConsolePlugin: Proxiesconsole.log,info,error,warn, anddebug.SystemPlugin: Reports PageSpy client information and available Lynx system information.NetworkPlugin: Prioritizes proxyingfetch; proxiesXMLHttpRequestonly if exposed by the runtime.WebSocketPlugin: Proxies WebSocket traffic only ifglobalThis.WebSocketis constructible.ErrorPlugin: Listens for global errors or unhandled rejections if the runtime exposes the necessary hooks.
You can disable any of these by adding their name to the
disabledPluginsarray in the configuration.How to communicate via socketStore in plugins
mainPlugins interact with the debugging terminal and other plugins using the
socketStoreinstance provided in lifecycle methods.Broadcasting Data
To send data to the debugging terminal, use
socketStore.broadcastMessage(message).Convention: If a plugin collects platform behavior data that other plugins might need (e.g., for statistics), it is recommended to also dispatch a
public-datainternal event usingsocketStore.dispatchEvent('public-data', message). This allows other plugins to uniformly collect data from this event.Listening for Terminal Events
You can listen for specific messages sent from the debugging terminal using
socketStore.addListener(eventName, callback). The callback provides asource(containing the data) and areplyfunction. Callingreply(result)will unicast the result back to the specific debugging terminal that sent the request.// Broadcasting data socketStore.broadcastMessage({ type: 'my-event', role: 'client', data: {} }); socketStore.dispatchEvent('public-data', { type: 'my-event', role: 'client', data: {} }); // Listening and replying socketStore.addListener('request-data', ({ source }, reply) => { const params = source.data; const result = { status: 'ok' }; reply(result); // Sends result back to the terminal });