• Stars
    star
    267
  • Rank 153,621 (Top 4 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created about 8 years ago
  • Updated almost 5 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Redux DevTools for production (web and React Native) with a highly flexible API.

Redux Remote DevTools for Production

Receive logs/reports from production and get them replicated with Redux DevTools extension (or other monitoring apps). Unlike other solutions (like Remote Redux DevTools), it aims to be optimized for production and suitable for different use cases (see the options). Even though it's designed to be used together with remotedev-server, it can be easily integrated with any other server or serverless architectures.

Installation

npm install --save redux-remotedev

Optionally, install isomorphic fetch polyfill for Node and unsupported browsers:

npm install --save isomorphic-fetch es6-promise

Usage

Just add the store enhancer to your Redux store:

import remotedev from 'redux-remotedev';
import 'isomorphic-fetch'; // include in the main script once
createStore(reducer, remotedev({ sendTo: 'http://localhost:8000' }));

More detailed example:

import { createStore, applyMiddleware, compose } from 'redux';
// import thunk from 'redux-thunk';
import remotedev from 'redux-remotedev';
import 'isomorphic-fetch';
import reducer from '../reducers';

export default function configureStore(initialState) {
  const enhancer = compose(
    // applyMiddleware(thunk),
    remotedev({
      sendTo: 'http://localhost:8000',
      sendOn: 'SOME_ACTION',
      maxAge: 50
    })
  );
  const store = createStore(reducer, initialState, enhancer);
  return store;
}

See also remotedev-server for integrating the server part.

API

remotedev(options)

At least sendTo or sender option should be present.

Enhancer's options

sendTo

string - url of the remote server where logs will be posted.

Example:

createStore(reducer, remotedev({ sendTo: 'http://localhost:8000' }))
sendOn

string or array of strings - action type(s) dispatching of which will trigger sending the history log. Useful for analytics or for triggering sending explicitly (for example, from a report form or when an exception is caught).

Example:

createStore(reducer, remotedev({
  sendTo: 'http://localhost:8000',
  sendOn: 'SOME_ACTION_ERROR' // or array: ['FETCH_ERROR', 'TARGETED_ACTION']
}))
sendOnCondition

function (state, action) - when returns true (the condition is satisfied), the report will be sent. Unlike sendOn, here you can check not only the action type, but the whole action object and also the state object. Another difference is that by default the report will be sent only first time the condition is satisfied. If you want to send it multiple times, set options.sentOnCondition to false in beforeSending function.

Example:

createStore(reducer, remotedev({
  sendTo: 'http://localhost:8000',
  sendOnCondition: (action, state) => state.counter.count === 5,
  // sendOnCondition: (action, state) => state.user.id !== undefined,
  // sendOnCondition: (action, state) => action.user.id !== undefined,
  // sendOnCondition: (action, state) => action.type === 'SOME_ACTION'
}))
sendOnError

boolean - when set to true, will listen for all exceptions from console.error, window.onerror and ErrorUtils (for React Native). When an exception occurs in the app, will send a report including all the details about the exception (also as a Redux action to see the exact failed point when debugging).

sendingStatus

object of functions

  • started(report, store): called when attempts to send a report. The report object is passed to the function. You can use it to show a loading indicator for your report dialog.
  • done(reportId, store): called when server returned a success response. The stored report id is passed, so you can generate an url like http://hostname/?remotedev_report=${id} (where hostname can be your development or production domain) to replicate the reported issue. When opening this url on a site with the extension included, the exact history state will be applied to your Redux store.
  • failed(error, store): called when server returned an error response or when fetch failed. The error message is passed.

Example:

createStore(reducer, remotedev({
  sendTo: 'http://localhost:8000',
  sendingStatus: {
    started(report) {
      console.log('Sending a report', report);
    },
    done(reportId) {
      console.info(
        'The report sent. ' +
        'Open this url to replicate: ' +
        'http://localhost:3000/?remotedev_report=' + reportId
       );
    },
    failed(error, store) {
      console.warn('Report cannot be sent.', error);
      // store.dispatch({ type: 'REPORT_FAILED` });
    }
  }
}))
beforeSending

function(report, sender, options) - called before attempting to send a report, so you can show a dialog and append some data to the report object.

createStore(reducer, remotedev({
  sendTo: 'http://localhost:8000',
  beforeSending(report, send) {
    send({ ...report, title: prompt('Please describe what happened') });
  }
}))
headers

object - custom headers to inject into the sending request additionally to { 'content-type': 'application/json' } (which can be overwritten).

Example:

createStore(reducer, remotedev({
  sendTo: 'http://localhost:8000',
  headers: {
    'content-type': 'application/javascript', // to use JSON-P instead
    'grant_type': 'client_credentials', // some systems may require credentials
    'client123': 'secret123' // custom header `'<Client-Id>': '<Secret>'`
  }
}))
sender

function - custom function used to post the data. Usually, you don't need to specify it. By default fetch function will be used, so make sure to include the polyfill in case you're not targeting for React Native only and want to support all browsers (add import 'isomorphic-fetch' in the consuming code).

Example:

createStore(reducer, remotedev({
  sendTo: 'http://localhost:8000',
  sender: (data, sendTo) => {
    fetch(sendTo, {
      method: 'POST',
      headers: {
        'content-type': 'application/json'
      },
      body: JSON.stringify(data)
    })
  }
}))

You can also just log the data instead of posting (for example when included a monitoring service):

createStore(reducer, remotedev({
  sender: (data) => {
    console.warn(data);
  }
}))
maxAge

number - maximum allowed actions to be stored in the history tree, the oldest actions are removed once maxAge is reached. Default is 30.

To restore the history tree, preloadedState will be added to the log, which represents the state for the committed (removed) action.

In case you want to send all actions from the beginning, set maxAge to Infinity, but it's not recommended as having lots of actions with large payloads can consume a lot of RAM and can cause CPU spikes when serializing the data.

withState

boolean - when set to true, will include also the current state for every action. It's not recommended as the state object can grow too large, and it's better to reconstruct states by recomputing actions.

every

boolean - when set to true, every dispatched action will be posted. It's not recommended as there will be lots of requests and serialization can affect the application's performance significantly.

onlyState

boolean - when set to true, will send only the current state (as preloadedState) without action list. Useful when only reproducing the state without time traveling would be enough. It's recommended for gaining the performance as nothing will be stored for feature posting.

actionsBlacklist

string or array of strings as regex - actions types to be omitted from sending.

Example:

createStore(reducer, remotedev({
  sendTo: 'http://localhost:8000',
  actionsBlacklist: 'SOME_ACTION'
  // or actionsBlacklist: ['SOME_ACTION', 'SOME_OTHER_ACTION']
  // or just actionsBlacklist: 'SOME_' to omit both
}))
actionsWhitelist

string or array of strings as regex - only actions with indicated types will be sent. Use the same as in the example above. If specified, actionsBlacklist is ignored.

actionSanitizer

function which takes the action object and returns it back. Used to sanitize sensitive data (for example credit cards numbers containing in the payload). Also it's used to strip large payloads (like image blobs) in order to make serializing faster.

Example:

createStore(reducer, remotedev({
  sendTo: 'http://localhost:8000',
  actionSanitizer: (action) => (
   action.type === 'FILE_DOWNLOAD_SUCCESS' && action.data ?
   { ...action, data: '<<LONG_BLOB>>' } : action
  )
}))
stateSanitizer

function which takes the state and returns it back. As well as actionSanitizer, it's used to sanitize sensitive data and to strip large payloads.

Example:

createStore(reducer, remotedev({
  sendTo: 'http://localhost:8000',
  stateSanitizer: (state) => state.data ? { ...state, data: '<<LONG_BLOB>>' } : state
}))

Also you can specify alternative values right in the reducer (in the state object) by adding toJSON function:

In the example bellow it will always send { conter: 'sensitive' }, regardless of the state value:

function counter(state = { count: 0, toJSON: () => ({ conter: 'sensitive' }) }, action) {
  switch (action.type) {
    case 'INCREMENT': return { count: state.count + 1 };
    default: return state;
  }
}

You could also alter the value. In the example below when state is { count: 1 }, we'll send { counter: 10 } (notice we don't have an arrow function this time to use the object's this):

function counter(
  state = { count: 0, toJSON: function (){ return { conter: this.count * 10 }; } },
  action
) {
  // ...
}

In case you want to sanitize only specific values, use:

function reducer(
  state = {
    v1: 1, v2: 2, v3: 3, v4: 4,
    toJSON: function (){
      return { ...this, v2: 'sanitized', v4: 'sanitized' };
      // Or return Object.assign({}, this, { v2: 'sanitized', v4: 'sanitized' })
    }
  },
  action
) {
  // ...
}
stringifyReplacer

function or array - a function that alters the behavior of the stringification process, or an array of String and Number objects that serve as a whitelist for selecting the properties of the value object to be included in the JSON string. As a function, it takes two parameters, the key and the value being stringified. Also useful if state is not plain object.

Example (for converting mori data structures):

createStore(reducer, remotedev({
  sendTo: 'http://localhost:8000',
  stringifyReplacer: (key, value) => (
    value && mori.isMap(value) ? mori.toJs(value) : value
  )
}))
Info

Add these optional options for better analytics: title, description, screenshot, version, userAgent, user, meta.

Example:

createStore(reducer, remotedev({
  sendTo: 'http://localhost:8000',
  sendOn: 'SOME_ACTION',
  title: 'Nothing works',
  description: 'It was supposed to be an useless report, but it\'s not ;)',
  screenshot: 'add here an image blob or an url of the stored screenshot',
  version: 'app version to git checkout that release tag',
  appId: 'id to identify the application',
  instanceId: 'id to identify the store in case there are multiple stores',
  userAgent: Platform.Version, // On React Native with: import { Platform } from 'react-native';
  // for browsers userAgent is detected automatically, so no need to specify it explicitely.
  user: {
    id: 'user_id',
    name: 'User Name',
    email: 'user@email',
    photo: 'url or image blob' 
  },
  // or just a string:
  // user: 'user id or user name to identify him',
  meta: 'everything else you want to send'
}))

Exclude the enhancer from development builds

Usually you want to send logs only for production, so you should either use it under a flag excluding from development or you use our helper to have no-op when process.env.NODE_ENV !== 'production':

import remotedev from 'redux-remotedev/productionOnly'

Exclude the enhancer from production builds

If you want to receive logs only from devs, not to affect the performance in production, you can use our helper to have the module stripped when process.env.NODE_ENV === 'production':

import remotedev from 'redux-remotedev/developmentOnly'

LICENSE

MIT

Created By

If you like this, follow @mdiordiev on twitter.

More Repositories

1

redux-devtools-extension

Redux DevTools extension.
JavaScript
13,500
star
2

remote-redux-devtools

Redux DevTools remotely.
JavaScript
1,804
star
3

crossbuilder

Building web, Electron, Cordova and Chrome apps, and cross-browser extensions with React, Redux and Webpack. "Write once, deploy everywhere" concept in practice.
JavaScript
483
star
4

mobx-remotedev

MobX DevTools extension
JavaScript
327
star
5

remotedev-server

Connect Redux DevTools extension to a remote app.
JavaScript
183
star
6

remotedev-app

Remote Redux DevTools monitor app.
JavaScript
158
star
7

remotedev

Remote debugging for any flux architecture.
JavaScript
143
star
8

atom-redux-devtools

Redux DevTools Atom package
CoffeeScript
140
star
9

redux-devtools-filter-actions

Redux DevTools composable monitor with the ability to filter actions.
JavaScript
77
star
10

social-expert

Master your GitHub notifications by priority and weight.
JavaScript
59
star
11

redux-devtools-instrument

Redux DevTools instrumentation. Moved to redux-devtools monorepo.
JavaScript
41
star
12

remotedev-serialize

Serialize "unserializable" data and parse it back.
JavaScript
25
star
13

redux-notify

Notify when specified redux actions are dispatched.
JavaScript
17
star
14

devui

Reusable React components for building Redux Devtools monitors.
JavaScript
16
star
15

redux-devtools-test-generator

Generate tests right in Redux DevTools.
JavaScript
14
star
16

momentjs-datetimepicker

jQuery Date and Time Picker using Momentjs format and translations.
JavaScript
14
star
17

browser-redux-sync

Keep redux states in sync for browser extensions and apps.
JavaScript
13
star
18

react-chat

WIP
JavaScript
12
star
19

react-switcher

Stateless React switcher component to toggle container states.
JavaScript
7
star
20

crossmessaging

Crossextension messaging.
JavaScript
6
star
21

chrome-storage-local

Use the same api for chrome.storage.local as for localStorage.
JavaScript
5
star
22

horizon-remotedev

Horizon DevTools extension.
JavaScript
4
star
23

browser-redux-bg

Messaging library for Cross-browser extensions and Chrome apps.
JavaScript
3
star
24

remotedev-utils

Moved to https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-core
JavaScript
2
star
25

zalmoxisus.github.io

HTML
2
star
26

boilerplate

JavaScript
1
star
27

remotedev-slider

Redux DevTools Slider monitor with remote reports
JavaScript
1
star