Skip to content

Commit d16e7f6

Browse files
authored
v2.0.0 beta.7 (#252)
* fix(reducer): allow setting paths ending in numbers - #248 * feat(auth): make signInWithCredential not dependent on provider - #247 * `signInWithCustomToken` no longer decodes token internally for profile data (`profileFactory` should be used) - #244 * Removed `jwt-decode` as a dependency (not needed since auth token no longer decoded internally) * Support lazy/module loading - #249, #250 * Updated SSR docs to include notes about `enableRedirectHanlding: false` - #251 * Updated Roadmap with detection of non-http environments
1 parent 0e56bdb commit d16e7f6

File tree

19 files changed

+185
-163
lines changed

19 files changed

+185
-163
lines changed

README.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,11 @@ const config = {
8080
const rrfConfig = { userProfile: 'users' } // react-redux-firebase config
8181

8282
// initialize firebase instance
83-
firebase.initializeApp(config) // <- new to v2.*.*
83+
const firebaseApp = firebase.initializeApp(config) // <- new to v2.*.*
8484

8585
// Add reduxReduxFirebase to compose
8686
const createStoreWithFirebase = compose(
87-
reactReduxFirebase(firebase, rrfConfig), // firebase instance as first argument
87+
reactReduxFirebase(firebaseApp, rrfConfig), // firebase instance as first argument
8888
)(createStore)
8989

9090
// Create store with reducers and initial state
@@ -207,7 +207,6 @@ In order to enable this functionality, you will most likely need to install a pl
207207
}
208208
```
209209

210-
211210
## [Docs](http://react-redux-firebase.com)
212211
See full documentation at [react-redux-firebase.com](http://react-redux-firebase.com)
213212

docs/api/compose.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Middleware that handles configuration (placed in redux's
1111

1212
**Parameters**
1313

14-
- `fbConfig`
14+
- `fbApp`
1515
- `otherConfig`
1616

1717
**Properties**

docs/recipes/populate.md

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,28 @@ const populates = [
2727

2828
### Populate Profile Parameters
2929

30-
To Populate parameters within profile/user object, include the `profileParamsToPopulate` parameter when [calling `reactReduxFirebase` in your compose function](/api/compose).
30+
To Populate parameters within profile/user object, include the `profileParamsToPopulate` parameter when [calling `reactReduxFirebase` in your compose function](/api/compose) as well as using `populate`.
31+
32+
**NOTE** Using `profileParamsToPopulate` no longer automatically populates profile, you must use `populate`. Un-populated profile lives within state under `state.firebase.profile`.
3133

3234
#### Examples
3335

34-
##### Populate List of Items
36+
##### Populate Role
37+
38+
Populating a user's role parameter from a list of roles (under `roles` collection).
3539

3640
```javascript
41+
export const profilePopulates = [{ child: 'role', root: 'roles' }]
3742
const config = {
3843
userProfile: 'users',
39-
profileParamsToPopulate: [ 'todos:todos' ] // populate list of todos from todos ref
44+
profileParamsToPopulate: profilePopulates // populate list of todos from todos ref
4045
}
46+
47+
// In component
48+
@connect(
49+
({ firebase }) => ({
50+
profile: firebase.profile,
51+
populatedProfile: populate(firebase, 'profile', profilePopulates),
52+
})
53+
)
4154
```

docs/recipes/ssr.md

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
11
# Server Side Rendering
22

3-
## Implement with webpack
3+
### Disable Redirect Handling
4+
5+
Support automatically detecting non-HTTP environments has been added as of [`v2.0.0-beta.7`](https://github.com/prescottprue/react-redux-firebase/releases/tag/v2.0.0-beta.7), which means you can skip the rest of this section.
6+
7+
If using earlier than `v2.0.0-beta.7`:
8+
9+
By default a redirect handling listener is set up, which will not work in environments without HTTP. Currently, for SSR, you must disable this redirect handling listener to keep an error from appearing (see [#251](https://github.com/prescottprue/react-redux-firebase/issues/251) for more info).
410

5-
### Make Sure Loaders are setup appropriately
6-
Note, make sure that you have excluded `node_modules` in your webpack loaders
711

812
```js
9-
// webpack 1
10-
exclude: /node_modules/,
11-
// or webpack 2
12-
options: { presets: [ [ 'es2015', { modules: false } ] ] }
13+
// disable redirect listener setup (happens by default)
14+
const config = {
15+
enableRedirectHandling: false
16+
}
17+
18+
reactReduxFirebase(firebaseInstance, config)
1319
```
1420

1521

@@ -21,3 +27,17 @@ global.XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest
2127
```
2228

2329
If you find adding this extra code to be an annoyance or you would like to discuss a different way to do it, please feel free to open an issue/pull request or reach out on [gitter](https://gitter.im/redux-firebase/Lobby).
30+
31+
32+
33+
## Implement with Webpack
34+
35+
### Make Sure Loaders are setup appropriately
36+
Note, make sure that you have excluded `node_modules` in your webpack loaders
37+
38+
```js
39+
// webpack 1
40+
exclude: /node_modules/,
41+
// or webpack 2
42+
options: { presets: [ [ 'es2015', { modules: false } ] ] }
43+
```

docs/roadmap.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@
8989
#### Breaking Changes
9090
* Remove usage of `Immutable.js` and Immutable Maps (no more need for `pathToJS()` & `dataToJS()` to load data from redux)
9191
* Firebase is now initialized outside of `react-redux-firebase` - [#173](https://github.com/prescottprue/react-redux-firebase/issues), [#131](https://github.com/prescottprue/react-redux-firebase/issues), [#107](https://github.com/prescottprue/react-redux-firebase/issues)
92+
* `login` with custom token no longer internally decodes JWT (use `profileFactory` instead to include token data on profile)
9293
* reducer split into multiple nested reducers for a few reasons:
9394
* follows [standard for nesting of reducers using combine reducers](http://redux.js.org/docs/recipes/reducers/UpdatingNormalizedData.html)).
9495
* allows for separately importable reducers (for placing in other parts of redux other than `state.firebase`)
@@ -100,12 +101,12 @@
100101
* `AuthRequired` decorator (or decorator factory) that forces auth to exist before rendering component
101102
* Support native modules through [`react-native-firebase`](https://github.com/invertase/react-native-firebase) - [#131](https://github.com/prescottprue/react-redux-firebase/issues/131)
102103
* Track online users and sessions by passing `presence` config option
103-
104-
#### Enhancements/Fixes
104+
* Detect Non-HTTP environments (such as with SSR) so that `enableRedirectHandling: false` is not required in config
105+
* Allowing `presence` setting to accept a function for dynamically building presence path based on auth
106+
* Firebase app can now be passed instead of full firebase lib (pass around a smaller object) - [#249](https://github.com/prescottprue/react-redux-firebase/issues/250), [#250](https://github.com/prescottprue/react-redux-firebase/issues/250)
105107
* Implement [`firebase-server`](https://github.com/urish/firebase-server) for tests instead of using demo firebase instance
106108

107109
#### Under Consideration
108-
* Allowing `presence` setting to accept a function for dynamically building presence path based on auth
109110
* Possibility of delayed initialization - [#70](https://github.com/prescottprue/react-redux-firebase/issues/70) (more research needed)
110111

111112
### Long Term Goals

examples/complete/material/config/webpack.config.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
const webpack = require('webpack')
2+
const path = require('path')
23
const cssnano = require('cssnano')
34
const HtmlWebpackPlugin = require('html-webpack-plugin')
45
const ExtractTextPlugin = require('extract-text-webpack-plugin')
@@ -19,6 +20,10 @@ const webpackConfig = {
1920
root: project.paths.client(),
2021
extensions: ['', '.js', '.jsx', '.json']
2122
},
23+
alias: {
24+
// fix issue of loading multiple versions of react
25+
react: path.resolve('./node_modules/react'),
26+
},
2227
module: {}
2328
}
2429
// ------------------------------------
@@ -113,10 +118,11 @@ if (!__TEST__) {
113118
// JavaScript / JSON
114119
webpackConfig.module.loaders = [{
115120
test: /\.(js|jsx)$/,
116-
exclude: [ /node_modules/, /react-redux-firebase\/dist/ /* exclude any npm-linked modules here */ ],
121+
exclude: [ /node_modules/, /react-redux-firebase\/lib\// /* exclude any npm-linked modules here */ ],
117122
loader: 'babel',
118123
query: project.compiler_babel
119124
}, {
125+
exclude: [ /node_modules/, /react-redux-firebase\/lib\// /* exclude any npm-linked modules here */ ],
120126
test: /\.json$/,
121127
loader: 'json'
122128
}]

examples/complete/material/src/store/createStore.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ import thunk from 'redux-thunk'
33
import { browserHistory } from 'react-router'
44
import { reactReduxFirebase, getFirebase } from 'react-redux-firebase'
55
import logger from 'redux-logger'
6-
import firebase from 'firebase'
6+
import firebase from 'firebase/app'
7+
import 'firebase/auth'
8+
import 'firebase/database'
79
import { firebase as fbConfig, reduxFirebase as reduxConfig } from '../config'
810
import makeRootReducer from './reducers'
911
import { updateLocation } from './location'
@@ -29,7 +31,7 @@ export default (initialState = {}, history) => {
2931
}
3032
}
3133

32-
firebase.initializeApp(fbConfig)
34+
const firebaseApp = firebase.initializeApp(fbConfig)
3335

3436
// ======================================================
3537
// Store Instantiation and HMR Setup
@@ -38,7 +40,7 @@ export default (initialState = {}, history) => {
3840
makeRootReducer(),
3941
initialState,
4042
compose(
41-
reactReduxFirebase(firebase, reduxConfig),
43+
reactReduxFirebase(firebaseApp, reduxConfig),
4244
applyMiddleware(...middleware),
4345
...enhancers
4446
)

package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-redux-firebase",
3-
"version": "2.0.0-beta.6",
3+
"version": "2.0.0-beta.7",
44
"description": "Redux integration for Firebase. Comes with a Higher Order Component for use with React.",
55
"main": "lib/index.js",
66
"module": "es/index.js",
@@ -58,7 +58,6 @@
5858
],
5959
"dependencies": {
6060
"hoist-non-react-statics": "^2.2.2",
61-
"jwt-decode": "^2.2.0",
6261
"lodash": "^4.17.4",
6362
"prop-types": "^15.5.10"
6463
},

src/actions/auth.js

Lines changed: 39 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
import jwtDecode from 'jwt-decode'
21
import {
3-
omit,
42
isArray,
53
isString,
64
isFunction,
75
forEach
86
} from 'lodash'
9-
import { actionTypes, defaultJWTProps } from '../constants'
7+
import { actionTypes } from '../constants'
108
import { getLoginMethodAndParams } from '../utils/auth'
119
import { promisesForPopulate } from '../utils/populate'
1210

@@ -46,11 +44,10 @@ export const unWatchUserProfile = (firebase) => {
4644
* @private
4745
*/
4846
export const watchUserProfile = (dispatch, firebase) => {
49-
const authUid = firebase._.authUid
50-
const userProfile = firebase._.config.userProfile
47+
const { authUid, config: { userProfile } } = firebase._
5148
unWatchUserProfile(firebase)
5249

53-
if (firebase._.config.userProfile) {
50+
if (userProfile && firebase.database) {
5451
firebase._.profileWatch = firebase.database()
5552
.ref()
5653
.child(`${userProfile}/${authUid}`)
@@ -100,20 +97,24 @@ export const watchUserProfile = (dispatch, firebase) => {
10097
* @private
10198
*/
10299
export const createUserProfile = (dispatch, firebase, userData, profile) => {
103-
const { database, _: { config } } = firebase
104-
if (!config.userProfile) {
100+
const { _: { config } } = firebase
101+
if (!config.userProfile || !firebase.database) {
105102
return Promise.resolve(userData)
106103
}
107-
try {
108-
if (isFunction(config.profileFactory)) {
104+
105+
// use profileFactory if it exists in config
106+
if (isFunction(config.profileFactory)) {
107+
// catch errors in user provided profileFactory function
108+
try {
109109
profile = config.profileFactory(userData, profile)
110+
} catch (err) {
111+
console.error('Error occured within profileFactory function:', err.message || err) // eslint-disable-line no-console
112+
return Promise.reject(err)
110113
}
111-
} catch (err) {
112-
console.error('Error occured within profileFactory function:', err.toString ? err.toString() : err) // eslint-disable-line no-console
113-
return Promise.reject(err)
114114
}
115+
115116
// Check for user's profile at userProfile path if provided
116-
return database()
117+
return firebase.database()
117118
.ref()
118119
.child(`${config.userProfile}/${userData.uid}`)
119120
.once('value')
@@ -141,7 +142,10 @@ export const createUserProfile = (dispatch, firebase, userData, profile) => {
141142
* @private
142143
*/
143144
const setupPresence = (dispatch, firebase) => {
144-
// TODO: Enable more settings here (enable/disable sessions, store past sessions)
145+
// exit if database does not exist on firebase instance
146+
if (!firebase.database) {
147+
return
148+
}
145149
const ref = firebase.database().ref()
146150
const { config: { presence, sessions }, authUid } = firebase._
147151
let amOnline = ref.child('.info/connected')
@@ -183,8 +187,11 @@ const setupPresence = (dispatch, firebase) => {
183187
* @private
184188
*/
185189
export const init = (dispatch, firebase) => {
190+
// exit if auth does not exist
191+
if (!firebase.auth) {
192+
return
193+
}
186194
dispatch({ type: actionTypes.AUTHENTICATION_INIT_STARTED })
187-
188195
firebase.auth().onAuthStateChanged(authData => {
189196
if (!authData) {
190197
// Run onAuthStateChanged if it exists in config and enableEmptyAuthChanges is set to true
@@ -195,9 +202,12 @@ export const init = (dispatch, firebase) => {
195202
}
196203

197204
firebase._.authUid = authData.uid
205+
206+
// setup presence if settings exist
198207
if (firebase._.config.presence) {
199208
setupPresence(dispatch, firebase)
200209
}
210+
201211
watchUserProfile(dispatch, firebase)
202212

203213
dispatch({ type: actionTypes.LOGIN, auth: authData })
@@ -209,11 +219,16 @@ export const init = (dispatch, firebase) => {
209219
})
210220

211221
// set redirect result callback if enableRedirectHandling set to true
212-
if (firebase._.config.enableRedirectHandling) {
222+
if (firebase._.config.enableRedirectHandling && (
223+
typeof window !== 'undefined' &&
224+
window.location &&
225+
window.location.protocol &&
226+
window.location.protocol.indexOf('http') !== -1
227+
)) {
213228
firebase.auth().getRedirectResult()
214229
.then((authData) => {
215230
// Run onRedirectResult if it exists in config
216-
if (firebase._.config.onRedirectResult) {
231+
if (typeof firebase._.config.onRedirectResult === 'function') {
217232
firebase._.config.onRedirectResult(authData, firebase, dispatch)
218233
}
219234
if (authData && authData.user) {
@@ -236,7 +251,8 @@ export const init = (dispatch, firebase) => {
236251
}
237252
)
238253
}
239-
}).catch((error) => {
254+
})
255+
.catch((error) => {
240256
dispatchLoginError(dispatch, error)
241257
return Promise.reject(error)
242258
})
@@ -276,15 +292,13 @@ export const login = (dispatch, firebase, credentials) => {
276292

277293
// For token auth, the user key doesn't exist. Instead, return the JWT.
278294
if (method === 'signInWithCustomToken') {
279-
// Extract the extra data in the JWT token for user object
280-
const { stsTokenManager: { accessToken }, uid } = userData.toJSON()
281-
const extraJWTData = omit(jwtDecode(accessToken), defaultJWTProps)
282-
295+
if (!firebase._.config.updateProfileOnLogin) {
296+
return { user: userData }
297+
}
283298
return createUserProfile(
284299
dispatch,
285300
firebase,
286-
{ uid },
287-
{ ...extraJWTData, uid }
301+
userData
288302
)
289303
}
290304

src/actions/query.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,17 @@ export const watchEvent = (firebase, dispatch, { type, path, populates, queryPar
4747
.child(path)
4848
.orderByKey()
4949
.limitToFirst(1)
50-
.once('value', snapshot => {
50+
.once('value')
51+
.then(snapshot => {
5152
if (snapshot.val() === null) {
5253
dispatch({
5354
type: NO_VALUE,
5455
path: storeAs || path
5556
})
5657
}
5758
return snapshot
58-
}, (err) => {
59+
})
60+
.catch(err => {
5961
// TODO: Handle catching unauthorized error
6062
// dispatch({
6163
// type: UNAUTHORIZED_ERROR,
@@ -95,7 +97,8 @@ export const watchEvent = (firebase, dispatch, { type, path, populates, queryPar
9597
})
9698
}
9799
return snapshot
98-
}, (err) => {
100+
})
101+
.catch(err => {
99102
dispatch({
100103
type: UNAUTHORIZED_ERROR,
101104
payload: err

0 commit comments

Comments
 (0)