piggy
aims to be a simple sandbox for developers who want a quick way to create custom tooling for their own projects.
This repository provides both a stand-alone Electron app, and a reference implementation of a client-side library for use with React Native. Eventually, libraries for different languages or runtimes may be included.
If you want to get up and running with React Native quickly, please refer to the integration guide.
While it does provide some useful functionality out of the box, it's best to think of piggy
as a straightforward, pre-configured, non-opinionated playground that uses Electron and React to communicate with your applications using WebSockets; stream data to piggy
, grab it from the WebSocket, and display it in a React component however you want.
While similar projects exist, they tend to have more ambitious goals: extension bundling, publishing, sharing, etc. That's great for certain classes of tooling, but also introduces a more complicated architecture that can be time consuming or intimidating to integrate against, especially if you just need to build a few one-off, in-house tools.
That said, we do believe that the stock version of piggy
can be immediately useful to some React Native developers, so notarized binaries are provided in the Releases section of this project, and the client-side React Native library is available via npmjs.com.
Let's take a quick look at the piggy
UI:
You can add your own tooling to the left bar by simply dropping some source files in the correct directory and reloading the app. The plugins in the screenshot are included in the app/App/Plugins/Standard directory as examples. If you want to learn more about writing your own tools, please see the custom plugin documentation.
Due to the (lack of) architecture, your plugins just become part of the app. There are no sandboxing rules between plugins, and your code has access to all of the app internals. Again, this design decision is intentional. piggy
plugins are not necessarily meant to be shared and published to the world, they are supposed to be tools that help you build your app, filling in gaps that may exist with existing solutions.
Over time applications grow to contain multiple complicated, loosely coupled subsystems for things like networking, state management, navigation and various other domain-specific tasks. Loosely coupled subsystems are great for reuse, extensibility and testability, but often times they can make software more difficult to reason about.
In addition, the subsystems are often implicitly affected by performance or timing of other subsystems, making certain types of optimization (like app startup) time-consuming and error prone.
The Timeline plugin can be used to:
- Obtain a visual overview of what an app is doing over time, as its running
- Measure how long subsystems are taking to complete their tasks.
- Identify implicit dependencies between subsystems.
- Spot certain classes of unexpected behavior that may not result in errors.
- Generally understand how the app works, at a high level.
The Event Log plugin federates logs and information from multiple large subsystems, and provides quick tools for filtering and searching. It includes:
- Logs from both the JS and native layers
- All HTTP traffic
- Navigation events
- Redux actions
As the app is used, the log is updated in real-time. It has a couple nice features baked in, including the ability to:
- View HTTP request and response data
- Copy HTTP requests as cURL commands
- Inspect the contents of Redux actions
While developing apps that use Redux it can often be useful to be notified when global state changes. The State Subscriptions tab allows developers to monitor changes to slices in the store, in real time.
Connecting to and debugging on physical devices can be annoying (and in some cases difficult), especially for developers without a lot of experience with pure-native development. The Devices tab in the tool has a couple nifty features to aide development on both iOS and Android hardware.
The Connected Clients
section can be used to see which devices are connected to the tooling. The device type, followed by an IP address, then a device identifier
is displayed for each connected client.
Sometimes, especially in automation environments, it may be useful to disallow specific devices from connecting to the tool. For these cases, devices can be blocklisted by device identifier
.
The Android Devices
section is a thing wrapper over the adb
binary that assists with the following:
- Starting or restarting the
adb
server - Automatically setting up
adb reverse
for TCP ports8081
(metro bundler),8347
(tooling), and8888
(http proxy, if available). - Grabbing screenshots and
adb logcat
dumps
adb reverse
is used to forwardTCP
ports overUSB
(or over Wifi). This allows your app on a device to access services running on your development machine via the device'slocalhost
.For example, if you have a server on your computer running on port
1234
, and you connect your device viaUSB
and runadb reverse tcp:1234 tcp1234
, on device you can access the server running on the computer by connecting tolocalhost:1234
.
The iOS development environment doesn't support anything like adb reverse
out of the box, which makes testing on device difficult, especially if the development machine and phone are on different networks.
One can work around this by using a combination of
- peertalk, a library that abstracts communication between a host computer and a device over
USB
- FBPortForwarding, which is an abstraction on top of
peertalk
that allows for forwardingTCP
traffic.
The tool and associated library packages these two pieces of functionality together with an easy to use API. Once integrated, as with Android, the following TCP
ports will be forwarded over USB
: 8081
(metro bundler), 8347
(tooling), and 8888
(http proxy, if available).
See the integration guide for more information.
Sometimes QA (or other users) run into difficult-to-reproduce bugs. If the bug can be reproduced while the app is attached to tooling, all Timeline and Event Log data can be imported and exported from the main app menu:
The resulting file can be attached to a bug report, and later imported by the developer that is troubleshooting the problem.
The current session can also be downloaded via local HTTP server, by simply making a request against http://localhost:8347/session/
. This can be useful in automation environments.
- Q: Does
piggy
only work with React Native apps?- A: Nope!
piggy
doesn't care what type of client sends it data. However, at this time we are only providing a client side library for React Native because it's our main, in-house use case. That said, building bindings for other languages or runtimes should be relatively trivial; as mentioned before, if you can create a WebSocket in your app, you can usepiggy
.
- A: Nope!
- Q: For React Native apps, why use
piggy
over other popular developer tools like React Native Debugger, Chrome DevTools, or Reactotron?- A: We don't necessarily recommend using
piggy
over existing solutions; it's designed to complement existing tooling!
- A: We don't necessarily recommend using
- Q: Why is this project named "piggy"?
- A:
piggy
is short for "piggy bank," something cute and vaguely on-brand for our company and community. Also, I'm not good at naming things.
- A: