Recently I was working on Ionic app that was built with Angular. The application uses NGRX for state management. I wanted to debug the state (i.e inspect actions, and state ..etc) while application is running on emulator. I expected that by simply running redux dev tools from chrome that it will magically work out of the box, and straight away, but unfortunately this was not the case.
Looking around for sometime I stumbled upon a precious article that was explaining how to put everything together.
Unfortunately the article is outdated, but through some further search and playing around, I managed to make everything work.
I thought to share details here to help anyone who might be looking for a solution to same exact issue.
Step 1:
install NGRX store dev toolsStep 2:
Create 2 files to handle connection between your application and Redux remote dev tool
File1:
remote-devtools-connection.ts
import { ReduxDevtoolsExtensionConnection } from '@ngrx/store-devtools/src/extension'
export class RemoteDevToolsConnectionProxy implements ReduxDevtoolsExtensionConnection {
constructor(public remotedev: any, public instanceId: string) {}
init(state?: any): void {
console.log('Socket was initiated', state)
}
error(anyErr: any): void {
console.error('Socket Error', anyErr)
}
subscribe(listener: (change: any) => void): any {
const listenerWrapper = (change: any) => {
listener(change)
}
this.remotedev.subscribe(listenerWrapper)
// Hack fix for commit/time-travelling etc. if the devtools are already open
setTimeout(() => listenerWrapper({ type: 'START' }))
}
unsubscribe(): any {
// HACK fix bug in @ngrx/store-devtools that calls this instead of returning
// a lambda that calls it when their Observable wrapper is unsubscribed.
return () => this.remotedev.unsubscribe(this.instanceId)
}
send(action: any, state: any): any {
this.remotedev.send(action, state)
// Never called
}
}
File2 (depends on File1):
remote-devtools-proxy.ts
import {
ReduxDevtoolsExtension,
ReduxDevtoolsExtensionConfig,
ReduxDevtoolsExtensionConnection
} from '@ngrx/store-devtools/src/extension'
import { connect } from 'remotedev/lib/devTools'
import { RemoteDevToolsConnectionProxy } from './remote-devtools-connection'
export class RemoteDevToolsProxy implements ReduxDevtoolsExtension {
remotedev: any = null
defaultOptions = {
realtime: true,
autoReconnect: true,
connectTimeout: 20000,
ackTimeout: 10000,
secure: true
}
constructor(defaultOptions: Object) {
this.defaultOptions = {
...this.defaultOptions,
...defaultOptions
}
console.log('Socket config', this.defaultOptions)
}
connect(
options:
| {
shouldStringify?: boolean
instanceId: string
} & ReduxDevtoolsExtensionConfig
): ReduxDevtoolsExtensionConnection {
const connectOptions = Object.assign(this.defaultOptions, options)
this.remotedev = connect(connectOptions)
const connectionProxy = new RemoteDevToolsConnectionProxy(
this.remotedev,
connectOptions.instanceId
)
return connectionProxy
}
send(action: any, state: any): any {
this.remotedev.send(action, state)
}
}
File3 (depends on File2): make sure to include this file in your app based on your environment setup. Like direct import, or webpack include .. etc
The variables REMOTE_DEV_HOST
& REMOTE_DEV_PORT
can be environment dependent, or hardcoded. You can hardcode them at least to make sure everything works as expected. However the most important point it to use "EXACT" same IP, and PORT in all following steps
index.ts
import { RemoteDevToolsProxy } from './remote-devtools-proxy'
declare const REMOTE_DEV_HOST: string
declare const REMOTE_DEV_PORT: number
if (!window['devToolsExtension'] && !window['__REDUX_DEVTOOLS_EXTENSION__']) {
console.log('!!!!!! REDUX INSPECTION HAS STARTED !!!!!')
const remoteDevToolsProxy = new RemoteDevToolsProxy({
// Needs to match what you run `remotedev` command with and
// what you setup in remote devtools local connection settings
hostname: REMOTE_DEV_HOST,
port: REMOTE_DEV_PORT,
connectTimeout: 300000, // extend for pauses during debugging
ackTimeout: 120000, // extend for pauses during debugging
secure: false // dev only
})
// support both the legacy and new keys, for now
window['devToolsExtension'] = remoteDevToolsProxy
window['__REDUX_DEVTOOLS_EXTENSION__'] = remoteDevToolsProxy
} else {
// handle case outside real device, or emulator
}
- Step 3: in your angular module make sure you include store dev module
@NgModule({
imports: [CommonModule, StoreDevtoolsModule.instrument({ maxAge: 100 })]
})
Step 4:
install @redux-devtools/cliStep 5:
add a script to start redux devtools server which will listen to state, and action changes in your package.json
scripts:
{"remote-dev":"redux-devtools --hostname=ADD_IP_FROM_PREVIOUS_STEPS --port=ADD_PORT_FROM_PREVIOUS_STEPS --wsEngine=ws --logLevel=3"}
and run it in a separate terminal tab/window
- Step 6: You may get some error about global is not defined, and in this case add following to polyfill.ts (this is generated by default in your root folder) in your Angular app (more info can be found here)
polyfill.ts
(window as any).global = window
- Step 7: open chrome, and right click redux extension to open remote dev tools
- Step 8: connect to your host from redux remote settings (UX is bad as there is no feedbad if connection succeeds, or fails). Howevwer ater successful connection you should see the store visible in your dev tools
Happy Hacking ...
Top comments (0)