Repository: reduxjs/redux-toolkit
Pull request #384 (2020-02-21 20:32:37)

Fork redux-devtools-extension
Per #380 , I've gone ahead and converted the `redux-devtools-extension` package to TS and dropped in the one entry point file that we actually use.  This appears to improve the tree shaking behavior overall.

netlify[bot]: Deploy preview for *redux-starter-kit-docs* ready!

Built with commit f0fb67607d88b9517605fbff269e81d264e67726

https://deploy-preview-384--redux-starter-kit-docs.netlify.com
github-actions[bot]: **Size Change:** -38 B (0%) 

**Total Size:** 56.7 kB

| Filename | Size | Change | |
|:--- |:---:|:---:|:---:|
| `dist/redux-toolkit.cjs.development.js` | 7.86 kB | +90 B (1%) |  |
| `dist/redux-toolkit.cjs.production.min.js` | 3.84 kB | +65 B (1%) |  |
| `dist/redux-toolkit.esm.js` | 7.68 kB | +100 B (1%) |  |
| `dist/redux-toolkit.umd.js` | 26.9 kB | -184 B (0%) |  |
| `dist/redux-toolkit.umd.min.js` | 10.2 kB | -109 B (1%) |  |

<details><summary>ℹ️ <strong>View Unchanged</strong></summary>

| Filename | Size | Change | |
|:--- |:---:|:---:|:---:|
| `dist/index.js` | 149 B | 0 B |  |


</details>



<a href="https://github.com/preactjs/compressed-size-action"><sub>compressed-size-action</sub></a>
markerikson: Huh. Surprised the CJS prod size went up, but we'll see how it works out.

