UNPKG

8.15 kBMarkdownView Raw
1<p align="center">
2 <b style="font-size: 25px">🎛 flopflip - Feature Toggling 🎚</b><br />
3 <i>flip or flop a feature in LaunchDarkly with real-time updates through a redux store.</i>
4</p>
5
6<p align="center">
7 <img alt="Logo" src="https://raw.githubusercontent.com/tdeekens/flopflip/master/logo.png" /><br /><br />
8 <i>Toggle features in LaunchDarkly with their state being maintained in a redux state slice being accessible through a set of Higher-Order Components in React (via recompose).</i><br />
9</p>
10
11<details>
12 <summary>Want to see a demo?</summary>
13
14 <img alt="Logo" src="https://raw.githubusercontent.com/tdeekens/flopflip/master/demo.gif" />
15</details>
16
17### Status
18
19[![Travis](https://img.shields.io/travis/tdeekens/flopflip.svg?style=flat-square)](https://travis-ci.org/tdeekens/flopflip) 💎 [![npm](https://img.shields.io/tdeekens/v/flopflip.svg?style=flat-square)]() 💎 [![David](https://img.shields.io/david/tdeekens/flopflip.svg?style=flat-square)]()
20
21## Installation
22
23`yarn add flopflip` or `npm i flopflip --save`
24
25## Demo
26
27A minimal [demo](/demo) exists and can adjusted to point to a [custom](https://github.com/tdeekens/flopflip/blob/master/demo/src/App.js#L108) LaunchDarkly account. You would have to create feature toggles according to the existing [flags](https://github.com/tdeekens/flopflip/blob/master/demo/src/flags.js) too.
28
29Then simply run:
30
311. From the repositories root: `yarn build:watch`
322. From `/demo`: first `yarn` and then `yarn start`
33
34A browser window should open and the network tab should show feature flags being loaded from LaunchDarkly.
35
36## Documentation
37
38Flopflip allows you to manage feature flags through [LaunchDarkly](https://launchdarkly.com/) within an application written using React and Redux.
39
40### API & exports
41
42The `modules/index.js` exports:
43
44- `createFlopFlipEnhancer` a redux store enhancer to configure LaunchDarkly and add feature toggle state to your redux store
45- `ConfigureFlopFlip` a component to configure LaunchDarkly (alternative to the store enhancer)
46- `reducer` and `STATE_SLICE` a reducer and the state slice for the feature toggle state
47- `withFeatureToggle` a Higher-Order Component (HoC) to conditionally render components depending on feature toggle state
48- `injectFeatureToggles` a HoC to inject requested feature toggles from existing feature toggles onto the `props` of a component
49- `FeatureToggled` a component conditionally rendering its `children` based on the status of a passed feature flag
50
51#### `createFlopFlipEnhancer`
52
53Requires arguments of `clientSideId:string`, `user:object`.
54
55- The `clientSideId` is your LaunchDarkly ID.
56- The `user` object needs at least a `key` attribute. An anonymous `key` will be generated using `uuid4` when nothing is specified. The user object can contain additional data.
57
58#### `reducer` & `STATE_SLICE`
59
60The flopflop reducer should be wired up with a `combineReducers` within your application in coordination with the `STATE_SLICE` which is used internally too to manage the location of the feature toggle states.
61
62In context this configuration could look like:
63
64```js
65import { createStore, compose, applyMiddleware } from 'redux';
66import {
67 createFlopFlipEnhancer,
68 flopflipReducer,
69
70 // We refer to this state slice in the `injectFeatureToggles`
71 // HoC and currently do not support a custom state slice.
72 FLOPFLIP_STATE_SLICE
73} from 'flopflip';
74
75// Maintained somewhere within your application
76import user from './user';
77import appReducer from './reducer';
78
79const store = createStore(
80 combineReducers({
81 appReducer,
82 [FLOPFLIP_STATE_SLICE]: featureToggleReducer,
83 }),
84 initialState,
85 compose(
86 applyMiddleware(...),
87 createFlopFlipEnhancer(
88 // NOTE:
89 // This clientId is not secret to you and can be found
90 // within your settings on LaunchDarkly.
91 window.application.env.LD_CLIENT_ID,
92 user
93 )
94 )
95)
96```
97
98Whenever setup is not preferred via the store enhance the same can be achieved using the `ConfigureFlopFlip` component.
99
100It takes the `props`:
101
102- The `clientSideId` is your LaunchDarkly ID.
103- The `user` object needs at least a `key` attribute. An anonymous `key` will be generated using `uuid4` when nothing is specified. The user object can contain additional data.
104
105```js
106import { createStore, compose, applyMiddleware } from 'redux';
107import {
108 ConfigureFlopFlip,
109 flopflipReducer,
110 FLOPFLIP_STATE_SLICE
111} from 'flopflip';
112
113// Maintained somewhere within your application
114import user from './user';
115import appReducer from './reducer';
116
117const store = createStore(
118 combineReducers({
119 appReducer,
120 [FLOPFLIP_STATE_SLICE]: featureToggleReducer,
121 }),
122 initialState,
123 compose(
124 applyMiddleware(...),
125 )
126)
127
128// Somewhere where your <App /> is rendered
129
130<ConfigureFlopFlip user={user} clientSideId={clientSideId}>
131 <App />
132</ConfigureFlopFlip>
133```
134
135#### `FeatureToggled`
136
137The component renders its `children` depending on the state of a given feature flag. It also allows passing an optional `untoggledComponent` which will be rendered whenever the feature is disabled instead of `null`.
138
139```js
140import React, { Component } from 'react';
141
142import { FeatureToggled } from 'flopflip';
143import flagsNames from './feature-flags';
144
145export default (
146 <FeatureToggled
147 flag={flagsNames.THE_FEATURE_TOGGLE}
148 untoggledComponent={<h3>At least there is a fallback!</h3>}
149 >
150 <h3>I might be gone or there!</h3>
151 </FeatureToggled>
152);
153```
154
155#### `withFeatureToggle`
156
157A HoC to conditionally render a component based on a feature toggle's state. It accepts the feature toggle name and an optional component to be rendered in case the feature is disabled.
158
159Without a component rendered in place of the `ComponentToBeToggled`:
160
161```js
162import { withFeatureToggle } from 'flopflip';
163import flagsNames from './feature-flags';
164
165const ComponentToBeToggled = () => <h3>I might be gone or there!</h3>;
166
167export default withFeatureToggle(flagsNames.THE_FEATURE_TOGGLE)(
168 ComponentToBeToggled
169);
170```
171
172With a component rendered in place of the `ComponentToBeToggled`:
173
174```js
175import { withFeatureToggle } from 'flopflip';
176import flagsNames from './feature-flags';
177
178const ComponentToBeToggled = () => <h3>I might be gone or there!</h3>;
179const ComponentToBeRenderedInstead = () =>
180 <h3>At least there is a fallback!</h3>;
181
182export default withFeatureToggle(flagsNames.THE_FEATURE_TOGGLE)(
183 ComponentToBeToggled,
184 ComponentToBeRenderedInstead
185);
186```
187
188#### `injectFeatureToggles`
189
190This HoC matches feature toggles given against configured ones and injects the matching result. `withFeatureToggle` uses this to conditionally render a component.
191
192```js
193import { injectFeatureToggles } from 'flopflip';
194import flagsNames from './feature-flags';
195
196const Component = props => {
197 if (props.featureToggles[flagsNames.TOGGLE_A])
198 return <h3>Something to render!</h3>;
199 else if (props.featureToggles[flagsNames.TOGGLE_B])
200 return <h3>Something else to render!</h3>;
201
202 return <h3>Something different to render!</h3>;
203};
204
205export default injectFeatureToggles([flagsNames.TOGGLE_A, flagsNames.TOGGLE_B])(
206 Component
207);
208```
209
210The feature flags will be available as `props` within the component allowing some custom decisions based on their value.
211
212### Module formats
213
214`Flopflip` is built as a UMD module using [`rollup`](https://github.com/tdeekens/flopflip/blob/master/rollup.config.js). The distribution version is not added to `git` but created as a `preversion` [script](https://github.com/tdeekens/flopflip/blob/master/package.json).
215
216- ...ESM just import the `dist/flopflip.es.js` within your app.
217 - ...it's a transpiled version accessible via the `pkg.module`
218- ...CommonJS use the `dist/flopflip.umd.js`
219- ...AMD use the `dist/flopflip.umd.js`
220- ...`<script />` link it to `dist/flopflip.umd.js` or `dist/flopflip.umd.min.js`
221
222All build files are part of the npm distribution using the [`files`](https://github.com/tdeekens/flopflip/blob/master/package.json) array to keep install time short.
223
224Also feel free to use [unpkg.com](https://unpkg.com/flopflip@latest/dist/flopflip.umd.min.js) as a CDN to the [dist](https://unpkg.com/flopflip@latest/dist/) files.