# README

Compose a Redux store out of smaller bundles of functionality.

Created by: [@HenrikJoreteg](http://twitter.com/henrikjoreteg)

Created for and used by PWAs that value small bundle sizes, network resilience, and explicit state management. If you want to be able to declaratively combine seemingly disparate logic such as: if it's the third tuesday of the month, our cached data is more than 3.5 days old, and the user is viewing the `/reposition-satellite` page then trigger a data refresh of satellite position... this toolkit is for you.

If you pair it with [Preact](https://preactjs.com/) it's \~15kb for an entire app toolkit.

If you want to see an app built with it, check out: [anesthesiacharting.com](https://anesthesiacharting.com).

## The basic idea

Organize all Redux-related code into a single flat folder of "redux bundles". A bundle is a single file for each main area of functionality in your app.

A bundle can optionally export things like:

1. A name
2. A reducer
3. Action creators
4. Selectors (functions for reading state)
5. An init method

For example:

`bundles/users.js:`

```javascript
export default {
  // the name becomes the reducer name in the resulting state
  name: 'users',
  // the Redux reducer function
  reducer: (state = [], action) => {
    // ...

    // state here is the "users" slice of full state object
    return state
  },
  // anything that starts with `select` is treated as a selector
  // selectors get full state object so they can use state from other bundles
  selectActiveUsers: state => state.users.filter(user => user.isActive),
  // anything that starts with `do` is treated as an action creator
  doUpdateUser: (userId, attrs) => ({ dispatch, apiFetch }) =>
    dispatch({ type: 'USER_UPDATE_STARTED' })
    apiFetch('/users', { type: 'PUT' }, attrs)
      .then(res => {
        dispatch({ type: 'USER_UPDATE_FINISHED' })
      })
      .catch(err => {
        dispatch({ type: 'USER_UPDATE_FAILED' })
      }),
  // optional init method is ran after store is created and passed the
  // store object.
  init: store => {
    // action creators are bound and attached to store as methods
    store.doUpdateUser()

    // selectors are also "bound" and attached to store as methods
    store.selectActiveUsers()
  }
}
```

Redux-bundler then composes those "bundles" into a function that returns a ready-to-go Redux store.

Usually you'd just do this in the index file of your bundles directory:

`bundles/index.js:`

```javascript
import { composeBundles } from 'redux-bundler'
import usersBundle from './the/file/above'
import authBundle from './bundles/auth'
// ... import other bundles

export default composeBundles(
  usersBundle,
  viewportBundle
  // ... add bundles here
)
```

Then, in your root component, call the function exported by the bundles directory, pass it any initial data and you're up and running:

`components/root.js`

```javascript
import React from 'react'
import { render } from 'react-dom'
// similar to react-redux
// bindings available for React and Preact
import { Provider } from 'redux-bundler-react'
import App from './components/app'
// the file above exports a ready-to-go
// createStore function
import createStore from './bundles'

// you can also pass it initial data here if you have any
const store = createStore(window.BOOTSTRAP_DATA)

// render your app
render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.body.getElementById('app')
)
```

Now you can efficiently connect components with way less boilerplate:

`components/some-component.js`

```javascript
import React from 'react'
import { connect } from 'redux-bundler-react'

// pass as many names of selectors or action creators as you want
// in any order. Functionality is implied from the name so `doX`
// is an action. `selectX` is a selector.
//
// - action creators are pre-bound to the store.
// - selector names create prop names that sound like the value so
//   `selectActiveUsers` here, becomes: `activeUsers`
export default connect(
  'doUpdateUser',
  'selectActiveUsers',
  ({ doUpdateUser, activeUsers }) => (
    <div>
      {activeUsers.map(user => (
        <div>
          name: {user.name}
          <button
            onClick={() =>
              // action creators are pre-bound to the store
              doUpdateUser({
                isAwesome: true
              })
            }
          />
        </div>
      ))}
    </div>
  )
)
```

## Features

1. This is not a toy project. This is how I build production Redux apps. It was extracted from real apps where it was used to solve real use cases.
2. It's quite small at [\~9k](https://bundlephobia.com/result?p=redux-bundler). That includes Redux itself, reselect for selectors, as well as an optional super light-weight routing system. If you pair it with [Preact](https://preactjs.com/) and [money-clip](https://github.com/HenrikJoreteg/money-clip) you have a complete PWA toolkit in \~14kb! That's before tree-shaking (could be much less if you don't use everything).
3. Dramatically reduces boilerplate without changing or replacing basic Redux concepts.
4. "Batteries included" approach where you use what you want, and tree-shake out the rest.
5. Simplified and more efficient `connect()` for binding to components (available for [React](https://github.com/HenrikJoreteg/redux-bundler-react) and [Preact](https://github.com/HenrikJoreteg/redux-bundler-preact))
6. Includes a very lightweight, robust, routing system (optional).
7. Supports code-splitting/lazy-loading of Redux bundles.
8. Makes re-use of Redux related code between apps really simple; just publish a bundle to npm.
9. Full [example-app](https://github.com/HenrikJoreteg/redux-bundler-example) available demonstrating data fetching, clientside caching, routing, etc.
10. Can run entirely in a WebWorker using [redux-bundler-worker](https://github.com/HenrikJoreteg/redux-bundler-worker) (complete [example app here](https://github.com/HenrikJoreteg/redux-bundler-worker-example)).
11. Supports the "reactor" pattern letting your react to your application state to dispatch other actions. This lets you write a total "honey badger" of an app that can seamlessly recover from errors and tolerate terrible network conditions.

## Motivation

Redux is awesome, but it's no secret that using it requires writing a fair amount of boilerplate. There are some [tips for reducing it in the official documentation](https://redux.js.org/recipes/ReducingBoilerplate.html) and there's an [open issue with over 100 comments](https://github.com/reactjs/redux/issues/2295) on the redux repo about how to handle it that is left largely unresolved.

I've been building redux apps for quite some time and some of you may have been introduced to it when I first [blogged about it](https://blog.andyet.com/2015/08/06/what-the-flux-lets-redux/) back in 2015. This library is how I build redux apps, I finally decided to open source it.

As I said this isn't a toy project. I'm currently using this library for my app that helps chart anesthesia during surgeries [AnesthesiaCharting.com](https://anesthesiacharting.com). This also builds on some of the ideas that were originally conceived and battle-tested when I was helping Starbucks re-platform and build their [shiny new PWA](https://app.starbucks.com). The point is this is actually how I build things with Redux, and given the lack of "solutions" to the boilerplate issue, I decided to share it.

There's a sample application [the source is here](https://github.com/HenrikJoreteg/redux-bundler-example) which is a good way to see how to build something with it. It's [deployed here](https://redux-bundler.netlify.com/) so you can see how it all works when it's up and running.

Note: redux-bundler includes its dependencies for simplicity to minimize surface area for bugs due to version mismatches. It also exports all the exports from redux. So you can still do stuff like `import { combineReducers } from 'redux-bundler'`. However, this also means you end up with code from redux with the debug blocks `if (process.env.NODE_ENV !== "production")` still present. Build your app with NODE\_ENV="production" before minification to strip that out for production. You can use DefinePlugin for webpack (<http://stackoverflow.com/questions/30030031>), loose-envify (<https://github.com/zertosh/loose-envify>) for browserify, or rollup-plugin-replace for Rollup (<https://github.com/rollup/rollup-plugin-replace>) to do this.

## What this enables

This approach of consolidating everything on the store actually enables some interesting things.

* Reuse of redux-related functionality across applications. (For example, I share an "authBundle" between 3 different apps built on the same API).
* You can make configurable bundles! You can write higher-level functions that returns a pre-configured bundle. This is *huge* for reducing boilerplate for things like simple data fetches. See the included `createAsyncResourceBundle` for an example of this.
* Keep things tidy. Behavior is decoupled from display. Components can focus on what they do best: rendering their current props.
* It strongly enforces a set of conventions for building redux apps (this is important for larger teams, especially). For example, you have to name your selectors starting with `select`.
* Supports lazy-loading additional redux bundles even after you've created the store. The new bundles are integrated into the existing redux store. Since, connected components reference things by name instead of directly import functions the the components can be sent in different JS payload than the redux code that will power them because until they're actually used they can reference things that don't yet exist on the store.
* This lib also includes an integrated approach for how to react to certain state conditions in your app. You can define special selectors that start with `react` instead of `select` that will be evaluated on a regular basis and can return actions to trigger in response. This enables really, really interesting patterns of being able to recover from failure and retrying failed requests, etc. The level of reliability that can be achieved here is *very* powerful especially for use in PWAs that may well be offline or have really poor network conditions.
* The fact that you *have to use a selector* to get state from redux dramatically simplifies refactoring of large redux apps and avoids many performance pitfalls.
* You can pass an array of selector names you want to subscribe to and get a callback with changes for those particular selectors. By consolidates state diffing into a single spot in the store, `connect()` doesn't have to do any dirty checking, so the binding code becomes very simple.
* Connected action creators are already pre-bound to the store so you never have to import an action creator and then bind it before using it in your component, which I've found to be really confusing for developers learning redux.
* It includes a debug bundle you can enable to see nice summary of what's happening for each action that is dispatched.
* In debug mode (which is enabled by setting `localStorage.debug` to a truthy value) the store instance is bound to `window` allowing console debugging of all your selectors, action creators via the JS console. For example you can type stuff like `store.selectIsLoggedIn()` to see results or `store.doLogout()` to trigger that action creator even if you don't have UI built for that yet.
* It is uniquely well-suited for running inside a WebWorker. Because so much of your application logic lives in the resulting store, and because it lets you subscribe to changes and get deltas of the state you care about, this whole system is uniquely well suited for being ran off of the main thread. I've put together [an example app that runs entirely in a worker](https://github.com/HenrikJoreteg/redux-bundler-worker-example)

## What about async stuff?!

This is another one of the chief complaints people have with redux. They eventually feel like `redux-thunk` doesn't suit their needs. This generally happens once they need to do something more complex than simple data fetches. Solutions like redux-loop or redux-saga attempt to solve this issue. I've never liked either one or any other solution that I've seen, for that matter. They're generally *way* more complicated than redux-thunk and in my opinion, nearly impossible for beginners to grok.

Let's take a step back. Many developers, if using react will use component life-cycle methods like `componentDidMount` to trigger data fetches required by that component. But this sucks for many reasons:

1. You've coupled data fetching arbitrarily to a component, what if another component needs the same data but it hasn't been fetched yet?
2. What if the component, due to user actions gets removed and immediately added back because the user clicked "back"?
3. What if you know ahead of time that data is *going* to be needed by the application, even if it isn't needed yet?
4. What if it fails and we want to retry a couple of times before we show a "failed" message to the user?
5. What if you want to show the data you already have, while fetching updated data in the background?

The point I'm trying to make is that coupling data fetches to a component being visible, or even to a certain URL in your app isn't ideal.

What you're really trying to do is define a set of *conditions* that should lead to a new data fetch. For example you may want to fetch if:

1. Nothing has actually happened but 5 minutes have passed since the last successful fetch.
2. You don't already have the data
3. It errored last time you fetched and 15 seconds has passed, but you still have some data that you want to keep showing because it's recent enough.
4. You've successfully fetched related data first
5. A user is on any url that includes `/reports` in the pathname.

Good luck writing that with simple procedural code!

Part of the appeal of react, as a movement, was to move toward a more reactive style of programming. Yet, most of our data-related stuff is *very* simplistic.

What we want, is our app to behave like a spreadsheet. I wrote about this in [a post about reactive programming](https://joreteg.com/blog/reactive-programming).

What if we let the current state of the app determine what should happen next? Instead of manually triggering things, what if a certain state could cause an action creator to fire? All of a sudden we can describe the *conditions* under which a data fetch should occur. We don't need better async solutions for redux, thunk is fine, what we need is a way to trigger "reactions" to certain state.

redux-bundler includes a pattern for this. Bundles can include what I call "reactors", which are really just selector functions. They can have dependencies on other selectors, and get passed the entire current state, just like other selectors. But if they return something it gets dispatched. This is all managed by redux-bundler. If your bundle includes a key that starts with `react` it will be assumed to be a reactor. From a reactor you can check for whatever conditions in your app you can dream up and then return the action you want to dispatch. And, to be consistent with the decoupled philosophies, you can return an object containing the name of the action creator you want to trigger and the arguments to call it with.

As an example, I like to make a bundle that just manages all the redirects in my app. Here's an an abbreviated version from an actual app:

```javascript
import { createSelector } from 'redux-bundler'

const publicUrls = ['/', '/login', '/signup']

export default {
  name: 'redirects',
  reactRedirects: createSelector(
    'selectIsLoggedIn',
    'selectPathname',
    'selectHasNoOrgs',
    (isLoggedIn, pathname, hasNoOrgs, activeOrgHasBasicInfo) => {
      if (isLoggedIn && publicUrls.includes(pathname)) {
        return { actionCreator: 'doUpdateUrl', args: ['/orgs'] }
      }
      if (!isLoggedIn && pathname.startsWith('/orgs')) {
        return { actionCreator: 'doUpdateUrl', args: ['/login'] }
      }
      if (hasNoOrgs && pathname === '/orgs') {
        return { actionCreator: 'doReplaceUrl', args: ['/orgs/create'] }
      }
      // remove trailing slash
      if (pathname !== '/' && pathname.endsWith('/')) {
        return { actionCreator: 'doReplaceUrl', args: [pathname.slice(0, -1)] }
      }
    }
  )
}
```

Now I have one unified place to see anything that could cause a redirect in my app.

## What next?

* Learn exactly [what bundles can do](/api-reference/bundle).
* Check out the example app here: <https://github.com/HenrikJoreteg/redux-bundler-example> to see how to build an app with redux-bundler.
* Learn about all the functionality available in the [included bundles](/api-reference/included-bundles).
* See the [patterns page](/guides/patterns) for tips on how to organize your code, and do things like caching and routing.

## license

[MIT](http://mit.joreteg.com/)


# Patterns

1. *all* redux-related functionality should live in a bundle.
2. Just keep a single, flat folder called `bundles` with one bundle per file.
3. Make an `index.js` file in `bundles` to export the result of `composeBundles()`, the resulting function takes a single argument which is any locally cached or bootstrapped data you may have, and returns a redux store. This is also useful for passing settings or config values to bundles that are dynamic as you see with the `cachingBundle` and `googleAnalytics` below:

   > ```javascript
   > import { composeBundles, createCacheBundle } from 'redux-bundler'
   > import config from '../config'
   > import user from '/user'
   > import other from './other'
   > import googleAnalytics from './analytics'
   > import { getConfiguredCache } from 'money-clip'
   >
   > const cache = getConfiguredCache({
   >   version: config.browserCacheVersion
   > })
   >
   > export default composeBundles(
   >   user,
   >   createCacheBundle(cache.set),
   >   other,
   >   googleAnalytics(config.gaId, '/admin')
   > )
   > ```
4. Data is *always* read from the store via selectors
5. Selectors must be written to take *the entire* state as an argument
6. Selectors must be named starting with the word `select` such as `selectAppTime`.
7. Actions creators must be named starting with the word `do` such as `doLogin`.

## Caching

Persisting data locally can have a huge impact on performance. But comes with many caveats with regard to loading stale data, loading data from another user, and handling changes in "shape" of data that's been cached.

Using [money-clip](https://github.com/HenrikJoreteg/money-clip) with `createCacheBundle` can help address all of these issues. See money-clip readme for more.

This approach is implemented in the [example app](https://github.com/HenrikJoreteg/redux-bundler-example).

## Routing

Use `createRouteBundle()` to generate routes as seen in the example app. When determining what to actually store as the "value" for a given route, I tend to use a component but you could certainly also return a string to be used for `<title></title>` or any other relevant items.

## React-Native (RN)

If you are using `redux-bundler` with RN make sure you run `global.self = global` as the very first piece of code. The most common approach would be to put the code snippet in a seperate file and import it as the first one in your RN entry point/s.

Some bundles like the `debugBundle` arent compatible with RN. So we cant use `composeBundles()` and only the `composeBundlesRaw()` method can help us out. If you want to use the reactions feature dont forget to compose `createReactionBundle()` in the compose function otherwise your actions returned never got dispatched!

```
import { composeBundlesRaw, createReactorBundle } from 'redux-bundler'

export default composeBundlesRaw(
    createReactorBundle(),
    // ... add more bundles here
)
```

## Using Redux DevTools

Both the `debug` bundle and redux dev tools are enabled if `localStorage.debug` is set to something "truthy". In this way you can keep your production apps debuggable, you just have to flip that `localStorage.debug` flag to enable it. Also beware that running `localStorage.debug = false` in your browser console won't actually turn it off. This is because LocalStorage serializes everything to strings so the value that's stored is actually the string `"false"` which... is truthy! So to turn it back off again, you can just do: `delete localStorage.debug` instead.


# Top Level API

## `composeBundles(...bundles)`

Returns a function that will return a fully configured store composed of all the bundles **including some built-in ones that you're likely to want**. If you have any data to use as starting state, it can be passed to this function.

Included bundles:

* `appTimeBundle`
* `asyncCountBundle`
* `onlineBundle`
* `createUrlBundle()`
* `createReactorBundle()`
* `debugBundle`

## `composeBundlesRaw(...bundles)`

Same as `composeBundles(...bundles)` but does not include anything bundles by default.

## `createSelector()`

Can be used to create selectors as described in the `selectX` section of the bundle API.

## `HAS_WINDOW`

Is `window` defined

## `IS_BROWSER`

Like `HAS_WINDOW` but also tries to determine if we're in a WebWorker.

## `raf`

Shim for `requestAnimationFrame` with fallback to `setTimeout(0)` for node.

## `ric`

Shim for `requestIdleCallback` with fallback to `setTimeout(0)` for node.

## Exports `*` from redux

As previously stated, this library includes Redux, so redux methods are exported too.


# Bundle API

Things bundles can contain:

## `bundle.name`

The only required attribute your bundle should supply. This will be used as the name of any exported reducer.

## `bundle.reducer` or `bundle.getReducer()`

If you export an item called `reducer` it is assumed it's a ready-to-user redux reducer. Sometimes you need to dynamically configure something like `initialData` in these cases a bundle can supply a `getReducer` function instead that will return a reducer. This can be useful for any setup you may need to do, like defining initialState, or whatnot.

## `bundle.selectX`

Anything you attach that starts with `select` such as `selectUserData` will be assumed to be a selector function that takes the entire state object selects what you want out of it. This supports any function that takes the entire store state and returns the relevant data. If you use the `createSelector` method exported by this library, you can create selectors whose dependencies are string names of other selectors. This allows for loose coupling between modules and means that you never have to worry about creating circular imports when various selectors depend on each other. This is possible because as part of creating the store, the library will resolve all those names into real functions. This is powered by [create-selector](https://github.com/HenrikJoreteg/create-selector) :point\_left: which is basically a fork of reselect.

## `bundle.doX`

Similarly to selectors, if your bundle contains any keys that start with `do`, such as `doSomething` they'll be assumed to be action creators.

These will be bound to dispatch for you and attached to the store. So you can call `store.doSomething('cool')` directly.

**important**: a slightly modified thunk middleware is included by default. So you always have access to `dispatch`, `getState`, and `store` within action creators as follows.

```javascript
const doSomething =
  value =>
  ({ dispatch }) =>
    dispatch({ type: 'something', payload: value })
```

Note that unlike standard thunk that uses positional arguments, this passes just one object containing `dispatch`, `getState`, and any other items included by bundles that define `getExtraArgs`.

## `bundle.reactX`

Reactors are like selectors but start with the word `react`. They get run automatically by redux-bundler whatever they return gets dispatched. This could either be an object: `{type: 'INITIATE_LOGIN'}` or it could be a named action creator like: `{actionCreator: 'doInitiateLogin', args: ['username']}`.

This allows a simple, declarative way to ask questions of state, via selectors to trigger an effect via action reators without the need to introduce new approaches to deal with effects.

**important**: It is *easy to make infinite loops*. Make sure that any action triggered by a reactor, immediately change the conditions that caused your reactor function to return something.

## `bundle.getExtraArgs`

If you define this function it should return an object containing items you wish to make available to all action creators of all bundles.

Commonly this would be used for passing things like api wrappers, configs, etc.

**important**: this function will be called *with the store*. This allows you to do things like create API wrappers that automatically handle authorization failures to trigger redirects, etc.

## `bundle.init`

This will be run *once* as a last step before the store is returned. It will be passed the `store` as an argument. This is useful for things like registering event listeners on the window or any other sort of initialization activity.

For example, you may want redux to track current viewport width so that other selectors can change behavior based on viewport size. You could create a `viewport` bundle and register a debounced event listener for the `resize` event on window, and then dispatch a `WINDOW_RESIZED` action with the new width/height and add a `selectIsMobileViewport` selector to make it available to other bundles.

You probably won't need this, but if you return a function from init, that function will be called if you call `store.destroy()`. This can be useful if you're building a micro-frontends or portal system and need to load/unload whole apps in the same webpage.

```javascript
  ...
  init: (store) {
    const handleOnline = () => store.dispatch({ type: 'ONLINE' })

    window.addEventListener('online', handleOnline)

    return () => {
      window.removeEventListener('online', handleOnline)
    }
  }
  ...
```

## `bundle.persistActions`

If the caching bundle is configured it will look for this property from other bundles. It should contain an array of action types that should cause contents of this bundle's reducer to be persisted to cache. These action types will be used by some generated redux middleware to lazily persist the contents of the reducer any time these actions occur.

Please note this is completely inert if no caching is configured for the app.


# Included Middleware

Redux-bundler includes a few middlewares by default:

## Slightly modified `redux-thunk`

Works like `redux-thunk` except that everything is passed as a single argument and since all our selectors and action creators are attached to the store instance we also pass the store itself, plus anything bundles may have added by using `getExtraArgs`. So it ends up passing something like this as an argument `{dispatch, store, getState, ...extraArgs}` to your thunk function.

This lets you write action creators that don't care about argument position:

```javascript
export const doCoolStuff =
  () =>
  ({ dispatch, myApiWrapper }) => {
    dispatch({ type: 'USER_FETCH_STARTED' })
    return myApiWrapper('/some-resource')
      .then(payload => {
        dispatch({ type: 'USER_FETCH_FINISHED', payload })
      })
      .catch(() => {
        dispatch({ type: 'USER_FETCH_FAILED' })
      })
  }
```

## Debug Middleware

If you're using the `debugBundle` it will also add some logging middleware that logs actions and state with each action and shows you the next reactor that will be dispatched.

## Named Action Middleware

The bundle created by `createReactorBundle` will also inject middleware that allows you to dispatch an object that names the action creator to be used and optionally the arguments to pass to it.

For example dispatching `{actionCreator: 'doLogOut', args: [true]}` would be the same as calling `store.doLogOut(true)`.

This is most useful when writing reactor functions in a bundle where you may not have a direct reference to the action creator function you want to call.


# Included Bundles

We take a "batteries included" approach where you don't have to use any of this stuff but where a pretty complete set of tools required for apps is included out of the box.

## `createDebugBundle([optionsObject])`

This is meant to be leave-in-able in production. It works as follows:

Unless `localStorage.debug` is set to something "truthy" it will do nothing.

It takes the following options (none are required):

* `logSelectors` (default: true): whether or not to log out selectors and their computed value with each action dispatch
* `logState` (default: true): whether to log state after each dispatch
* `logStackTraces` (default: true): whether to log stack traces with each dispatch
* `stackTraceLimit` (default: 100): stack trace limit to set when logging stack traces
* `actionFilter` (default: null): a function to call that determines whether or not to log an action (if debug is enabled). For example, if you want hide the `APP_IDLE` actions pass this: `(action) => action.type !== 'APP_IDLE'`
* `enabled` (default: HAS\_DEBUG\_FLAG): explicitly enable/disable. This is helpful in node.js where there's no localStorage flag.
* `ignoreActions` (default: \[]): an array of actions to ignore when logging.

If enabled:

* The store is bound to `window.store` for easy access to *all selectors and action creators* since they're all bound to the store. This is super helpful for debugging state issues, or running action creators even if you don't have UI built for it yet.
* On boot, it logs out list of all installed bundles
* On each action it logs out:
  * action object that was dispatched
  * the current state in its entirety
  * the result of all selectors after that state change
  * if there's a reactor that will be triggered as as result, it will log that out too as `next reaction`

![logger screenshot](https://cldup.com/bHBHBqkW0B-3000x3000.png)

In order to support use inside a Web Worker which doesn't have `localStorage` access debug state is stored in a reducer and it includes `doEnableDebug()` and `doDisableDebug()` action creators. But most people won't need this. Simply use the localStorage flag.

## `createUrlBundle([optionsObject])`

A complete redux-based URL solution. It binds the browser URL to Redux store state and provides a very complete\
set of selectors and action creators to give you full control of browser URLs.

**Handling in-app navigation**: An extremely lightweight in-app navigation approach is to just by rendering normal `<a>` tags, add an `onClick()` handler on your root component and use [internal-nav-helper](https://github.com/HenrikJoreteg/internal-nav-helper) to inspect the events, calling `doUpdateUrl` as necessary. When click events bubble up, it will inspect the event target looking for `<a>` tags and then determining whether or not to consider it an internal link based on its href. See [internal-nav-helper](https://github.com/HenrikJoreteg/internal-nav-helper) library for more details.

Sample root component:

```js
import navHelper from 'internal-nav-helper'
import { connect } from 'redux-bundler-preact'
import { h } from 'preact'

export default connect(
  'doUpdateUrl',
  'selectRoute',
  ({ doUpdateUrl, route }) => {
    const CurrentPage = route
    return (
      <div onClick={navHelper(doUpdateUrl)}>
        <CurrentPage />
      </div>
    )
  }
)
```

Options object:

* `inert`: Boolean whether or not to bind to the browser. If you make it `inert` it will simply maintain state in Redux without trying to update the browser, or listen for `popstate`
* `handleScrollRestoration`: Boolean (default `true`). Whether or not to handle scroll position restoration on document.body. Some browsers handle this for you with the notable exception of FF and IE 11. If you leave this as `true` it should work in latest version of all browsers.

Action creators:

* `doUpdateUrl(pathname | {pathname,query,hash}, [options])`: Generic URL updating action creator. You can pass it any pathname string or an object with `pathname`, `query`, and `hash` keys. ex: `doUpdateUrl('/new-path')`, `doUpdateUrl('/new-path?some=value#hash')`. You can pass `{replace: true}` as an option to trigger `replaceState` instead of `pushState`. Additionally, you can pass `{ maintainScrollPosition: true }` for cases when you do not expect window scroll position to be reset to top as a result of route transition.
* `doReplaceUrl(pathname | {pathname,query,hash})`: just like `doUpdateUrl` but replace is prefilled to replace current URL.
* `doUpdateQuery(queryString | queryObject, [options])`: can be used to update query string in place. Either pass in new query string or an object. It does a replaceState by default but you can pass `{replace: false}` if you want to do a push.
* `doUpdateHash(string | object, [options])`: for updating hash value, does a push by default, but can do replace if passed `{replace: true}`.

Selectors:

* `selectUrlRaw()`: returns contents of reducer.
* `selectUrlObject()`: returns an object like what would come from `new URL()` but as a plain object.
* `selectQueryObject()`: returns query string as an object
* `selectQueryString()`: returns query string as a string
* `selectPathname()`: returns pathname, without hash or query
* `selectHash()`: returns hash value as string
* `selectHashObject()`: returns hash value as object (if relevant)
* `selectHostname()`: returns hostname as string.
* `selectSubdomains()`: returns array of subdomains, if relevant.

## `createRouteBundle(routesObject, optionsObject)`

Takes an object of routes and returns a bundle with selectors to extract route parameters from the routes.

Example:

```js
export default createRouteBundle({
  '/': Home,
  '/users': UserList,
  '/users/:userId': UserDetail,
  '*': NotFound
})
```

The value like `Home`, `UserList`, etc, can be *anything*. Whatever the current route that matches, calling `selectRoute()` will *return whatever that is*. This could be a root component for that "page" in your app. Or it could be an object with a component name along with a page title or whatever else you may want to link to that route.

Then in your root component in your app you'd simply `selectRoute()` to retrieve it.

Options object:

* `routeInfoSelector`: String (default: `'selectPathname'`) used to configure the key that is used for matching the current route on. Set it to `'selectHash'` to enable hash-based routing. **Note**: Currently you need entries for both '' and '/' if you rely on hash-based routing.

```js
export default createRouteBundle(
  {
    '': Home,
    '/': Home,
    '/users': UserList
  },
  {
    routeInfoSelector: 'selectHash'
  }
)
```

Selectors:

`selectRouteParams()`: returns an object of any route params extracted based on current route and current URL. In the example above `/users/:userId` would return `{userId: 'valueExtractedFromURL'}`.`selectRouteMatcher()`: returns the route matcher function used. Can be useful for seeing what result a URL would return before actually setting that URL.`selectRoutes()`: returns the routes object originally passed in. Can be useful for static sites where you want to pre-render all available pages at build time.`selectRoute()`: returns whatever the value was in the routes object for the current matched route.`selectRouteInfo()`: returns the key that was passed to the route matcher. By default this is the value of `selectPathname` as defined by the `createUrlBundle` above.

Action creators:

`doReplaceRoutes()`: takes new set of routes. This can be useful if you're using placeholder routes and want to dynamically load and replace them with real ones if you're doing extensive code splitting or using "sub app" type architectures. Note that calling this will trigger a `ROUTE_MATCHER_REPLACED` action with a `payload` property of `{routes: newRoutes, routeMatcher: newRouteMatcher}`. If you really want a different name for the action that is triggered, you can add `{replaceAction: "OTHER_ACTION_NAME"}` to the options passed when calling `createRouteBundle`.

## `createReactorBundle(optionsObject)`

This is the functionality that allows for the `reactX` pattern in your bundles. Manual configuration here is entirely optional.

This bundle is included by default when you use `composeBundles`. If you want to pass it custom options you'll have to use `composeBundlesRaw` instead.

Available options:

* `idleTimeout`: Number (default `30000`). Idle timeout is time to fire an `APP_IDLE` event.
* `idleAction`: String (default `'APP_IDLE'`). Action type to dispatch on idle.
* `cancelIdleWhenDone`: Boolean (default `true`). In certain cases this can be useful. For example, if you're using reactors in a node process and you want it to be able to exit when there's no pending reactions. In browsers, this will be ignored.
* `doneCallback`: Function (default `null`). If you want to pass a callback to call when there are no more pending reactions, you can do so.
* `stopWhenTabInactive`: Boolean (default `true`). By default if a given tab is in the background we don't want to keep wasting cycles. But, in certain cases you don't want it to stop just because its in the background. Gives you that option. Note: this is implemented by taking advantage of behavior of `requestAnimationFrame`. So it relies on the browser for this logic.
* `reactorPermissionCheck`: Function (default: null). This function, if passed, will be given the name of the reactor, and the result of having called it that would normally have lead to a reaction being queued. If you return `false` from this function the reactor will not be queued. This allows you to implement rate limiting, etc. It also makes it possible to build in safe-guards for infinite reaction loops or other development tools.

## `appTimeBundle`

This simply tracks an `appTime` timestamp that gets set any time an action is fired. This is useful for writing deterministic selectors and eliminates the need for setting timers throughout the app. Any selector that uses `selectAppTime` will get this time as an argument. It's ridiculously tiny at only 5 lines of code, but is a nice pattern. Just be careful to not do expensive work in reaction to this changing, as it changes *with each action*.

## `asyncCountBundle`

This bundle takes no options, simply add it as is. It uses action naming conventions to track how many outstanding async actions are occurring.

It works like this:

If an action contains `STARTED` it increments, if it contains `FINISHED` or `FAILED` it decrements. It adds a single selector to the store called `selectAsyncActive`. This is intended to be used to display a global loading indicator in the app. You may have seen these implemented as a thin colored bar across the top of the UI.

## `createCacheBundle(optionsObject)`

Adds support for local caching of bundle data to the app. Other bundle can declare caching when this has been added to the app.

This bundle takes *one required option*: `cacheFn` a function to use to persist data. The function has to take two arguments: the key and the value and return a `Promise`. Suggested caching lib: [money-clip](https://github.com/HenrikJoreteg/money-clip).

Once the caching bundle has been added, other bundles can indicate that their contents should be persisted by exporting a `persistActions` array of action types. Any time one of those action types occur, the contents of that bundle's reducer will be persisted lazily. Again, see the example app for usage.

Two other options are supported:

1. `enabled: [Boolean]`: by default, it will be enabled in the browser only. Passing `enabled: [Boolean]` allows explicitly specifying whether it should be enabled or not. So if you're wanting to persist things in node.js, make sure you're passing `true`.
2. `logger: [Function]`: by default it logs nothing. If you want to log a success message after things have been persisted. Pass a function here, for example: `{ logger: console.log.bind(console), cacheFn: () => { ... } }`

Example usage:

```js
composeBundles(
  createCacheBundle({
    logger: console.log.bind(console),
    cacheFn: cache.put
  }),
  ...yourOtherBundles
)
```

## `createAsyncResourceBundle(optionsObject)`

Not in main index, be imported directly: `import createAsyncResourceBundle from 'redux-bundler/dist/create-async-resource-bundle'` (note, this requires inclusion of `redux-bundler/dist/online-bundle` in your app as well).

Returns a pre-configured bundle for fetching a remote resource (like some data from an API) and provides a high-level abstraction for declaring when this data should be considered stale, what conditions should cause it to fetch, and when it should expire, etc.

This bundle requires `appTimeBundle` and `onlineBundle` to be added as well (order doesn't matter) as long as both are included.

Options:

* `name` (required): name of reducer. Also used in action creator names and selector names. For example if the name is `users` you'll end up with a selector named: `selectUsers()`.
* `getPromise` (required): A function that should return a Promise that gets the data. If this throws, it will automatically be retried. If you want to consider it a permanent error that should not be retried throw an error object with a `error.permanent = true` property. **note:** this function will be called with the same arguments as you get when writing a thunk action creator: `({dispatch, getState, store, ...extraArgs }) => {}`
* `actionBaseType` (optional): This is used to build action types. So if you pass `USERS`, it will use action types like `USERS_FETCH_STARTED` and `USERS_EXPIRED`. Default: `name.toUpperCase()`.
* `staleAfter` (optional): Length of time in milliseconds after which the data should be considered stale and needing to be re-fetched. Default: 15 minutes.
* `retryAfter` (optional): Length of time in milliseconds after which a failed fetch should be re-tried after the last failure. Default: 1 minute.
* `expireAfter` (optional): Length of time in milliseconds after which data should be automatically purged because it is expired. Default: `Infinity`.
* `checkIfOnline` (optional): Whether or not to stop fetching if we know we're offline. This is imperfect because it's listens for the global `offline` and `online` events from the browser which are good for things like airplane mode, but not for "lie-fi" situations. Default: `true`
* `persist` (optional): Whether or not to include the `persistActions` required to cache this reducers content. Simply setting this to `true` doesn't mean it will be cached. You still have to make sure caching is setup using `createCachingBundle()` and a persistance mechanism [like money-clip](https://github.com/HenrikJoreteg/money-clip). Default `true`

Action creators:

Names are built dynamically using the `name` of the bundle with first letter upper-cased:

* `doFetch{Name}`: what is used internally to trigger fetches, but you can trigger it manually too.
* `doMark{Name}AsOutdated`: used to forcibly mark contents as stale, which will not clear anything, but will cause it to be re-fetched as if it's too old.
* `doClear{Name}`: clears and resets the reducer to initial state.
* `doExpire{Name}`: should mostly likely not be used directly, but it used internally when items expire. This is a bit like `doClear{Name}` except it does not clear errors and explicitly denotes that the contents are expired. So, if an app is offline and the content was wiped because it expired, your UI can show a relevant message.

Selectors:

* `select{Name}Raw`: get entire contents of reducer.
* `select{Name}`: get `data` portion of reducer (or `null`).
* `select{Name}IsStale`: Boolean. Is data stale?
* `select{Name}IsExpired`: Boolean. Is it expired?
* `select{Name}LastError`: Timestamp in milliseconds of last error or `null`
* `select{Name}IsWaitingToRetry`: Boolean. If there was an error and it's in the period where it's waiting to retry.
* `select{Name}IsLoading`: Boolean. Is it currently trying to fetch.
* `select{Name}FailedPermanently`: Boolean. Was a `error.permanent = true` error thrown? (if so, it will stop trying to fetch).
* `select{Name}ShouldUpdate`: Boolean. Based on last successful fetch, errors, loading state, should the content be updated?

Defining the state that should trigger the fetch:

Rather than manually calling `doFetch{Name}` from a component, you can use a reactor to define the scenarios in which the action should be dispatched. The simplest way is to add it to your bundle after generating it and then using the `select{Name}ShouldUpdate` as an input selector. The following code would cause the fetch to happen right away and the data to be kept up to date not matter what state the rest of the app was in or URL/Route was being displayed.

```js
const bundle = createAsyncResourceBundle({
  name: 'honeyBadger',
  actionBaseType: 'HONEY_BADGER',
  getPromise: () => {
    // return
  }
})

bundle.reactHoneyBadgerFetch = createSelector(
  'selectHoneyBadgerShouldUpdate',
  shouldUpdate => {
    if (shouldUpdate) {
      return { actionCreator: 'doFetchHoneyBadger' }
    }
  }
)

export default bundle
```

If instead you wanted to only have the fetch occur on a certain URL or route, or based on other conditions, you can check for that as well by adding and checking for other conditions in your reactor:

```js
const bundle = createAsyncResourceBundle({
  name: 'honeyBadger',
  actionBaseType: 'HONEY_BADGER',
  getPromise: () => {
    // return
  }
})

bundle.reactHoneyBadgerFetch = createSelector(
  'selectHoneyBadgerShouldUpdate',
  'selectPathname',
  (shouldUpdate, pathname) => {
    if (shouldUpdate && pathname === '/honey-badger') {
      return { actionCreator: 'doFetchHoneyBadger' }
    }
  }
)

export default bundle
```

## `onlineBundle`

Not in main index, be imported directly: `import onlineBundle from 'redux-bundler/dist/online-bundle'`

Tiny little (18 line) bundle that listens for `online` and `offline` events from the browser and reflects these in redux. Note that browsers will not detect "lie-fi" situations well. But these events will be fired for things like airplane mode. This can be used to suspend network requests when you know they're going to fail anyway.

Exports a single selector:

`selectIsOnline`: Returns current state.


# Added Store Methods

First, all `selectX` and `doX` action creators from the bundles of course.

Most of these exist in order to simplify writing code that binds state to a view library. These are used heavily by tools like:

* [redux-bundler-preact](https://github.com/HenrikJoreteg/redux-bundler-preact)
* [redux-bundler-react](https://github.com/HenrikJoreteg/redux-bundler-react)
* [redux-bundler-worker](https://github.com/HenrikJoreteg/redux-bundler-worker)

## `store.select(arrayOfSelectorNames)`

Get the results of many selectors at once. Pass it an array of selector names and it will run all those selectors and return an object of results where they key name is the name implied by the selector.

Example:

```js
// calling this:
store.select(['selectUserName', 'selectIsLoggedIn'])

// returns
{
  userName: 'some name',
  isLoggedIn: true
}
```

## `store.selectAll()`

Shortcut for calling `store.select()` but passing in all known selector names.

## `store.integrateBundles(...bundlesToAdd)`

Add additional bundles after the fact. This will manage updating redux-bundler and internally using redux's `.replaceReducer` to update the store in place.

Any `init` methods on the bundles will be called after the store is configured.

## `store.subscribeToSelectors(arrayOfSelectors, callback, [options])`

Given an array of selector names, the callback will be called whenever the resulting values change. This will *not* be called with the initial value/state of the selector.

Passing `{ allowMissing: true }` as `options` will let you pass selectors that don't yet exist on the store without throwing an error. This may be helpful if\
a bundle that gets integrated later via `integrateBundle` will add a selector that you want to listen for. If the initial value of the selector when the new bundle is integrated is anything but `undefined` the callback will be fired with the initial value.

Just like Redux's `subscribe()` it returns a function that can be used to unsubscribe.

In redux apps built without redux-bundler this type of comparison is done by `react-redux` for each connected component. By consolidating this logic onto the store itself, the binding implementations for various UI technologies can be much simpler see [redux-bundler-preact source](https://github.com/HenrikJoreteg/redux-bundler-preact/blob/master/src/index.js) as an example. Also, by consolidating this logic there's very little wasted cycles.

## `store.subscribeToAllChanges(callback)`

Shortcut for `subscribeToSelectors` where you instead subscribe to *all*. This is useful for things like [redux-bundler-worker](https://github.com/HenrikJoreteg/redux-bundler-worker) where we want to propagate state deltas to the main thread.

Returns a function that when called unsubscribes the callback.

## `store.action(actionCreatorName, [argsArray])`

Lets you dispatch an action creator by name. Give it the name of the action creator as a string, if you want to call the action creator with arguments pass the array of arguments to apply to the action creator as an array.

This utility exists to simplify support for propagating actions from main thread to web worker or vice versa.

## `store.destroy()`

Lets you remove event listeners, cleanup state and unsubscribe from store listeners. This calls the destroy implementation for every bundle. It is a 1-way function and the store cannot be re-initialized afterwards. You probably won't need this, but it can be handy if you're building a micro-frontends or portal system and you're loading/unloading whole apps in the same webpage.

## Special `BATCH_ACTIONS` action type

If you dispatch an action that looks like this `{type: 'BATCH_ACTIONS', actions: [array of other actions]}` it will dispatch them all in one update cycle. Rather than calling all callbacks at once, it will process all actions through all reducers then call the functions. These should be prepared "simple" action objects, not async actions that return a thunk function.

## Special `REPLACE_STATE` action type

If you dispatch an action like: `{type: 'REPLACE_STATE, payload: newState}` it will be as if your store got `newState` as initial state when the store was first created.

This lets you replace the entire state of your redux store. This can be handy for building tooling. Say, for example, you're building a remote PDF rendering service built with puppeteer. You could use `REPLACE_STATE` to post state from your app to the rendering service and use puppeteer to run your app, but inject the state you passed to it to produce a PDF with your app state.


# Change Log

* `29.1.0` Log stacktraces in the debug bundle log output.
* `29.0.0` This release has some changes that are unlikely to be breaking, but for safety releasing as a major bump:
  * Fixes a bug during `integrateBundles` calls where the new bundles' `init` functions would be called before the store reducer had been replaced; potentially causing the code in the `init` function to throw if it called a selector that depended on the new state. The `init` functions are now called as the final step in `integrateBundles` - this is unlikely to be a breaking but if you are using `integrateBundles` and `init` functions, verifying they are working as expected is advised.
  * Adds an `allowMissing` option to `subsribeToSelectors`. If passed, you can now subscribe to selectors that don't yet exist without the `subscribeToSelectors` call throwing. If the selector is added later (via `integrateBundles`) then changes to that selector will be emitted to the callback as expected.
  * Switched CI from circle ci to github actions
* `28.1.0` Minor non-breaking enhancement to `createRouteBundle` to more easily allow dynamic replacement of routes. Adding `doReplaceRoutes` action creator and explicitly storing cached routes and routeMatcher in a reducer so they can be easily replaced.
* `28.0.3` No API changes.
  * Replaces all uses of `self` with `globalThis`.
  * Explicitly pre-binds `raf` and `ric` to `globalThis` to prevents bug otherwise caused by Parcel 2 compiler optimization.
  * Adds `prettier` and `fixpack` as cleanup steps.
* `28.0.2` npm 7 deprecated prepublish, so last publish didn't build first. This fixes that.
* `28.0.1` Super minor fix. Some bundlers will remove context for `requestIdleCallback` and `requestAnimationFrame` so they end up being called as a method of the main redux-bundler export. This can cause "ILLEGAL invocation" errors when using them. This change simply wraps them in a fn so they're always called on `self`.
* `28.0.0` No API changes, just internal change to how reactors are dispatched. Due to potential behavioral impact to apps this is a major version bump. Details: to keep perf good we fire reactors on a `requestIdleCallback` we were firing the result even if by the time it fired, state had changed. The changes in this release should make that scenario impossible.
* `27.0.2` Fixed handling of `selectRoute` if there was no match. Previously, this would error, now it returns `null`. Previously `selectRouteParams` would also error, now it returns `{}`. Updated dependencies to eliminate some npm audit security warnings. Updated doc table of contents to fix broken links (due to change in gitbook). Removed `standard` and `prettier-standard` in lieu of vanilla eslint. Removed a couple of unused deps (oops).
* `27.0.1` Fix build issue for newly extracted "extra" bundles.
* `27.0.0` Separated a few non-core items into their own exports must be imported independently: `redux-bundler/dist/create-async-resource-bundle`, `redux-bundler/dist/create-geolocation-bundle`, `redux-bundler/dist/online-bundle`. This just removes stuff that is often unused from main build.
* `26.1.0` Added `reactorPermissionCheck` option to `createReactorBundle` to better support building rate-limiting or developer tools for reactors. Also, added better docs for `createReactorBundle` options.
* `26.0.0`
  * Removed `logIdle` option from `createDebugBundle` and added support for `actionFilter` function instead. Thanks to [@malbonesi](https://github.com/HenrikJoreteg/redux-bundler/pull/59) for the idea of making this more flexible.
  * Added `store.destroy()` method. Bundle `.init()` methods can optionally return a "cleanup" function. This means you can have an architecture that loads/unloads entire apps within the same document and lets you do cleanup like removing event listeners, etc. Thanks to [@rudionrails](https://github.com/HenrikJoreteg/redux-bundler/pull/57)
* `25.0.0`
  * Re-worked debug bundle. It is now created programmatically so it can be configured: `createDebugBundle()`
    * Now works in node.js ([#31](https://github.com/HenrikJoreteg/redux-bundler/issues/31))
    * Big thanks to [@aulneau](https://github.com/HenrikJoreteg/redux-bundler/pull/32) for general idea. Unfortunately wasn't quite able to merge his PR as it was and wanted to do some other related changes as well. But credit is due, for sure. Thanks!
    * Fix logging difference when activated later: ([#24](https://github.com/HenrikJoreteg/redux-bundler/issues/24))
  * Updates `querystringify` and `create-selector` to `2.1.1` ([#55](https://github.com/HenrikJoreteg/redux-bundler/issues/24))
  * Fixes annoying "missing sourcemap" warning when building with parcel.
* `24.0.0`
  * Breaking change to `createCacheBundle`. It now takes an options object as an argument instead of just a cache function. This allows us to pass an `enabled` option to enable its use in node.js (it's still off by default in node). Also adds support for passing a `logger` function as an option. It will be called with a message describing what was persisted and why.
  * Fixes persist action support for bundles added later with `integrateBundles`. Previously the map of actions to reducers to persist was only created up front. It is now re-generated after other bundles are integrated.
  * Added, tests to demonstrate these changes.
* `23.2.0` Adds option for `cancelIdleWhenDone` to `createReactorBundle`. By default, if redux-bundler is running in node.js and there are no pending reactions, the idle dispatcher stops firing. This is to support normal SSR use-cases where you may want to wait for the store to be "done" doing any remaining work, then fire the done callback. However, for use cases where you're wanting to use redux-bundler as a long-lived state engine in node.js it was problematic to have it stop idling. The default behavior is unchanged, but no if you pass `cancelIdleWhenDone: false` as an option, it will keep running indefinitely.
* `23.1.2` Adds `setTimeout` to restore scroll position util. This buys UI libs a chance to update the DOM and makes scroll position restoration work in some cases where it wasn't previously.
* `23.1.1` Updates `create-selector` to `4.0.3` to improve selector resolution perf. Updates a few dev dependencies to latest versions.
* `23.1.0` Adds `maintainScrollPosition` option to `doUpdateUrl()` (thanks [@abuinitski](https://github.com/abuinitski)). Minor tweak to explicitly check for `null` instead of implied type in order to support storing `0` as the data in `createAsyncResourceBundle()` (thanks [@layflags](https://github.com/layflags)).
* `23.0.2` Fixes issues with scroll restoration not working in all cases when using the url bundle.
* `23.0.1` Use `--no-compress` instead of `--compress=false`. It was not being parsed properly by the updated version of microbundle.
* `23.0.0`
  * Added support for passing a `REPLACE_STATE` action to replace entire state of store. Because this could be a breaking change if you already have such an action type, I'm doing a major version bump for this.
  * Updated npm deps to mitigate security advisories.
* `22.2.0`
  * Added `selectRoutes` to enable retrieving the entire routes object.
  * Merged refactored `createAsyncResourceBundle` (thanks [@aaronmccall](https://github.com/aaronmccall)) to enable better bundle composition.
* `22.1.0` - Added `selectRouteMatcher` to enable retrieving the function used to match urls to routes.
* `22.0.0` - Upgraded to redux v4.0.0.
* `21.2.2` - Fixed `staleAge` -> `staleAfter` bug in geolocation bundle and fix starting state from online bundle should come from `navigator.onLine` (thanks [@layflags](https://github.com/layflags)!). Minor docs update (thanks [@JayChetty](https://github.com/JayChetty)).
* `21.2.1` - Super minor tweak to `appTimeBundle` to make it possible to overwrite `Date.now()` after the app has started which can be useful to enable speeding up time for automated testing.
* `21.2.0` - Added support for hash-based routing by passing in options object to `createRouteBundle` (thanks \[@olizilla]!).
* `21.1.0` - Added support for Redux Dev Tools (thanks [@aulneau](https://github.com/aulneau)!). Added CI. Added some notes for React Native users to docs (thanks [@quarkcore](https://github.com/quarkcore)).
* `21.0.3` - Fix for bug in required options check in createAsyncResourceBundle (thanks [@greggb](https://github.com/greggb)). Minor simplification/cleanup of `custom-apply-middleware.js`. (this was supposed to be `21.0.2` but accidentally got published as `21.0.3` :facepalm:)
* `21.0.1` - Build with compress=false to avoid redux console warning and improve debugging experience.
* `21.0.0` - Adding scroll restoration handling. (many browsers already handle this well by default, but not FF or IE 11). This handles scroll position internally in the url bundle if used, it also exports the scroll restoration helper functions so that they can be used directly as well.
* `20.0.0` - Adding documentation site, wrote lots of docs and made mostly internal changes and bug fixes, can cause breakage if depending on action type names, or if using `composeBundlesRaw()` to handpick what's included.
  * Changed all action types to be past-tense (so they don't sound like RPC calls). Action types should describe things that happened, not sound like they're causing things to happen. So in asyncCount instead of `START`, `SUCCESS`, `ERROR` it's now `STARTED`, `FINISHED`, `FAILED`. In URL bundle `UPDATE_URL` -> `URL_UPDATED`. In geolocation bundle `REQUEST_GEOLOCATION_X` -> `GEOLOCATION_REQUEST_X`.
  * All included bundles that require instantiation with a config are now named `createXBundle` for consistency. This includes `createGeolocationBundle`, `createReactorBundle`, `createCacheBundle`.
  * Added lots of documentation to readme several of the included bundles.
  * Significant changes to `createAsyncResourceBundle`:
    * `actionBaseType` is now the noun, such as `USER`, from this we build `FETCH_USER_STARTED`, `USER_EXPIRED`, etc.
    * `doMarkXAsStale` is now `doMarkXAsOutdated`.
    * Action type names updated to be past tense: `MAKE_STALE` -> `X_INVALIDATED`
    * Added `doClearX` action creator and reducer case.
    * Now takes 3 time-related settings: `staleAfter`, `retryAfter`, and `expireAfter`.
    * Support for `expireAfter` was added, the `X_EXPIRED` action will be dispatched clearing the state.
  * Removed wonky batch dispatch quasi-middleware.
* `19.0.1` - Minor fix for WebWorkers (updating redux-persist-middleware dep).
* `19.0.0` - Externalized caching lib as its own library called [money-clip](https://github.com/HenrikJoreteg/money-clip) and the caching bundle now uses [redux-persist-middleware](https://github.com/HenrikJoreteg/redux-persist-middleware) to generate it's persistance middleware. Nothing huge changes other than importing caching lib from outside of bundler. I've updated [redux-bundler-example](https://github.com/HenrikJoreteg/redux-bundler-example) for sample usage of caching bundle with money-clip. Renamed `cacheBundle` -> `createCacheBundle` since it needs to be configured to be used. Removed unused `npm-watch` dev dependency.
* `18.0.0` - Renamed `selectCurrentComponent` -> `selectRoute` in create route bundle.
* `17.1.1` - Fix bug where `requestAnimationFrame` was expected to exist when running inside a worker.
* `17.1.0` - Export `*` from redux in index.
* `17.0.1` - Fix to ensure publishing/mapping to correct build files :facepalm:.
* `17.0.0` - Switched to build with microbundle. Should address issues #5, #8. No longer pulling in redux-bundler version into build.
* `16.1.1` - Ensure all output from selectors of included bundles is serializable. `selectUrlObject()` in the url bundle was returning a `URL` object instance. Now it just returns a plain object with all string properties from the URL object. Did this as bug fix release because it was always intended this way. In theory it could could be a breaking change, but odds are miniscule. Only if someone were doing `selectUrlObject` then treating its resulting `searchParams` prop as a `URLSearchParams` object and calling its methods instead of using one of the selectors that already exist for accessing query params.
* `16.1.0` - Added `.action()` method to store for calling an action creator by name (useful when wanting to proxy all actions to another object, such as a web worker)
* `16.0.0` - First public release


