File: README.md
Introduction
Reactotron is a powerful debugger for React and React Native applications. It provides an easy-to-use interface for developers to monitor their application's state, network requests, and performance metrics and can be used for any size of project, from small personal apps to large-scale enterprise applications. The OG debugger at Infinite Red that we use on a day-to-day basis to build client apps. Additionally, Reactotron is completely open source and free to use, making it an invaluable tool for developers at all levels of experience.
We recommend that you watch Darin Wilson's talk at Chain React: Chain React 2018: Debugging and Beyond with Reactotron!
Reactotron Superpowers
Use Reactotron to:
- view your application state
- show API requests & responses
- perform quick performance benchmarks
- subscribe to parts of your application state
- display messages similar to
console.log - track global errors with source-mapped stack traces including saga stack traces!
- dispatch actions like a government-run mind control experiment
- hot swap your app's state using Redux or mobx-state-tree
- show image overlay in React Native
- track your Async Storage in React Native
You plug it into your app as a dev dependency so it adds nothing to your production builds.
Desktop
Reactotron on the left, demo React Native app on the right.
Installation
On the Releases page, navigate to the latest reactotron-app release to find the newest version of:
- macOS (x64 & arm64)
- Linux (32-bit & 64-bit)
- Windows (32-bit & 64-bit)
How to setup Reactotron in our app
How to use Reactotron's features/plugins
- Track Global Errors
- Track Global Logs
- Networking
- Async Storage
- React Native MMKV
- Benchmark
- apisauce
- Overlay
- MST
- Redux
- Open in Editor
- Storybook (only for React Native)
reactotron-react-nativeships with Storybook.
This enables you to switch to Storybook from the Reactotron app. - Custom Commands
Tips and Tricks
Some tips that will elevate your Reactotron experience.
Bug Reports
When reporting problems with Reactotron, use the provided example app located in app/example-app to replicate the issue. This approach enables us to isolate and expedite the resolution of the problem.
Want to contribute? Here are some helpful reading materials
Troubleshooting
Credits
Reactotron is developed by Infinite Red, @rmevans9, and 70+ amazing contributors! Special thanks to @skellock for originally creating Reactotron while at Infinite Red.
Premium Support
Reactotron, as an open source project, is free to use and always will be. Infinite Red offers premium React and React Native mobile app design/development services. Email us at [email protected] to get in touch for more details.
File: apps/reactotron-app/README.md
What is Reactotron?
Reactotron is a macOS, Windows, and Linux app for inspecting your React JS and React Native apps.
Watch Darin Wilson's talk at Chain React: Chain React 2018: Debugging and Beyond with Reactotron!
Use it to:
- view your application state
- show API requests & responses
- perform quick performance benchmarks
- subscribe to parts of your application state
- display messages similar to
console.log - track global errors with source-mapped stack traces including saga stack traces!
- dispatch actions like a government-run mind control experiment
- hot swap your app's state using Redux or mobx-state-tree
- show image overlay in React Native
- track your Async Storage in React Native
You plug it into your app as a dev dependency so it adds nothing to your product builds.
Desktop
Reactotron on the left, demo React Native app on the right.
Documentation
See our documentation site here: https://docs.infinite.red/reactotron/
Credits
Reactotron is developed by Infinite Red, @rmevans9, and 70+ amazing contributors! Special thanks to @skellock for originally creating Reactotron while at Infinite Red.
Premium Support
Reactotron, as an open source project, is free to use and always will be. Infinite Red offers premium React and React Native mobile app design/development services. Email us at [email protected] to get in touch for more details.
File: apps/example-app/README.md
Welcome to the Reactotron Example App
The sole purpose of this app is to aid in developing Reactotron. It contains an example configuration and code for exercising the functionality of Reactotron's packages.
The example app was generated with Ignite; the boilerplate that Infinite Red uses as a way to test bleeding-edge changes to our React Native stack.
Quick Start
:::info
Before you start, run yarn in the root directory of the repo to make sure all of the dependencies have been installed successfully.
:::
- From the parent directory, run
yarn build && yarn startThis will build the latest version of Reactotron and open it. - From the parent directory, run
yarn start:exampleor inside of example app directoryyarn start. (Check the example app'spackage.jsonfor additional options.) - Select the host platform you'd like to build for.
- Once the build has completed, there should be a connection on the home screen of Reactotron from the example app.
File: docs/contributing/architecture.md
Architecture
Publish / Subscribe
Reactotron uses a publish / subscribe model to communicate between clients. This is implemented using WebSockets.
There are three main parties:
- The web socket server that publishes information
- The Electron app with Reactotron's UI, which subscribes to app updates
- The app client that we are debugging, which sends commands with information about the app to the server
Websockets are used to sends "commands", which are JSON objects with information about the app we are debugging. The payloads are sent to the server, which then publishes them to all subscribers (like the Electron app).
Workspaces
This repository is broken into different workspaces:
Reactotron app
These workspaces are used to build the Electron app that runs Reactotron.
reactotron-app- The Electron app that runs Reactotron.reactotron-core-ui- UI components used by Reactotron. This was created to allow for other types of Reactotron clients to be built.reactotron-core-server- The server that receives commands from the client and publishes them to subscribers. This server is started when the Reactotron Electron app is started.
Reactotron client
Clients are based around a plugin architecture. This allows us to add new features without having to modify the core of Reactotron.
See reactotron-core-client for more information about plugins are implemented. In short, plugins are a way to listen to all the commands published by the server and then can do certain actions or publish new commands.
These workspaces are used to build the client that we are debugging.
Core Plugins
reactotron-core-client- The base client with functionality for sending commands to the server.reactotron-react-native- This is the Reactotron client for React Native apps. This contains core plugins specific to React Native apps.reactotron-react-js- This is the Reactotron client for React web apps. This contains core plugins specific to React web apps.
Extra Plugins
Reactotron client is built on a plugin architecture. This allows us to add new features without having to modify the core of Reactotron.
reactotron-redux- This is a plugin that adds Redux support to Reactotron.reactotron-mst- This is a plugin that adds MobX State Tree support to Reactotron.
File: docs/contributing/ci.md
name: Running Tests on Untrusted Forks sidebar_position: 99
Running CI Scripts on Untrusted Forks
Untrusted forks could contain malicious code to mine cryptocurrency, steal secrets, or otherwise harm the CI server.
For PRs from untrusted forks, to run the CI scripts, we need to:
- Review the code to ensure that it is safe to run on the CI server.
- If the code is safe, run the
ci:trustscript to push the commits to a branch on the main repository, where the CI scripts can be run. - Once the tests have run, the status of the PR will be updated automatically (because the commits are the same).
How to run the CI scripts on untrusted forks:
Copy the name of the branch from the PR.
From your local clone of the main repository, run the
ci:trustscript.bashyarn ci:trustThe branch will be pushed and the tests will run
What does ci:trust do?
The ci:trust script does the following:
- Adds and fetches the untrusted fork as a temporary remote in your local repository.
- Pushes the specific branch from the untrusted fork to a designated temporary branch in your original repository.
- Pushing to a local branch triggers the continuous integration (CI) tests on the commits of the branch.
- Because the commits are the same, the status of the PR will be updated automatically.
Notes
- The ci:trust script will only work if you have write access to the main repository. This prevents malicious users from running the script on the main repository.
- The ci:trust script pushes the commits to a branch called
temp-ci-trusted-fork.
:::warning
The temp-ci-trusted-fork branch will be deleted and recreated if it already exists. This allows the script to
clean up its own temporary branches.
:::
File: docs/contributing/index.md
Welcome to the Reactotron Contributing Guide
Thank you for investing your time in contributing to our project!
:::tip
Please start by reading the other docs in this folder to understand how the monorepo folder structure and plugin architecture work.
:::
Making changes to the Reactotron App
Step 1: Get the development version of reactotron running
- Fork the repo and then clone it to your local machine:
git clone [email protected]:YOUR_USER_NAME/reactotron.git - Install dependencies:
yarn - Start the
reactotron-appin development mode:yarn start
You should see the reactotron electron app open on your machine with the development menu open.
Step 2: Use the example react-native app to test your changes
- Start the example app with
yarn start:example - Launch the app in the simulator of your choice.
- You should see output in the reactotron app.
Step 3: Making changes
Changes made to the main reactotron electron app in ./apps/reactotron-app will be reflected in the reactotron app that you started in step 1. You may need to kill the app and restart it to see your changes.
:::info
Remember to reload the example app from step 2 or other connected application(s) to reconnect the app to reactotron.
:::
Changes made to the client packages will be reflected in the example application immediately.
Bring Your Own Application
Let's say that you want to develop features using your own application instead of the example app. If you make changes to the non-electron app packages in this monorepo like reactotron-react-native or reactotron-core-client, you will need to build the packages and then link them to your react-native app. Luckily, we have a script that will do this for you.
You can run yarn build to build all reactotron packages, or yarn build:watch to watch and rebuild changes automatically.
If your app was located in the ~/Code/PizzaApp folder, to link the packages to your react-native app run:
npx zx scripts/install-workspace-packages-in-target.mjs ~/Code/PizzaAppor if you want to watch for rebuilds and automatically link them:
npx nx watch --all -- "npx zx scripts/install-workspace-packages-in-target.mjs ~/Code/PizzaApp:::info
Make sure that the path to your app is an absolute path and not a relative one (i.e. ~/Code/PizzaApp instead of ../PizzaApp)
:::
:::note
You must have already run yarn in your app folder (e.g. ~/Code/PizzaApp) before running this script because is copies over the built js files from each reactotron library into the app's node_modules folder.
:::
Adding a new Reactotron plugin to `./lib`
If you have a new plugin to contribute to the Reactotron ecosystem, you can start a new workspace by running the generate plugin script:
yarn generate:plugin my-pluginThis will create the necessary directory in ./lib and get you started with a template. You'll want to implement your configuration and plugin in ./lib/reactotron-my-plugin/reactotron-my-plugin.ts.
Keep in mind this won't add the workspace to .circleci/config.yml, that must still be done manually when ready.
Prepare for a pull request
Before you open a pull request, please ensure that the following command runs without errors:
yarn build-and-test:localOnce you've made your changes and verified your local codebase passes all tests and linters, you'll need to commit them and push them to your fork. Then, you can open a pull request to the main repo.
File: docs/contributing/monorepo.md
Monorepo Structure
Yarn 4
This project uses yarn 4 workspaces to manage the monorepo. It hoists dependencies shared across workspaces to the root of the project, and allows for a single yarn.lock file to be used for all packages.
As long as you have yarn 1 installed, you will use the yarn 4 automatically using the version specified in .yarnrc.yml.
nodeLinker
Yarn 4 philosophically has chosen to go in a direction where dependencies should be vendored and checked into the repo. This is a departure from the way yarn 1 and npm work, where dependencies are installed in the node_modules directory. They call this Plug'n'Play, and it is enabled by default in yarn 4.
However, this can behavior can be modified through the nodeLinker value in yarnrc.yml to use node-modules, which is the normal behavior for yarn 1 and npm.
Since yarn 1 is no longer being actively worked on, so we are using yarn 4 with the nodeLinker set to node-modules.
Patches
Yarn 4 has a patching feature similar to patch-package through yarn patch . You can read more about it here: https://yarnpkg.com/cli/patch
Nx
This project uses nx as a task runner for the monorepo. Nx has many features, including build integration, dependency graph visualization, and more. You can read more about it here: https://nx.dev/
Tasks
npx nx run-many is a common command used to run a command across all workspaces. For example, npx nx run-many --target=lint will run the lint target in all workspaces. Targets are like npm scripts, but they can be run across multiple workspaces.
These are aliased as yarn scripts in the root package.json file. For example, yarn lint will run the lint target in all workspaces.
Affected
Nx also has a affected command that will run a command on all workspaces that have been affected by a change. For example, npx nx affected:lint will run the lint target in all workspaces that have been affected by a change.
project.json
Each workspace needs a project.json file to register it with nx. This file is used to define the targets for the workspace, and to define the dependencies between workspaces.
Any script in the scripts section of the package.json file will be registered as a target in nx. For example, the lint script in the package.json file will be registered as a target in nx.
Additionally, you can set target defaults in the root nx.json file.
Task Caching
Nx has a feature called task caching that will cache the output of a task. Nx can fingerprint whether a task like build has already run and not changed. The cache is stored in the node_modules/.cache/.nx directory. If you want to clear the cache, you can delete the node_modules/.cache/.nx directory.
Linting
Eslint allows for having a parent config file and then extending it in child config files. This project has a generic Typescript linting setup at the top, and then child projects can extend it and add their own rules (for React, Electron, etc.). Read more about it here: https://eslint.org/docs/latest/user-guide/configuring/configuration-files
Typescript
In order for typescript-eslint to work, we use a tsconfig.base.json in the parent directory, and then each workspace extends that base with it's own tsconfig.json file. But in the parent eslint config, you must declare the location of all the tsconfig.json files in a glob pattern. You can read more here: https://typescript-eslint.io/linting/typed-linting/monorepos/#one-tsconfigjson-per-package-and-an-optional-one-in-the-root
Common Gotchas
In order to prevent nested folders in our dist directory, "rootDir": ".", needs to be specified in the workspace tsconfig.json to avoid the parent tsconfig.base.json from being used.
Prettier
Ignore file
Prettier has a .prettierignore file that is used to ignore files. This file is used in addition to the .gitignore file. This is useful for ignoring files that are not checked into git, but still need to be ignored by prettier. Unfortunately, there is no way to extend the .gitignore file in the .prettierignore file, so we have to duplicate the entries. See copy-prettier-ignore in the root package.json script.
File: docs/contributing/releasing.md
Releasing
Note: this is a document primarily intended for maintainers at Infinite Red.
High Level Overview
Git Tags
Git tags are used to mark a commit for a release. The format of the git tag is <workspace>@<version> (e.g. [email protected]).
A release commit and a git tag is created for every affected workspace on a release branch: master, beta, or alpha.
Versions for a workspace are determined by the version in the workspace package.json.
{
"name": "reactotron-app",
"version": "3.0.0"
}Would correspond to a git tag [email protected].
Release Branches
In CI, on every commit to a release branch, a task is run to determine what changed between the current commit and the last commit. If a workspace has changed, then a new release commit and tag will be added to the release branch.
So if 3 workspaces change, then 3 release commits are added to the release branch and 3 git tags are created.
Releasing Artifacts
When a new git tag is published, CI will build and publish the workspace artifacts for that tag.
As of writing this, we have two workspaces: apps and lib.
Artifacts from lib workspaces are published to npm.
Artifacts from app workspaces are published to GitHub releases.
How Releases Are Implemented
Releases are implemented using:
- nx to manage workspaces and determine which workspaces have changed between commits
- jscutlery/semver to bump package.json versions, create release commits, and create git tags
- CircleCi to run the release tasks
Nx
nx has this concept of tasks, which are like npm scripts defined in a project.json file.
To be consistent in the jscutlery/semver docs, we have defined semantic release target task in the projects.json file as version.
This can be run with npx nx run :version (e.g. npx nx run app:version).
However, normally this will be run using npx nx affected --target version --parallel=1 --base HEAD~1 --head HEAD. The affected command from nx will run the version task for the workspaces that have changed between the branches current commit and the last commit.
`jscutlery/semver`
To determine the new version, jscutlery/semver will look at the git tags on the repo, and look for an existing tag :<version> (e.g. app:1.0.0). If it finds one, it will increment the version number based on the existing git tags.
Settings for this plugin are managed using the nx.json and project.json files in a workspace.
CircleCi
CircleCi is used to run the release tasks. The config.yml file is located in the .circleci folder.
CircleCi is configured to check for whether new release commits and tags are needed on every commit to a release branch: master, beta, and alpha.
Once a new release tag is created, CircleCi will run a job to publish the artifacts for the workspace.
npm Authentication (Trusted Publishing via OIDC)
npm packages are published using npm Trusted Publishing โ CircleCI mints a short-lived OIDC token that Yarn 4.14+ exchanges for a single-use publish token. There is no long-lived NPM_TOKEN to rotate.
How it works in CI
The release_package job in .circleci/config.yml runs two steps:
- Mint npm OIDC token โ runs
circleci run oidc get --claims '{"aud":"npm:registry.npmjs.org"}'and exports the result asNPM_ID_TOKEN. - Release to npm and github โ
yarn release:artifacts $CIRCLE_TAGcallsscripts/release.artifacts.mjs. The script (not Yarn) exchangesNPM_ID_TOKENfor a single-use npm publish token via a directPOSTtohttps://registry.npmjs.org/-/npm/v1/oidc/token/exchange/package/<name>, then exposes the result asNPM_TOKENso.yarnrc.yml'snpmAuthToken: "${NPM_TOKEN-}"picks it up at config-load time. Finally it invokesyarn npm publish.
The reason the script does the exchange rather than Yarn: Yarn 4.14.1's yarn npm publish gates the OIDC code path on GITHUB_ACTIONS || GITLAB_CI, even though its getOidcToken helper already handles CIRCLECI. The companion fix is tracked upstream at yarnpkg/berry#7122. Once Yarn ships the one-line gate fix and we bump, the exchange block in release.artifacts.mjs can be deleted and yarn npm publish will pick up NPM_ID_TOKEN directly.
The job still requires the reactotron-npm-context CircleCI context for $GITHUB_TOKEN (used to create the GitHub release).
Adding a trusted publisher to a new package
When publishing a new reactotron-* package, configure its Trusted Publisher on npm before the first release tag, otherwise the publish will fail with a "no trusted publisher configured" error.
For each package:
- Navigate to
https://www.npmjs.com/package//access. - Scroll to "Trusted Publisher" and select CircleCI.
- Fill in the org/project/context IDs (ask a maintainer for current values; they live in the CircleCI project settings, not in this repo).
- Save.
npm trust (npm v11.10.0+) supports batch configuration after npm login. See npm bulk trusted publishing config.
Out-of-scope packages
reactotron-appis published as GitHub release artifacts, not to npm.reactotron-mcpis private ("private": true) and intentionally not on npm. An unrelatedreactotron-mcppackage bysteve228ukexists on npm โ that is his own project and is not affiliated with Infinite Red.
File: docs/plugins/apisauce.md
title: Apisauce
reactotron-apisauce
Apisauce is a lightweight wrapper around the fantastic Axios networking library.
Installing
npm i --save-dev reactotron-apisauceyarn add reactotron-apisauce -DConfiguration
To use the apisauce plugin, add the additional plugin on the import line.
import apisaucePlugin from "reactotron-apisauce" //Then plug it in when you configure Reactotron.
Reactotron.configure()
.use(
apisaucePlugin({
// ignoreContentTypes: /^(image)\/.\*$/i // <--- a way to skip printing the body of some requests (default is any image)
})
) // <-- here we go!!!
.connect()Usage
Next, wherever you create api functions for you application, bring in Reactotron and attach the monitor to your apisauce instance. Apisauce has a feature where you can attach a handler to watch.
- To view all requests/response flowing through your api
//for web
import Reactotron from "reactotron-react-js"
//for mobile
import Reactotron from "reactotron-react-native"
api.addMonitor(Reactotron.apisauce)- To view only the requests/response that have a problem
//if you just wanted to track on 500's
api.addMonitor((response) => {
if (response.problem === "SERVER_ERROR") Reactotron.apisauce(response)
})File: docs/plugins/async-storage.md
title: AsyncStorage
AsyncStorage
The asyncStorage plugin is part of reactotron-react-native which allows you to track AsyncStorage on React Native.
Usage
To use the Async Storage plugin, add the additional plugin on the import line.
import Reactotron, { asyncStorage } from "reactotron-react-native"Next, add it as a plugin to Reactotron.
Reactotron.configure()
.use(asyncStorage()) // <--- here we go!
.connect()And you're done! Now you can see your AsyncStorage in Reactotron.
Advanced Usage
asyncStorage() also accepts an object with an ignore key. The value is an array of strings you would like to prevent sending to Reactotron.
asyncStorage({
ignore: ["secret"],
})