Patch:
diff --git a/etc/redux-toolkit.api.md b/etc/redux-toolkit.api.md
index f90952e0..a4ac2c2d 100644
--- a/etc/redux-toolkit.api.md
+++ b/etc/redux-toolkit.api.md
@@ -5,13 +5,13 @@
 ```ts
 
 import { Action } from 'redux';
+import { ActionCreator } from 'redux';
 import { AnyAction } from 'redux';
 import { default as createNextState } from 'immer';
 import { createSelector } from 'reselect';
 import { DeepPartial } from 'redux';
 import { Dispatch } from 'redux';
 import { Draft } from 'immer';
-import { EnhancerOptions } from 'redux-devtools-extension';
 import { Middleware } from 'redux';
 import { Reducer } from 'redux';
 import { ReducersMapObject } from 'redux';
diff --git a/package-lock.json b/package-lock.json
index b7eab20c..d859ae83 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -6856,11 +6856,6 @@
         "symbol-observable": "^1.2.0"
       }
     },
-    "redux-devtools-extension": {
-      "version": "2.13.8",
-      "resolved": "https://registry.npmjs.org/redux-devtools-extension/-/redux-devtools-extension-2.13.8.tgz",
-      "integrity": "sha512-8qlpooP2QqPtZHQZRhx3x3OP5skEV1py/zUdMY28WNAocbafxdG2tRD1MWE7sp8obGMNYuLWanhhQ7EQvT1FBg=="
-    },
     "redux-immutable-state-invariant": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/redux-immutable-state-invariant/-/redux-immutable-state-invariant-2.1.0.tgz",
diff --git a/package.json b/package.json
index d0afc996..8c83104a 100644
--- a/package.json
+++ b/package.json
@@ -42,7 +42,7 @@
     "build": "tsdx build --format cjs,esm,umd --name redux-toolkit && api-extractor run --local",
     "dev": "tsdx watch  --format cjs,esm,umd",
     "format": "prettier --write \"src/*.ts\" \"**/*.md\"",
-    "format:check": "prettier --list-different \"src/*.ts\" \"**/*.md\"",
+    "format:check": "prettier --list-different \"src/*.ts\" \"docs/*/**.md\"",
     "lint": "tsdx lint src",
     "prepare": "npm run lint && npm run format:check && npm test && npm run build-ci",
     "test": "tsdx test"
@@ -58,7 +58,6 @@
     "immer": "^4.0.1",
     "nanoid": "^2.1.11",
     "redux": "^4.0.0",
-    "redux-devtools-extension": "^2.13.8",
     "redux-immutable-state-invariant": "^2.1.0",
     "redux-thunk": "^2.3.0",
     "reselect": "^4.0.0"
diff --git a/src/configureStore.ts b/src/configureStore.ts
index f0078f61..907641be 100644
--- a/src/configureStore.ts
+++ b/src/configureStore.ts
@@ -16,7 +16,7 @@ import {
 import {
   composeWithDevTools,
   EnhancerOptions as DevToolsOptions
-} from 'redux-devtools-extension'
+} from './devtoolsExtension'
 
 import isPlainObject from './isPlainObject'
 import {
diff --git a/src/devtoolsExtension.ts b/src/devtoolsExtension.ts
new file mode 100644
index 00000000..88445aa2
--- /dev/null
+++ b/src/devtoolsExtension.ts
@@ -0,0 +1,201 @@
+import { Action, ActionCreator, StoreEnhancer, compose } from 'redux'
+
+/**
+ * @public
+ */
+export interface EnhancerOptions {
+  /**
+   * the instance name to be showed on the monitor page. Default value is `document.title`.
+   * If not specified and there's no document title, it will consist of `tabId` and `instanceId`.
+   */
+  name?: string
+  /**
+   * action creators functions to be available in the Dispatcher.
+   */
+  actionCreators?: ActionCreator<any>[] | { [key: string]: ActionCreator<any> }
+  /**
+   * if more than one action is dispatched in the indicated interval, all new actions will be collected and sent at once.
+   * It is the joint between performance and speed. When set to `0`, all actions will be sent instantly.
+   * Set it to a higher value when experiencing perf issues (also `maxAge` to a lower value).
+   *
+   * @default 500 ms.
+   */
+  latency?: number
+  /**
+   * (> 1) - maximum allowed actions to be stored in the history tree. The oldest actions are removed once maxAge is reached. It's critical for performance.
+   *
+   * @default 50
+   */
+  maxAge?: number
+  /**
+   * - `undefined` - will use regular `JSON.stringify` to send data (it's the fast mode).
+   * - `false` - will handle also circular references.
+   * - `true` - will handle also date, regex, undefined, error objects, symbols, maps, sets and functions.
+   * - object, which contains `date`, `regex`, `undefined`, `error`, `symbol`, `map`, `set` and `function` keys.
+   *   For each of them you can indicate if to include (by setting as `true`).
+   *   For `function` key you can also specify a custom function which handles serialization.
+   *   See [`jsan`](https://github.com/kolodny/jsan) for more details.
+   */
+  serialize?:
+    | boolean
+    | {
+        date?: boolean
+        regex?: boolean
+        undefined?: boolean
+        error?: boolean
+        symbol?: boolean
+        map?: boolean
+        set?: boolean
+        function?: boolean | Function
+      }
+  /**
+   * function which takes `action` object and id number as arguments, and should return `action` object back.
+   */
+  actionSanitizer?: <A extends Action>(action: A, id: number) => A
+  /**
+   * function which takes `state` object and index as arguments, and should return `state` object back.
+   */
+  stateSanitizer?: <S>(state: S, index: number) => S
+  /**
+   * *string or array of strings as regex* - actions types to be hidden / shown in the monitors (while passed to the reducers).
+   * If `actionsWhitelist` specified, `actionsBlacklist` is ignored.
+   */
+  actionsBlacklist?: string | string[]
+  /**
+   * *string or array of strings as regex* - actions types to be hidden / shown in the monitors (while passed to the reducers).
+   * If `actionsWhitelist` specified, `actionsBlacklist` is ignored.
+   */
+  actionsWhitelist?: string | string[]
+  /**
+   * called for every action before sending, takes `state` and `action` object, and returns `true` in case it allows sending the current data to the monitor.
+   * Use it as a more advanced version of `actionsBlacklist`/`actionsWhitelist` parameters.
+   */
+  predicate?: <S, A extends Action>(state: S, action: A) => boolean
+  /**
+   * if specified as `false`, it will not record the changes till clicking on `Start recording` button.
+   * Available only for Redux enhancer, for others use `autoPause`.
+   *
+   * @default true
+   */
+  shouldRecordChanges?: boolean
+  /**
+   * if specified, whenever clicking on `Pause recording` button and there are actions in the history log, will add this action type.
+   * If not specified, will commit when paused. Available only for Redux enhancer.
+   *
+   * @default "@@PAUSED""
+   */
+  pauseActionType?: string
+  /**
+   * auto pauses when the extension’s window is not opened, and so has zero impact on your app when not in use.
+   * Not available for Redux enhancer (as it already does it but storing the data to be sent).
+   *
+   * @default false
+   */
+  autoPause?: boolean
+  /**
+   * if specified as `true`, it will not allow any non-monitor actions to be dispatched till clicking on `Unlock changes` button.
+   * Available only for Redux enhancer.
+   *
+   * @default false
+   */
+  shouldStartLocked?: boolean
+  /**
+   * if set to `false`, will not recompute the states on hot reloading (or on replacing the reducers). Available only for Redux enhancer.
+   *
+   * @default true
+   */
+  shouldHotReload?: boolean
+  /**
+   * if specified as `true`, whenever there's an exception in reducers, the monitors will show the error message, and next actions will not be dispatched.
+   *
+   * @default false
+   */
+  shouldCatchErrors?: boolean
+  /**
+   * If you want to restrict the extension, specify the features you allow.
+   * If not specified, all of the features are enabled. When set as an object, only those included as `true` will be allowed.
+   * Note that except `true`/`false`, `import` and `export` can be set as `custom` (which is by default for Redux enhancer), meaning that the importing/exporting occurs on the client side.
+   * Otherwise, you'll get/set the data right from the monitor part.
+   */
+  features?: {
+    /**
+     * start/pause recording of dispatched actions
+     */
+    pause?: boolean
+    /**
+     * lock/unlock dispatching actions and side effects
+     */
+    lock?: boolean
+    /**
+     * persist states on page reloading
+     */
+    persist?: boolean
+    /**
+     * export history of actions in a file
+     */
+    export?: boolean | 'custom'
+    /**
+     * import history of actions from a file
+     */
+    import?: boolean | 'custom'
+    /**
+     * jump back and forth (time travelling)
+     */
+    jump?: boolean
+    /**
+     * skip (cancel) actions
+     */
+    skip?: boolean
+    /**
+     * drag and drop actions in the history list
+     */
+    reorder?: boolean
+    /**
+     * dispatch custom actions or action creators
+     */
+    dispatch?: boolean
+    /**
+     * generate tests for the selected actions
+     */
+    test?: boolean
+  }
+  /**
+   * Set to true or a stacktrace-returning function to record call stack traces for dispatched actions.
+   * Defaults to false.
+   */
+  trace?: boolean | (<A extends Action>(action: A) => string)
+  /**
+   * The maximum number of stack trace entries to record per action. Defaults to 10.
+   */
+  traceLimit?: number
+}
+
+/**
+ * @public
+ */
+export const composeWithDevTools: {
+  (options: EnhancerOptions): typeof compose
+  <StoreExt>(...funcs: Array<StoreEnhancer<StoreExt>>): StoreEnhancer<StoreExt>
+} =
+  typeof window !== 'undefined' &&
+  (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
+    ? (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
+    : function() {
+        if (arguments.length === 0) return undefined
+        if (typeof arguments[0] === 'object') return compose
+        return compose.apply(null, (arguments as any) as Function[])
+      }
+
+/**
+ * @public
+ */
+export const devToolsEnhancer: {
+  (options: EnhancerOptions): StoreEnhancer<any>
+} =
+  typeof window !== 'undefined' && (window as any).__REDUX_DEVTOOLS_EXTENSION__
+    ? (window as any).__REDUX_DEVTOOLS_EXTENSION__
+    : function() {
+        return function(noop) {
+          return noop
+        }
+      }


Test patch:
diff --git a/src/configureStore.test.ts b/src/configureStore.test.ts
index 4d6290c6..a7a4bab6 100644
--- a/src/configureStore.test.ts
+++ b/src/configureStore.test.ts
@@ -1,6 +1,6 @@
 import { configureStore } from './configureStore'
 import * as redux from 'redux'
-import * as devtools from 'redux-devtools-extension'
+import * as devtools from './devtoolsExtension'
 import { StoreEnhancer, StoreEnhancerStoreCreator } from 'redux'
 
 describe('configureStore', () => {
diff --git a/src/entities/sorted_state_adapter.test.ts b/src/entities/sorted_state_adapter.test.ts
index 72e243ef..13419d78 100644
--- a/src/entities/sorted_state_adapter.test.ts
+++ b/src/entities/sorted_state_adapter.test.ts
@@ -29,7 +29,6 @@ describe('Sorted State Adapter', () => {
     adapter = createEntityAdapter({
       selectId: (book: BookModel) => book.id,
       sortComparer: (a, b) => {
-        //console.log(`${a.title}, ${b.title}`)
         return a.title.localeCompare(b.title)
       }
     })
diff --git a/src/entities/unsorted_state_adapter.test.ts b/src/entities/unsorted_state_adapter.test.ts
index 13a11ac4..5b83f145 100644
--- a/src/entities/unsorted_state_adapter.test.ts
+++ b/src/entities/unsorted_state_adapter.test.ts
@@ -228,8 +228,6 @@ describe('Unsorted State Adapter', () => {
 
     const { ids, entities } = withUpdates
 
-    console.log(withUpdates)
-
     /*
       Original code failed with a mish-mash of values, like: