diff --git a/.babelrc b/.babelrc index 17f6f7d..10d759f 100644 --- a/.babelrc +++ b/.babelrc @@ -1,18 +1,31 @@ { - "optional": ["runtime"], - "stage": 0, + "plugins": ["transform-runtime"], + "presets": [ "es2015", "stage-0", "react" ], "env": { "development": { - "plugins": ["react-transform"], - "extra": { - "react-transform": { - "transforms": [{ - "transform": "react-transform-hmr", - "imports": ["react"], - "locals": ["module"] - }] - } - } + "plugins": [ + [ "react-transform", { + "transforms": [ + { + "transform": "react-transform-hmr", + "imports": ["react"], + "locals": ["module"] + }, + { + "transform": "react-transform-catch-errors", + "imports": [ "react", "redbox-react" ] + } + ] + }] + ] + }, + "i18n": { + "plugins": [ + [ "react-intl", { + "messagesDir": "./_translations", + "enforceDescriptions": false + }] + ] } } } \ No newline at end of file diff --git a/.babelrc.i18n b/.babelrc.i18n deleted file mode 100644 index dedc368..0000000 --- a/.babelrc.i18n +++ /dev/null @@ -1,10 +0,0 @@ -{ - "optional": ["runtime"], - "stage": 0, - "plugins": ["react-intl"], - "extra": { - "react-intl": { - "messagesDir": "_translations" - } - } -} \ No newline at end of file diff --git a/README.md b/README.md index d053116..878f3fa 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,10 @@ http://emmenko.github.io/redux-react-router-async-example -This is a boilerplate example showcasing _mostly_ [Redux](https://github.com/gaearon/redux) and [React Router](https://github.com/rackt/react-router). +This is a boilerplate example showcasing _mostly_ [Redux](https://github.com/gaearon/redux) and [React Router](https://github.com/rackt/react-router) and it aims to provide different examples or use cases with the two libraries. -> Still a **WIP** but it aims to provide different examples or use cases with the two libraries. +##### The project will be constantly updated and improved with the latest dependencies, features, best practices and so on. + +> Check out the [migration to babel 6](https://github.com/emmenko/redux-react-router-async-example/pull/52). ## Features diff --git a/TODO.md b/TODO.md index 23147a2..aa7ace5 100644 --- a/TODO.md +++ b/TODO.md @@ -1,7 +1,7 @@ # TODO - JSDoc -- better error handling +- loading spinner for data fetching - use inline styles https://github.com/emmenko/redux-react-router-async-example/issues/7 - add use-case for `AsyncProps` - add use-case for external plugin https://dl.dropboxusercontent.com/u/4803975/ReactEurope/slides.pdf diff --git a/lib/Root.js b/lib/Root.js index 65784e9..190b8c9 100644 --- a/lib/Root.js +++ b/lib/Root.js @@ -48,7 +48,7 @@ function getRootChildren (props) { ] if (__DEVTOOLS__) { - const DevTools = require('./components/DevTools') + const DevTools = require('./components/DevTools').default rootChildren.push() } return rootChildren @@ -90,11 +90,10 @@ function logout (nextState, replaceState) { replaceState({}, '/login') } -@connect(({ application }) => ({ application })) -export default class Root extends React.Component { +class Root extends React.Component { static propTypes = { application: PropTypes.object.isRequired - } + }; render () { return ( @@ -102,3 +101,5 @@ export default class Root extends React.Component { ) } } + +export default connect(({ application }) => ({ application }))(Root) diff --git a/lib/components/Application.js b/lib/components/Application.js index addc5c0..e9ff7e0 100644 --- a/lib/components/Application.js +++ b/lib/components/Application.js @@ -8,7 +8,7 @@ export default class Application extends React.Component { static propTypes = { children: PropTypes.any - } + }; constructor (props, context) { super(props, context) diff --git a/lib/components/DevTools.js b/lib/components/DevTools.js index 806af92..ac6d9ef 100644 --- a/lib/components/DevTools.js +++ b/lib/components/DevTools.js @@ -5,8 +5,8 @@ import DockMonitor from 'redux-devtools-dock-monitor' export default createDevTools( + toggleVisibilityKey='ctrl-h' + changePositionKey='ctrl-q'> ) diff --git a/lib/components/DisplayError.js b/lib/components/DisplayError.js index 0739fb8..d671c69 100644 --- a/lib/components/DisplayError.js +++ b/lib/components/DisplayError.js @@ -7,7 +7,7 @@ class DisplayError extends React.Component { static propTypes = { hideError: PropTypes.func.isRequired, error: PropTypes.object - } + }; render () { const { props: { hideError, error } } = this diff --git a/lib/components/Menu.js b/lib/components/Menu.js index 39539bf..58d4d10 100644 --- a/lib/components/Menu.js +++ b/lib/components/Menu.js @@ -13,14 +13,13 @@ const menuItems = [ { text: 'Fork Me', link: GITHUB_REPO, icon: 'fa fa-github', isExternal: true } ] -@connect(({ application }) => ({ application }), applicationActions) -export default class Menu extends React.Component { +class Menu extends React.Component { static propTypes = { activeClass: PropTypes.string.isRequired, application: PropTypes.object.isRequired, switchLocale: PropTypes.func.isRequired - } + }; constructor (props, context) { super(props, context) @@ -58,3 +57,8 @@ export default class Menu extends React.Component { ) } } + +export default connect( + ({ application }) => ({ application }), + applicationActions +)(Menu) diff --git a/lib/components/MenuListItem.js b/lib/components/MenuListItem.js index 9d41cfc..37b7443 100644 --- a/lib/components/MenuListItem.js +++ b/lib/components/MenuListItem.js @@ -8,9 +8,9 @@ export default class MenuListItem extends Component { isExternal: PropTypes.bool, link: PropTypes.string.isRequired, text: PropTypes.string.isRequired - } + }; - static defaultProps = { isExternal: false } + static defaultProps = { isExternal: false }; render () { return ( diff --git a/lib/components/github/Explore.js b/lib/components/github/Explore.js index ea09da3..21f896a 100644 --- a/lib/components/github/Explore.js +++ b/lib/components/github/Explore.js @@ -27,11 +27,11 @@ export default class Explore extends React.Component { repo: PropTypes.string, username: PropTypes.string }) - } + }; static contextTypes = { history: PropTypes.object.isRequired - } + }; constructor (props) { super(props) diff --git a/lib/components/github/Pagination.js b/lib/components/github/Pagination.js index 340cbe6..d3aa1db 100644 --- a/lib/components/github/Pagination.js +++ b/lib/components/github/Pagination.js @@ -6,7 +6,7 @@ export default class Pagination extends React.Component { static propTypes = { onPagination: PropTypes.func, pagination: PropTypes.object - } + }; handlePaginationClick (link) { const page = link.url diff --git a/lib/components/github/Repo.js b/lib/components/github/Repo.js index b5c62b3..c26bcb1 100644 --- a/lib/components/github/Repo.js +++ b/lib/components/github/Repo.js @@ -4,17 +4,12 @@ import { fetchOnUpdate } from '../../decorators' import StargazersUser from './StargazersUser' import Pagination from './Pagination' -@fetchOnUpdate([ 'username', 'repo' ], (params, actions) => { - const { username, repo } = params - actions.fetchRepo({ username, repo }) - actions.fetchRepoStargazers({ username, repo }) -}) -export default class Repo extends React.Component { +class Repo extends React.Component { static propTypes = { actions: PropTypes.object, github: PropTypes.object - } + }; render () { const { github: { repo, stargazers } } = this.props @@ -87,3 +82,9 @@ export default class Repo extends React.Component { ) } } + +export default fetchOnUpdate([ 'username', 'repo' ], (params, actions) => { + const { username, repo } = params + actions.fetchRepo({ username, repo }) + actions.fetchRepoStargazers({ username, repo }) +})(Repo) diff --git a/lib/components/github/StargazersRepo.js b/lib/components/github/StargazersRepo.js index 25936c8..b0f444b 100644 --- a/lib/components/github/StargazersRepo.js +++ b/lib/components/github/StargazersRepo.js @@ -5,7 +5,7 @@ export default class StargazersRepo extends React.Component { static propTypes = { repo: PropTypes.object.isRequired - } + }; render () { const { repo } = this.props diff --git a/lib/components/github/StargazersUser.js b/lib/components/github/StargazersUser.js index 0fae294..48939bb 100644 --- a/lib/components/github/StargazersUser.js +++ b/lib/components/github/StargazersUser.js @@ -5,7 +5,7 @@ export default class StargazersUser extends React.Component { static propTypes = { user: PropTypes.object.isRequired - } + }; render () { const { user } = this.props diff --git a/lib/components/github/User.js b/lib/components/github/User.js index d432596..e5dfc52 100644 --- a/lib/components/github/User.js +++ b/lib/components/github/User.js @@ -4,17 +4,12 @@ import { fetchOnUpdate } from '../../decorators' import StargazersRepo from './StargazersRepo' import Pagination from './Pagination' -@fetchOnUpdate(['username'], (params, actions) => { - const { username } = params - actions.fetchUser({ username }) - actions.fetchUserStargazers({ username }) -}) -export default class User extends React.Component { +class User extends React.Component { static propTypes = { actions: PropTypes.object, github: PropTypes.object - } + }; render () { const { github: { user, stargazers } } = this.props @@ -67,3 +62,9 @@ export default class User extends React.Component { ) } } + +export default fetchOnUpdate(['username'], (params, actions) => { + const { username } = params + actions.fetchUser({ username }) + actions.fetchUserStargazers({ username }) +})(User) diff --git a/lib/components/pages/Account.js b/lib/components/pages/Account.js index c6c8ae9..2038233 100644 --- a/lib/components/pages/Account.js +++ b/lib/components/pages/Account.js @@ -4,7 +4,7 @@ export default class Account extends React.Component { static propTypes = { children: PropTypes.any - } + }; render () { return
{this.props.children}
diff --git a/lib/components/pages/GithubStargazers.js b/lib/components/pages/GithubStargazers.js index cdfce18..a411576 100644 --- a/lib/components/pages/GithubStargazers.js +++ b/lib/components/pages/GithubStargazers.js @@ -13,17 +13,12 @@ const messages = defineMessages({ } }) -@connect(state => ({ - github: state.github -}), dispatch => ({ - actions: bindActionCreators(githubActions, dispatch) -})) -export default class GithubStargazers extends React.Component { +class GithubStargazers extends React.Component { static propTypes = { children: PropTypes.any, actions: PropTypes.object - } + }; render () { return ( @@ -44,3 +39,8 @@ export default class GithubStargazers extends React.Component { ) } } + +export default connect( + ({ github }) => ({ github }), + dispatch => ({ actions: bindActionCreators(githubActions, dispatch) }) +)(GithubStargazers) diff --git a/lib/components/pages/Login.js b/lib/components/pages/Login.js index da3de9a..b33bdf0 100644 --- a/lib/components/pages/Login.js +++ b/lib/components/pages/Login.js @@ -5,12 +5,12 @@ export default class Login extends React.Component { static propTypes = { location: PropTypes.object - } + }; static contextTypes = { store: PropTypes.any, history: PropTypes.object.isRequired - } + }; constructor (props) { super(props) diff --git a/lib/components/pages/SuperSecretArea.js b/lib/components/pages/SuperSecretArea.js index 50561cf..147b74c 100644 --- a/lib/components/pages/SuperSecretArea.js +++ b/lib/components/pages/SuperSecretArea.js @@ -10,8 +10,7 @@ const messages = defineMessages({ } }) -@secure('manage_account') -export default class SuperSecretArea extends React.Component { +class SuperSecretArea extends React.Component { render () { return (
@@ -25,3 +24,5 @@ export default class SuperSecretArea extends React.Component { ) } } + +export default secure('manage_account')(SuperSecretArea) diff --git a/lib/decorators/fetchOnUpdate.js b/lib/decorators/fetchOnUpdate.js index d4593c9..cc08e36 100644 --- a/lib/decorators/fetchOnUpdate.js +++ b/lib/decorators/fetchOnUpdate.js @@ -15,7 +15,7 @@ export default function fetchOnUpdate (paramKeys, fn) { static propTypes = { actions: PropTypes.object, params: PropTypes.object - } + }; componentWillMount () { fn(mapParams(paramKeys, this.props.params), this.props.actions) diff --git a/lib/decorators/secure.js b/lib/decorators/secure.js index a98bf9e..eeff34e 100644 --- a/lib/decorators/secure.js +++ b/lib/decorators/secure.js @@ -8,7 +8,7 @@ export default function secure (scope) { static contextTypes = { store: PropTypes.any - } + }; render () { const { store } = this.context diff --git a/lib/index.js b/lib/index.js index f0524be..bb89db6 100644 --- a/lib/index.js +++ b/lib/index.js @@ -18,7 +18,7 @@ addLocaleData(it) // For that we need to patch in on runtime. if (!global.Intl) require.ensure(['intl'], require => { - require('intl') + require('intl').default start() }, 'IntlBundle') else start() diff --git a/lib/utils/configure-store.js b/lib/utils/configure-store.js index 57df1b6..0733a60 100644 --- a/lib/utils/configure-store.js +++ b/lib/utils/configure-store.js @@ -13,19 +13,21 @@ import * as reducers from '../reducers' const createHistory = process.env.NODE_ENV === 'production' ? createHashHistory : createBrowserHistory -let combinedCreateStore const storeEnhancers = [ persistenceStore, reduxReactRouter({ createHistory }) ] if (__DEVTOOLS__) { - const DevTools = require('../components/DevTools') + const DevTools = require('../components/DevTools').default storeEnhancers.push(DevTools.instrument()) } -combinedCreateStore = compose(...storeEnhancers)(createStore) -const finalCreateStore = applyMiddleware(thunk, logger)(combinedCreateStore) +const finalCreateStore = compose( + applyMiddleware(thunk, logger), + ...storeEnhancers +)(createStore) + const combinedReducer = combineReducers(Object.assign({ router: routerStateReducer }, reducers)) @@ -37,7 +39,7 @@ export default function configureStore (initialState) { if (module.hot) // Enable Webpack hot module replacement for reducers module.hot.accept('../reducers', () => { - const nextRootReducer = require('../reducers/index') + const nextRootReducer = require('../reducers').default store.replaceReducer(nextRootReducer) }) diff --git a/lib/utils/process-response.js b/lib/utils/process-response.js index 35cee79..9a8332d 100644 --- a/lib/utils/process-response.js +++ b/lib/utils/process-response.js @@ -6,7 +6,6 @@ export default function processResponse (response) { try { body = JSON.parse(body) } catch (error) { if (isOk) isOk = false } - console.log(body, response) if (isOk) return body throw { ...body, statusCode: response.status } diff --git a/package.json b/package.json index 5f5117b..11cce92 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ }, "scripts": { "build": "npm run clean && npm run lint && webpack", - "build:i18n": "rimraf _translations && babel --quiet --babelrc .babelrc.i18n lib > /dev/null", + "build:i18n": "rimraf _translations && BABEL_ENV=i18n babel --quiet lib > /dev/null", "build:i18n:langs": "npm run build:i18n && babel-node scripts/i18nToXliff.js", "clean": "rimraf dist", "deploy": "npm run dist && gh-pages -d dist", @@ -25,49 +25,55 @@ "test": "echo \"Error: no test specified\" && exit 1" }, "dependencies": { - "babel-runtime": "~5.8.29", - "classnames": "~2.2.1", - "history": "~1.13.1", + "classnames": "~2.2.3", + "history": "~1.17.0", "intl": "~1.0.1", "parse-link-header": "~0.4.1", "purecss": "~0.6.0", - "react": "~0.14.3", - "react-dom": "~0.14.3", + "react": "~0.14.6", + "react-dom": "~0.14.6", "react-intl": "2.0.0-beta-1", "react-pure-render": "~1.0.2", - "react-redux": "~4.0.1", - "react-router": "~1.0.2", + "react-redux": "~4.0.6", + "react-router": "~1.0.3", "redux": "~3.0.5", - "redux-devtools": "~3.0.0", - "redux-devtools-dock-monitor": "~1.0.1", - "redux-devtools-log-monitor": "~1.0.1", - "redux-router": "~1.0.0-beta5", - "redux-thunk": "~1.0.2", + "redux-router": "~1.0.0-beta7", + "redux-thunk": "~1.0.3", "whatwg-fetch": "~0.10.1" }, "devDependencies": { - "babel": "^5.8.29", - "babel-core": "^5.8.32", - "babel-eslint": "^4.1.3", - "babel-loader": "^5.3.2", - "babel-plugin-react-intl": "^1.0.0-beta-5", - "babel-plugin-react-transform": "^1.1.1", - "css-loader": "^0.23.0", + "babel-cli": "^6.4.0", + "babel-core": "^6.4.0", + "babel-eslint": "^5.0.0-beta6", + "babel-loader": "^6.2.1", + "babel-plugin-react-intl": "^2.0.0", + "babel-plugin-react-transform": "^2.0.0", + "babel-plugin-transform-decorators": "^6.4.0", + "babel-plugin-transform-runtime": "^6.4.0", + "babel-polyfill": "^6.3.14", + "babel-preset-es2015": "^6.3.13", + "babel-preset-react": "^6.3.13", + "babel-preset-stage-0": "^6.3.13", + "babel-runtime": "^6.3.19", + "css-loader": "^0.23.1", "cssnext-loader": "^1.0.1", "eslint": "^1.10.3", - "eslint-plugin-react": "^3.11.3", + "eslint-plugin-react": "^3.14.0", "express": "^4.13.3", - "extract-text-webpack-plugin": "^0.9.1", + "extract-text-webpack-plugin": "^1.0.1", "gh-pages": "^0.8.0", - "glob": "^6.0.1", + "glob": "^6.0.4", "html-webpack-plugin": "^1.7.0", "mkdirp": "^0.5.1", - "react-transform-catch-errors": "^1.0.0", + "react-transform-catch-errors": "^1.0.1", "react-transform-hmr": "^1.0.1", "redbox-react": "^1.2.0", - "rimraf": "^2.4.4", + "redux-devtools": "~3.0.1", + "redux-devtools-dock-monitor": "~1.0.1", + "redux-devtools-log-monitor": "~1.0.1", + "rimraf": "^2.5.0", "style-loader": "^0.13.0", - "webpack": "^1.12.9", + "webpack": "^1.12.10", "webpack-dev-middleware": "^1.4.0", "webpack-hot-middleware": "^2.6.0" } diff --git a/webpack.config.js b/webpack.config.js index 1592a36..f56906f 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -5,6 +5,7 @@ var HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { devtool: 'cheap-module-eval-source-map', entry: [ + 'babel-polyfill', 'webpack-hot-middleware/client', './lib/index' ], @@ -32,7 +33,7 @@ module.exports = { module: { loaders: [ { test: /\.css$/, loader: 'style-loader!css-loader!cssnext-loader' }, - { test: /\.js$/, loaders: ['babel'], include: path.join(__dirname, 'lib') } + { test: /\.js$/, loader: 'babel', include: path.join(__dirname, 'lib') } ] }, cssnext: { diff --git a/webpack.config.production.js b/webpack.config.production.js index 32bddd1..d5ca095 100644 --- a/webpack.config.production.js +++ b/webpack.config.production.js @@ -5,7 +5,7 @@ var HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: { - app: './lib/index.js' + app: [ 'babel-polyfill', './lib/index.js' ] }, output: { filename: '[name].min.js',