Remote Debugging @ngrx/store with Ionic

Yes, you can do on-device debugging with Ionic!

Most developers that have used Redux or tools that follow the Redux pattern will be able to wax lyrical about the fantastic development experience it is. It does make debugging pretty breezy — even in more complex applications. While Redux is typically associated with React, it’s framework agnostic and can fit pretty easily into most frameworks including Angular and, by association, Ionic.

@ngrx/platform is an Angular spin on the Redux pattern that lets you leverage the awesome power of the remote redux devtools. If you wire @ngrx/store and @ngrx/store-devtools up to an Ionic app debugging works pretty well out of the box in Chrome using ionic serve. The extension picks up your store and you get to dispatch actions and time travel around to your heart’s content.

However, if you run your app on a device you quickly find that you’re a bit more out of luck when it comes to debugging. You might write an effect that console.logs an action and the state with every dispatch but it’s not a particularly elegant or enjoyable debugging experience.

Becoming frustrated with this I did some searching and came across this gist written by rob3c which worked pretty well with only some minor tweaks — so full credit to him for getting this working.

Too much text without a break. Relax your eyes with these rolling fields from [Skitterphoto]( on [Pexels]( Too much text without a break. Relax your eyes with these rolling fields from Skitterphoto on Pexels

Receiving Actions from the Devtools

Interaction with the Remote DevTools is a two-way process. The extension send commends that the user puts in (such as time-travelling; commits and rollbacks; and requests to dispatch actions) app sends the extension updates of new actions that come in as well as the current state. The above snippet is the first half of this process — actions received from the extension are sent to the store.

For example, if we use remote devtools to dispatch the following arbitrary action:

      type: 'MY_ACTION', payload: 1

The listenerWrapper function receives the following change to dispatch to the application reducer:

      type: "ACTION",
      action: "{type: 'MY_ACTION', payload: 1}",
      instanceId: "0ambaorvwb65",
      payload: "{type: 'MY_ACTION', payload: 1}"

Note, I found from the original gist that these sorts of commands would not work if the devtools were open when the application loaded — I’d have to restart them each time. This line was a fix for that issue:

setTimeout(() => listenerWrapper({type: 'START'});

Sending Actions to the Devtools

The above class will be what sends actions that occur in the app back to the Remote DevTools extension. Ensure you update the hostname property with the IP of you development machine. Alternatively, you can use webpack to inject a value in such as process.env.DEVTOOLS_HOST during the build.

Connecting Everything to the App

Now that we’ve got our proxy to communicate with the devtools, we need to shim it in where @ngrx/store-devtools expects it to live — the global devToolsExtension or __REDUX_DEVTOOLS_EXTENSION__ keys depending on what version you use.

Starting and Configuring the Devtools

Before you start up the app, you’ll need to install and run the remmotedev server for the app to communicate with. Run npm i -g remotedev-server and then start it up with remotedev --hostname=<your-machine-ip> --port=8000.

To open the remote devtools, right click the Redux Devtools extension icon in chrome and click “Open Remote DevTools”. You’ll need to go to “Settings” down the bottom and tick “Use custom (local) server” and then fill in the hostname and port to match what you put in remote-devtools-connection.ts and in the remotedev command above.

You can now start the app as normal using ionic run android --device or ionic run ios.

Once the app is running, you should start see actions coming into the inspector as normal. If you opened the app first before opening the remote devtools, you won’t see any state until a new action is sent from the app.

For some Android devices, if you are using Chrome Inspector, you may need to forward the 8000 port. To do this, navigate to about://inspect in chrome on your development machine and then next to “Discover USB Devices” select port forwarding. Forward 8000 to localhost:8000 and ensure you check “Enable Port Forwarding” before hitting done.

🎉 Congratulations! You can now inspect your store, dispatch actions and get your time-travelling McFly hat on.