master ea1cca81f18c cached
48 files
77.3 KB
20.5k tokens
15 symbols
1 requests
Download .txt
Repository: dvdzkwsk/react-redux-starter-kit
Branch: master
Commit: ea1cca81f18c
Files: 48
Total size: 77.3 KB

Directory structure:
gitextract_602yozfj/

├── .editorconfig
├── .eslintignore
├── .eslintrc
├── .gitignore
├── .travis.yml
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── build/
│   ├── karma.config.js
│   ├── lib/
│   │   └── logger.js
│   ├── scripts/
│   │   ├── compile.js
│   │   └── start.js
│   └── webpack.config.js
├── package.json
├── project.config.js
├── public/
│   ├── humans.txt
│   └── robots.txt
├── server/
│   └── main.js
├── src/
│   ├── components/
│   │   └── App.js
│   ├── index.html
│   ├── layouts/
│   │   └── PageLayout/
│   │       ├── PageLayout.js
│   │       └── PageLayout.scss
│   ├── main.js
│   ├── normalize.js
│   ├── routes/
│   │   ├── Counter/
│   │   │   ├── components/
│   │   │   │   └── Counter.js
│   │   │   ├── containers/
│   │   │   │   └── CounterContainer.js
│   │   │   ├── index.js
│   │   │   └── modules/
│   │   │       └── counter.js
│   │   ├── Home/
│   │   │   ├── components/
│   │   │   │   ├── HomeView.js
│   │   │   │   └── HomeView.scss
│   │   │   └── index.js
│   │   └── index.js
│   ├── store/
│   │   ├── createStore.js
│   │   ├── location.js
│   │   └── reducers.js
│   └── styles/
│       ├── _base.scss
│       └── main.scss
└── tests/
    ├── .eslintrc
    ├── layouts/
    │   └── PageLayout.spec.js
    ├── routes/
    │   ├── Counter/
    │   │   ├── components/
    │   │   │   └── Counter.spec.js
    │   │   ├── index.spec.js
    │   │   └── modules/
    │   │       └── counter.spec.js
    │   └── Home/
    │       ├── components/
    │       │   └── HomeView.spec.js
    │       └── index.spec.js
    ├── store/
    │   ├── createStore.spec.js
    │   └── location.spec.js
    └── test-bundler.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .editorconfig
================================================
# http://editorconfig.org

# A special property that should be specified at the top of the file outside of
# any sections. Set to true to stop .editor config file search on current file
root = true

[*]
# Indentation style
# Possible values - tab, space
indent_style = space

# Indentation size in single-spaced characters
# Possible values - an integer, tab
indent_size = 2

# Line ending file format
# Possible values - lf, crlf, cr
end_of_line = lf

# File character encoding
# Possible values - latin1, utf-8, utf-16be, utf-16le
charset = utf-8

# Denotes whether to trim whitespace at the end of lines
# Possible values - true, false
trim_trailing_whitespace = true

# Denotes whether file should end with a newline
# Possible values - true, false
insert_final_newline = true


================================================
FILE: .eslintignore
================================================
coverage/**
node_modules/**
dist/**
src/index.html


================================================
FILE: .eslintrc
================================================
{
  "parser": "babel-eslint",
  "extends": [
    "standard",
    "standard-react"
  ],
  "plugins": [
    "babel",
    "react",
    "promise"
  ],
  "env": {
    "browser" : true
  },
  "globals": {
    "__DEV__"      : false,
    "__TEST__"     : false,
    "__PROD__"     : false,
    "__COVERAGE__" : false
  },
  "rules": {
    "key-spacing"          : "off",
    "jsx-quotes"           : [2, "prefer-single"],
    "max-len"              : [2, 120, 2],
    "object-curly-spacing" : [2, "always"],
    "comma-dangle"         : "off"
  }
}


================================================
FILE: .gitignore
================================================
.DS_STORE
*.log
node_modules
dist
coverage
.idea/
.yarn-cache


================================================
FILE: .travis.yml
================================================
sudo: false
language: node_js
node_js:
  - "5"
  - "6"

cache:
  yarn: true
  directories:
    - node_modules

script:
  - yarn lint
  - yarn test
  - yarn build

after_success:
  - yarn codecov


================================================
FILE: CHANGELOG.md
================================================
Changelog
=========

3.0.1
-------------

### Improvements
* Added Node `^5.0.0` to CI build

### Fixes
* Removed usage of the spread operator for function arguments
* Added missing `fs-extra` dependency

3.0.0
-------------

### Features
* Upgraded webpack to `^2.0.0` (along with all associated dependencies)
* Upgraded react to `^15.5.4`
* Upgraded react-dom to `^15.5.4`
* Upgraded react-redux to `^5.0.4`
* Upgraded redbox-react to `^5.0.4`
* Upgraded bootstrap to `^4.0.0-alpha`
* Replaced 3rd-party bootstrap import with local dependency
* Replaced `babel-preset-stage-1` and friends with `babel-preset-env`
* Added normalizer bundler for JavaScript (`Promise`, `fetch`, and `Object.assign`)
* Added `dirty-chai`

### Improvements
* Replaced PropTypes usage with `prop-types` package
* Simplified project structure and configuration
* Replaced postcss-loader usage with css-loader builtins
* Webpack manifest is now bundled separately from vendor bundle (improves caching)
* Replaced `file-loader` with `url-loader`
* Moved all build-related dependencies back to `devDependencies`
* Replaced `better-npm-run` with `cross-env`
* Cleaned up some sloppy tests

### Fixes
* `console.log` now works correctly inside of Karma

### Deprecations
* Code coverage reporting has been temporarily removed
* Support for `.css` files has been temporarily removed (use `.scss` or `.sass`)
* Removed `normalize.css` since this is now provided by bootstrap

3.0.0-alpha.0
-------------

### Improvements
* Migrated to Fractal Project Structure, huge thanks to [justingreenberg](https://github.com/justingreenberg). See https://github.com/davezuko/react-redux-starter-kit/pull/684 for details and discussion.

2.0.0
-----

### Features
* Upgraded `eslint-plugin-react` to `^5.0.0`
* Upgraded `fs-extra` to `^0.28.0`

### Improvements
* Updated syntax used for `createStore` to match `redux@^3.1.0`
* Cleaned up `connect` decorator in `HomeView`
* Cleaned up flow types in `HomeView`

2.0.0-alpha.5
-------------

### Features
* Upgraded `flow-bin` to `0.23.0`
* Upgraded `fs-extra` to `^0.27.0`

### Improvements
* Minor cleanup in Karma configuration
* Added missing node-style index files in blueprints

### Fixes
* Modified webpack manifest initialization to prevent syntax errors in some environments (https://github.com/davezuko/react-redux-starter-kit/issues/572)

2.0.0-alpha.4
-------------

### Features
* Upgraded `react` to `^15.0.0`
* Upgraded `react-dom` to `^15.0.0`
* Upgraded `react-addons-test-utils` to `^15.0.0`
* Upgraded `eslint-plugin-flow-vars` to `^0.3.0`

### Improvements
* Updated `npm run deploy` to be environment agnostic (no longer forces `production`)
* Added `npm run deploy:prod` (forces `production`, acts as old `npm run deploy`)
* Added `npm run deploy:dev` (forces `development`)

### Fixes
* Removed `strip_root` option in Flow to support Nuclide
* Updated webpack development configuration to use correct `public_path`


2.0.0-alpha.3
-------------

### Features
* Upgraded `flow-interfaces` to `^0.6.0`

### Improvements
* Moved dependencies needed for production builds from devDependencies to regular dependencies

### Fixes
* Production configuration now generates assets with absolute rather than relative paths

### Deprecations
* Removed `eslint-loader` for performance reasons

2.0.0-alpha.2
-------------

### Features
* Upgraded `eslint` to `^2.4.0`
* Upgraded `babel-eslint` to `^6.0.0-beta.6`
* Upgraded `better-npm-run` to `0.0.8`
* Upgraded `phantomjs-polyfill` to `0.0.2`
* Upgraded `karma-mocha-reporter` to `^2.0.0`
* Upgraded `webpack` to `^1.12.14`
* Upgraded `redux-thunk` to `^2.0.0`

### Improvements
* Added `index.js` files for blueprints for convenient imports

### Fixes
* Removed some `cssnano` options that caused potential conflicts with css modules
* Updated flow to understand global webpack definitions

2.0.0-alpha.1
-------------

### Features
* Upgraded `react-router-redux` from `^4.0.0-beta` to `^4.0.0`

2.0.0-alpha.0
-------------

### Features
* Integrated with [redux-cli](https://github.com/SpencerCDixon/redux-cli)
* Added support for [Flowtype](http://flowtype.org/)
* Added `npm run flow:check` script
* Added [chai-enzyme](https://github.com/producthunt/chai-enzyme)
* Added `babel-plugin-transform-react-constant-elements` in production
* Added `babel-plugin-transform-react-remove-prop-types` in production
* Added `eslint-plugin-flowvars`
* Added `better-npm-run`
* Added loader for `.otf` files
* Added `nodemon` for local server development
* Added placeholder favicon, `humans.txt`, and `robots.txt`
* Replaced `express` with `koa@^2.0.0-alpha`
* Added `koa-proxy` with config support
* Added `koa-conntect-history-api-fallback`
* Upgraded `eslint` to `^2.0.0`
* Upgraded `babel-eslint` to `^5.0.0`
* Upgraded `eslint-plugin-react` to `^4.0.0`
* Upgraded `yargs` to `^4.0.0`
* Upgraded `html-webpack-plugin` from `^1.6.1` to `^2.7.1`
* Upgraded `react-router` to `^2.0.0`
* Replaced `redux-simple-router` with `react-router-redux`
* Replaced `phantomjs` with `phantomjs-prebuilt`
* Replaced Karma spec reporter with mocha reporter

### Improvements
* Webpack optimization plugins are now correctly used only in production
* Added ability to simultaneously use CSS modules and regular CSS
* Added `karma-webpack-with-fast-source-maps` for selective and faster test rebuilds
* Simplified environment-based webpack configuration
* Fixed CSS being minified twice with both `cssnano` and `css-loader`
* Updated `cssnano` to not use unsafe options by default
* Redux devtools now looks for the browser extension if available
* Added webpack entry point for tests to replace file globs in Karma
* Made Webpack compiler script generic so it can accept any webpack configuration file
* Added sample tests for counter redux module
* Replaced `react-hmre` with `redbox-react` and `react-transform-hmr`
* Disabled verbose uglify warnings during compilation
* Updated route definition file to have access to the redux store
* Updated server start message so link is clickable
* `ExtractTextPlugin` is now correctly used whenever HMR is disabled
* `npm run deploy` now cleans out `~/dist` directory
* Miscellaneous folder structure improvements
* Removed unnecessary `bin` file for Karma
* Removed unnecessary `NotFoundView`
* Re-enabled support for `.jsx` files
* Specified compatible Node and NPM engines

### Fixes
* Fixed some development-only code not being stripped from production bundles
* Added rimraf for `~/dist` clearing to support Windows users
* Fixed miscellaneous path issues for Windows users
* Fixed source maps for Sass files
* Updated server start debug message to display correct host

### Deprecations
* Removed `redux-actions`
* Removed `dotenv`
* Removed `add-module-exports` babel plugin

1.0.0
-----

### Features
* Upgraded from Babel 5 to Babel 6 :tada:
* Added script to copy static assets from ~src/assets to ~/dist during compilation
* Added CSS Modules (can be toggled on/off in config file)
* Enabled source maps for CSS
* Added `postcss-loader`
* Added `debug` module to replace `console.log`
* Added `json-loader`
* Added `url-loader` for `(png|jpg)` files
* Added `redux-actions` with demo
* Upgraded `redux-devtools` from `^3.0.0-beta` to `^3.0.0`
* Upgraded `redux-simple-router` from `^0.0.10` to `^1.0.0`
* Upgraded `isparta` from `^2.0.0` to `^3.0.0`
* Replaced `karma-sinon-chai` with `karma-chai-sinon` for peerDependencies fix
* Added sample asynchronous action
* Added example `composes` style to demo CSS modules in `HomeView`
* Added `lint:fix` npm script
* Added CONTRIBUTING document
* Added placeholder favicon

### Improvements
* Refactored application to follow ducks-like architecture
* Improved how configuration determines when to apply HMR-specific Babel transforms
* Replaced explicit aliases with `resolve.root`
* Renamed karma configuration file to more widely-known `karma.conf`
* Made `CoreLayout` a pure (stateless) component
* Renamed debug namespace from `kit:*` to `app:*`
* Standardized coding conventions
* Added ability to easily specify environment-specific configuration overrides
* Extended available configuration options
* Improved miscellaneous documentation
* Refactored webpack middleware in express server into separate files

### Fixes
* Fixed DevTools imports so they are longer included in production builds
* Added CSS best practices to root tag, node, and `core.scss` file
* Disabled manifest extraction due to broken production builds
* Updated Webpack dev server uses explicit publicPath during live development
* Fixed Karma running tests twice after file change during watch mode

### Deprecations
* Removed `eslint-config-airbnb`
* Deprecated support for Node `^4.0.0`

0.18.0
-----

### Features
* Replaces `webpack-dev-server` with `Express` and webpack middleware
* Replaces `redux-router` with `redux-simple-router`
* Use `postcss-loader` for autoprefixing rather than autoprefixer-loader
* Configuration will now warn you of missing dependencies for vendor bundle
* Upgrade `react-router` from `1.0.0-rc1` -> `^1.0.0`
* Upgrade `css-loader` from `0.21.0` -> `0.23.0`
* Upgrade `eslint-config-airbnb` from `0.1.0` to `^1.0.0`
* Upgrade `karma-spec-reporter` from `0.0.21` to `0.0.22`
* Upgrade `extract-text-webpack-plugin` from `^0.8.0` to `^0.9.0`

### Improvements
* Compiled `index.html` is now minified
* Content hashes are now injected directly into the filename rather than appended as query strings
* Better reporting of webpack build status
* Use object-style configuration for `sass-loader` rather than inline query string
* Rename `test:lint` task to `lint:tests`
* Various documentation improvements

### Fixes
* Content hash is now longer duplicated in CSS bundle
* Karma plugins are autoloaded now, rather than explicitly defined
* Removes extraneous wrapping div in `Root` container
* Fixes awkwardly named arguments to `createReducer` utility
* Add missing alias to `~/src/store`

0.17.0
------

### Features
* Karma coverage now generates proper coverage reports
* Added chai-as-promised
* Added `npm run lint` script to lint all `~/src` code
* Added `npm run test:lint` script to lint all `*.spec.js` files in `~/tests`
* Updated `npm run deploy` to explicitly run linter on source code
* Added `dotenv` (thanks [dougvk](https://github.com/dougvk))

### Improvements
* Renamed application entry point from `index.js` -> `app.js` (clarifies intent and helps with coverage reports)
* Refactored sample counter constants and actions to their appropriate locations (thanks [kyleect](https://github.com/kyleect))
* Devtools in `npm run dev:nw` now take up the full window (thanks [jhgg](https://github.com/jhgg))
* Webpack no longer runs an eslint pre-loader (cleans up console messages while developing)
* Moved tests into their own directory (alleviates lint/organization issues)
* Renamed `stores` to `store` to be more intuitive
* Webpack-dev-server now uses a configurable host (thanks [waynelkh](https://github.com/waynelkh))
* Sass-loader is now configured independently of its loader definition
* Upgraded `redux-devtools` from `^2.0.0` -> `^3.0.0`
* Upgraded `react-transform-catch-errors` from `^0.1.0` -> `^1.0.0`

### Fixes
* Fix .editorconfig missing a setting that caused it to not be picked up in all IDE's
* Cleans up miscellaneous lint errors.


0.16.0
------

### Features
* Adds redux-router (thanks to [dougvk](https://github.com/dougvk))
* Adds redux-thunk middleware
* Adds loaders for font files (thanks to [nodkz](https://github.com/nodkz))
* Adds url loader
* Upgrades React dependencies to stable `^0.14.0`
* Upgrades react-redux to `^4.0.0`

### Improvements
* Cleans up unused configuration settings
* configureStore no longer relies on a global variable to determine whether or not to enable devtool middleware
* Removes unused invariant and ImmutableJS vendor dependencies
* Removes unused webpack-clean plugin
* Tweaks .js loader configuration to make it easier to add json-loader
* Updates counter example to demonstrate `mapDispatchToProps`
* Force `components` directory inclusion
* Documentation improvements

0.15.2
------

### Fixes
* Remove unused/broken "minify" property provided to HtmlWebpackPlugin configuration.

0.15.1
------

### Fixes
* Dev server now loads the correct Webpack configuration with HMR enabled.
* Redbox-React error catcher is now loaded correctly in development.

0.15.0
------

### Fixes
* HMR is now longer enabled for simple compilations. You can now compile development builds that won't constantly ping a non-existent dev server.
* react-transform-hmr now only runs when HMR is enabled.

### Improvements
* Unit tests now only run in watch mode when explicitly requested. This makes it much more convenient to run tests on any environment without having to struggle with the `singleRun` flag in Karma.
* There is now only a single webpack configuration (rather than one for the client and one for the server). As a result, configuration has once again been split into a base configuration which is then extended based on the current `NODE_ENV`.

### Deprecations
* Removed Koa server (sad days).

0.14.0
------

#### Features
* Replaces `react-transform-webpack-hmr` with its replacement `react-transform-hmr`. Thanks to [daviferreira](https://github.com/daviferreira).
* Replaces `delicate-error-reporter` with `redbox-react`. Thanks to [bulby97](https://github.com/bulby97).
* Created a `no-server` branch [here](https://github.com/davezuko/react-redux-starter-kit/tree/no-server) to make it easier for users who don't care about Koa.

#### Improvements
* Renames `client` directory to `src` to be more intuitive.
* `inline-source-map` has been replaced by `source-map` as the default webpack devTool to reduce build sizes.
* Refactors configuration file to focus on commonly-configured options rather than mixing them with internal configuration.
* Swaps `dev` and `dev:debug` so debug tools are now enabled by default and can be disabled instead with `dev:no-debug`.
* Repositions Redux devtools so they no longer block errors displayed by `redbox-react`.
* Adds explicit directory references to some `import` statements to clarify which are from from `npm` and which are local.

#### Fixes
* Fixes naming in `HomeView` where `mapStateToProps` was incorrectly written as `mapDispatchToProps`.

#### Deprecations
* Removes local test utilities (in `~/src/utils/test`).

0.13.0
------

#### Features
* Adds `react-transform-catch-errors` along with `delicate-error-reporter`. Thanks [bulby97](https://github.com/bulby97) for this!

#### Fixes
* ExtractTextPlugin is once again production only. This fixes an issue where styles wouldn't be hot reloaded with Webpack.

0.12.0
------

#### Features
* Upgrades react-router to `^3.0.0`. This is the only reason for the minor-level version  bump.
* Webpack now uses OccurrenceOrderPlugin to produce consistent bundle hashes.

#### Fixes
* Adds `history` to vendor dependencies to fix HMR caused by upgrade to react-router `1.0.0-rc`

#### Improvements
* Server no longer modifies initial counter state by default.
* Adds invariant error in route rendering method to enforce router state definition through props.

0.11.0
------

#### Features
* Upgrades all React dependencies to `0.14.0-rc1`
* Upgrades react-router to `1.0.0-rc`
  * Updates client and server rendering accordingly
* Adds Sinon-Chai for improved assertions and function spies
* Adds option to disable eslint when in development

#### Improvements
* Improved example unit tests using react-addons-test-utils and Sinon Chai

0.10.0
------

#### Features
* Initial state can now be injected from the server (still WIP).
* Adds react-addons-test-utils as a devDependency.

#### Improvements
* Eslint no longer prevents webpack from bundling in development mode if an error is emitted.
  * See: https://github.com/MoOx/eslint-loader/issues/23
* Updates all `.jsx` files to `.js`. (https://github.com/davezuko/react-redux-starter-kit/issues/37)
* Updates all React component file names to be ProperCased.

0.9.0
-----

#### Features
* Koa server now uses gzip middleware.

#### Improvements
* Switches out react-hot-loader in favor of [react-transform-webpack-hmr](https://github.com/gaearon/react-transform-webpack-hmr).
* Eslint configuration now uses Airbnb's configuration (slightly softened).
* Migrates all actual development dependencies to devDependencies in `package.json`.
* Example store and view are now more intuitive (simple counter display).
* CSS-loader dependency upgraded from `0.16.0` to `0.17.0`.

#### Deprecations
* Removes unnecessary object-assign dependency.

0.8.0
-----

#### Improvements
* All build-, server-, and client-related code is now ES6.
* Significantly refactors how client and server webpack configs are built.
* `reducers/index.js` now exports combined root reducer.
* Client application code now lives in `~/client` instead of `~/src` in order to conform to Redux standards.

#### Fixes
* Redux store now explicitly handles HMR.

#### Changes
* Webpack compiler configurations are no longer merged on top of a base default configuration. This can become unwieldy and even though explicitly writing each configuration file out is more verbose, it ends up being more maintainable.

#### Deprecations
* Quiet mode has been removed (`npm run dev:quiet`).

0.7.0
-----
#### New Features
* Support for redux-devtools in separate window with `dev:debugnw`
  - Thanks to [mlusetti](https://github.com/mlusetti)

#### Improvements
* Upgrades react to `0.14.0-beta3`
* Upgrades react to `0.14.0-beta3`
* Upgrades redux to `^2.0.0`
* Upgrades redux-devtools to `^2.0.0`
* Upgrades react-redux to `^2.0.0`

#### Fixes
* Configuration file name trimming on Windows machines
  - Thanks to [nuragic](https://github.com/nuragic)

0.6.0
-----

#### Fixes
* Fixes potential spacing issues when Webpack tries to load a config file.
  - Thanks to [nuragic](https://github.com/nuragic) for his [PR](https://github.com/davezuko/react-redux-starter-kit/pull/32)

#### Improvements
* Upgrades koa to `1.0.0`
* Upgrades react-redux to `1.0.0`
* Upgrades object-assign to `0.4.0`

0.5.0
-----

#### Improvements
* Restructures src directory so filenames are more identifiable.

#### Breaking Changes
* Removes action-creators alias as it's unlikely to be used.

0.4.0
-----

#### Improvements
* Cleans up/removes example code per https://github.com/davezuko/react-redux-starter-kit/issues/20

0.3.1
-----

#### Fixes
* https://github.com/davezuko/react-redux-starter-kit/issues/19
  - Invalid initialStates from server-side router will now yield to the next middleware.

0.3.0
-----

#### Improvements
* Bumps Redux version to first major release.
* Bumps Redux-devtools version to first major release.

#### Fixes
* Fixes broken hot-reload in `:debug` mode.
  - Temporarily fixed by moving `redux-devtools` into the vendor bundle.

0.2.0
-----

#### Improvements
* Weakens various eslint rules that were too opinionated.
  - notable: `one-var` and `key-spacing`.

Thanks to [StevenLangbroek](https://github.com/StevenLangbroek) for the following:
* Adds alias `utils` to reference `~/src/utils`
* Adds `createConstants` utility.
* Adds `createReducer` utility.
* Refactors `todos` reducer to use a function map rather than switch statements.

#### Fixes
* Nested routes are now loaded correctly in react-router when using BrowserHistory.
* Bundle compilation now fails if an eslint error is encountered when running a production build.
  - Thanks [clearjs](https://github.com/clearjs)
* Upgrades all outdated dependencies.
  - Karma, eslint, babel, sass-loader, and a handful more.


================================================
FILE: CONTRIBUTING.md
================================================
# Contributing Guidelines

Some basic conventions for contributing to this project.

### General

Please make sure that there aren't existing pull requests attempting to address the issue mentioned. Likewise, please check for issues related to update, as someone else may be working on the issue in a branch or fork.

* Non-trivial changes should be discussed in an issue first
* Develop in a topic branch, not master
* Squash your commits

### Linting

Please check your code using `npm run lint` before submitting your pull requests, as the CI build will fail if `eslint` fails.

### Commit Message Format

Each commit message should include a **type**, a **scope** and a **subject**:

```
 <type>(<scope>): <subject>
```

Lines should not exceed 100 characters. This allows the message to be easier to read on github as well as in various git tools and produces a nice, neat commit log ie:

```
 #271 feat(standard): add style config and refactor to match
 #270 fix(config): only override publicPath when served by webpack 
 #269 feat(eslint-config-defaults): replace eslint-config-airbnb 
 #268 feat(config): allow user to configure webpack stats output 
``` 

#### Type

Must be one of the following:

* **feat**: A new feature
* **fix**: A bug fix
* **docs**: Documentation only changes
* **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing
  semi-colons, etc)
* **refactor**: A code change that neither fixes a bug or adds a feature
* **test**: Adding missing tests
* **chore**: Changes to the build process or auxiliary tools and libraries such as documentation
  generation

#### Scope

The scope could be anything specifying place of the commit change. For example `webpack`,
`babel`, `redux` etc...

#### Subject

The subject contains succinct description of the change:

* use the imperative, present tense: "change" not "changed" nor "changes"
* don't capitalize first letter
* no dot (.) at the end


================================================
FILE: LICENSE
================================================
The MIT License (MIT)

Copyright (c) 2015 David Zukowski

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
# Deprecation Warning

This project was started at the advent of the Redux ecosystem, and was intended to help users get up and running quickly. Since then, tooling and best practices have evolved tremendously. In order to get the most modern experience possible, I recommend checking out something like [create-react-app](https://github.com/facebookincubator/create-react-app) which is supported by many core React and Redux developers.

You are welcome to use this project if it is a better fit for your needs, but if you are brand new to the ecosystem I highly recommend checking out something that has received more recent updates.

Thank you to everyone who made this project possible over the past year(s).

# React Redux Starter Kit

[![Build Status](https://travis-ci.org/davezuko/react-redux-starter-kit.svg?branch=master)](https://travis-ci.org/davezuko/react-redux-starter-kit?branch=master)
[![dependencies](https://david-dm.org/davezuko/react-redux-starter-kit.svg)](https://david-dm.org/davezuko/react-redux-starter-kit)
[![devDependency Status](https://david-dm.org/davezuko/react-redux-starter-kit/dev-status.svg)](https://david-dm.org/davezuko/react-redux-starter-kit#info=devDependencies)
[![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg)](http://standardjs.com/)

This starter kit is designed to get you up and running with a bunch of awesome front-end technologies.

The primary goal of this project is to provide a stable foundation upon which to build modern web appliications. Its purpose is not to dictate your project structure or to demonstrate a complete real-world application, but to provide a set of tools intended to make front-end development robust, easy, and, most importantly, fun. Check out the full feature list below!

Finally, This project wouldn't be possible without the help of our many contributors. What you see today is the product of hundreds changes made to keep up with an ever-evolving ecosystem. [Thank you](#thank-you) for all of your help.

## Table of Contents
1. [Requirements](#requirements)
1. [Installation](#getting-started)
1. [Running the Project](#running-the-project)
1. [Project Structure](#project-structure)
1. [Live Development](#local-development)
    * [Hot Reloading](#hot-reloading)
    * [Redux DevTools](#redux-devtools)
1. [Routing](#routing)
1. [Testing](#testing)
    * [dirty-chai](#dirty-chai)
1. [Building for Production](#building-for-production)
1. [Deployment](#deployment)
1. [Thank You](#thank-you)

## Requirements
* node `^5.0.0`
* yarn `^0.23.0` or npm `^3.0.0`

## Installation

After confirming that your environment meets the above [requirements](#requirements), you can create a new project based on `react-redux-starter-kit` by doing the following:

```bash
$ git clone https://github.com/davezuko/react-redux-starter-kit.git <my-project-name>
$ cd <my-project-name>
```

When that's done, install the project dependencies. It is recommended that you use [Yarn](https://yarnpkg.com/) for deterministic dependency management, but `npm install` will suffice.

```bash
$ yarn  # Install project dependencies (or `npm install`)
```

## Running the Project

After completing the [installation](#installation) step, you're ready to start the project!

```bash
$ yarn start  # Start the development server (or `npm start`)
```

While developing, you will probably rely mostly on `yarn start`; however, there are additional scripts at your disposal:

|`yarn <script>`    |Description|
|-------------------|-----------|
|`start`            |Serves your app at `localhost:3000`|
|`build`            |Builds the application to ./dist|
|`test`             |Runs unit tests with Karma. See [testing](#testing)|
|`test:watch`       |Runs `test` in watch mode to re-run tests when changed|
|`lint`             |[Lints](http://stackoverflow.com/questions/8503559/what-is-linting) the project for potential errors|
|`lint:fix`         |Lints the project and [fixes all correctable errors](http://eslint.org/docs/user-guide/command-line-interface.html#fix)|

## Project Structure

The project structure presented in this boilerplate is **fractal**, where functionality is grouped primarily by feature rather than file type. This structure is only meant to serve as a guide, it is by no means prescriptive. That said, it aims to represent generally accepted guidelines and patterns for building scalable applications. If you wish to read more about this pattern, please check out this [awesome writeup](https://github.com/davezuko/react-redux-starter-kit/wiki/Fractal-Project-Structure) by [Justin Greenberg](https://github.com/justingreenberg).

```
.
├── build                    # All build-related code
├── public                   # Static public assets (not imported anywhere in source code)
├── server                   # Express application that provides webpack middleware
│   └── main.js              # Server application entry point
├── src                      # Application source code
│   ├── index.html           # Main HTML page container for app
│   ├── main.js              # Application bootstrap and rendering
│   ├── normalize.js         # Browser normalization and polyfills
│   ├── components           # Global Reusable Components
│   ├── containers           # Global Reusable Container Components
│   ├── layouts              # Components that dictate major page structure
│   │   └── PageLayout       # Global application layout in which to render routes
│   ├── routes               # Main route definitions and async split points
│   │   ├── index.js         # Bootstrap main application routes with store
│   │   ├── Home             # Fractal route
│   │   │   ├── index.js     # Route definitions and async split points
│   │   │   ├── assets       # Assets required to render components
│   │   │   ├── components   # Presentational React Components
│   │   │   └── routes **    # Fractal sub-routes (** optional)
│   │   └── Counter          # Fractal route
│   │       ├── index.js     # Counter route definition
│   │       ├── container    # Connect components to actions and store
│   │       ├── modules      # Collections of reducers/constants/actions
│   │       └── routes **    # Fractal sub-routes (** optional)
│   ├── store                # Redux-specific pieces
│   │   ├── createStore.js   # Create and instrument redux store
│   │   └── reducers.js      # Reducer registry and injection
│   └── styles               # Application-wide styles (generally settings)
└── tests                    # Unit tests
```

## Live Development

### Hot Reloading

Hot reloading is enabled by default when the application is running in development mode (`yarn start`). This feature is implemented with webpack's [Hot Module Replacement](https://webpack.github.io/docs/hot-module-replacement.html) capabilities, where code updates can be injected to the application while it's running, no full reload required. Here's how it works:

* For **JavaScript** modules, a code change will trigger the application to re-render from the top of the tree. **Global state is preserved (i.e. redux), but any local component state is reset**. This differs from React Hot Loader, but we've found that performing a full re-render helps avoid subtle bugs caused by RHL patching.

* For **Sass**, any change will update the styles in realtime, no additional configuration or reload needed.

### Redux DevTools

**We recommend using the [Redux DevTools Chrome Extension](https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd).**
Using the chrome extension allows your monitors to run on a separate thread and affords better performance and functionality. It comes with several of the most popular monitors, is easy to configure, filters actions, and doesn't require installing any packages in your project.

However, it's easy to bundle these developer tools locally should you choose to do so. First, grab the packages from npm:

```bash
yarn add --dev redux-devtools redux-devtools-log-monitor redux-devtools-dock-monitor
```

Then follow the [manual integration walkthrough](https://github.com/gaearon/redux-devtools/blob/master/docs/Walkthrough.md).

## Routing
We use `react-router` [route definitions](https://github.com/ReactTraining/react-router/blob/v3/docs/API.md#plainroute) (`<route>/index.js`) to define units of logic within our application. See the [project structure](#project-structure) section for more information.

## Testing
To add a unit test, create a `.spec.js` file anywhere inside of `./tests`. Karma and webpack will automatically find these files, and Mocha and Chai will be available within your test without the need to import them. Here are a few important plugins and packages available to you during testing:

### dirty-chai

Some of the assertions available from [chai](chaijs.com) use [magical getters](http://chaijs.com/api/bdd/#method_true). These are problematic for a few reasons:

1) If you mistype a property name (e.g. `expect(false).to.be.tru`) then the expression evaluates to undefined, the magical getter on the `true` is never run, and so your test silently passes.
2) By default, linters don't understand them and therefore mark them as unused expressions, which can be annoying.

[Dirty Chai](https://github.com/prodatakey/dirty-chai) fixes this by converting these getters into callable functions. This way, if mistype an assertion, our attempt to invoke it will throw due to the property being undefined.

```js
// This silently passes because the getter on `true` is never invoked!
it('should be true', () => {
  expect(false).to.be.tru // evalutes to undefined :(
})

// Much better! Our assertion is invalid, so it throws rather than implicitly passing.
it('should be true', () => {
  expect(false).to.be.tru() // `tru` is not defined!
})
```

## Building for Production

## Deployment

Out of the box, this starter kit is deployable by serving the `./dist` folder generated by `yarn build`. This project does not concern itself with the details of server-side rendering or API structure, since that demands a more opinionated structure that makes it difficult to extend the starter kit. The simplest deployment strategy is a [static deployment](#static-deployments).

### Static Deployments

Serve the application with a web server such as nginx by pointing it at your `./dist` folder. Make sure to direct incoming route requests to the root `./dist/index.html` file so that the client application will be loaded; react-router will take care of the rest. If you are unsure of how to do this, you might find [this documentation](https://github.com/reactjs/react-router/blob/master/docs/guides/Histories.md#configuring-your-server) helpful. The Express server that comes with the starter kit is able to be extended to serve as an API and more, but is not required for a static deployment.

## Thank You

This project wouldn't be possible without help from the community, so I'd like to highlight some of its biggest contributors. Thank you all for your hard work, you've made my life a lot easier and taught me a lot in the process.

* [Justin Greenberg](https://github.com/justingreenberg) - For all of your PR's, getting us to Babel 6, and constant work improving our patterns.
* [Roman Pearah](https://github.com/neverfox) - For your bug reports, help in triaging issues, and PR contributions.
* [Spencer Dixon](https://github.com/SpencerCDixon) - For your creation of [redux-cli](https://github.com/SpencerCDixon/redux-cli).
* [Jonas Matser](https://github.com/mtsr) - For your help in triaging issues and unending support in our Gitter channel.

And to everyone else who has contributed, even if you are not listed here your work is appreciated.


================================================
FILE: build/karma.config.js
================================================
const argv = require('yargs').argv
const webpackConfig = require('./webpack.config')

const TEST_BUNDLER = './tests/test-bundler.js'

const karmaConfig = {
  basePath: '../',
  browsers: ['PhantomJS'],
  singleRun: !argv.watch,
  coverageReporter: {
    reporters: [
      { type: 'text-summary' },
    ],
  },
  files: [{
    pattern  : TEST_BUNDLER,
    watched  : false,
    served   : true,
    included : true
  }],
  frameworks: ['mocha'],
  reporters: ['mocha'],
  preprocessors: {
    [TEST_BUNDLER]: ['webpack'],
  },
  logLevel: 'WARN',
  browserConsoleLogOptions: {
    terminal: true,
    format: '%b %T: %m',
    level: '',
  },
  webpack: {
    entry: TEST_BUNDLER,
    devtool: 'cheap-module-source-map',
    module: webpackConfig.module,
    plugins: webpackConfig.plugins,
    resolve: webpackConfig.resolve,
    externals: {
      'react/addons': 'react',
      'react/lib/ExecutionEnvironment': 'react',
      'react/lib/ReactContext': 'react',
    },
  },
  webpackMiddleware: {
    stats: 'errors-only',
    noInfo: true,
  },
}

module.exports = (cfg) => cfg.set(karmaConfig)


================================================
FILE: build/lib/logger.js
================================================
const chalk = require('chalk')
const figures = require('figures')

// Need to support Node versions that don't support spreading function arguments
const spread = (fn) => function () {
  return fn([].slice.call(arguments))
}

exports.log = console.log.bind(console)

exports.error = spread((messages) => {
  console.error(chalk.red.apply(chalk, [figures.cross].concat(messages)))
})

exports.info = spread((messages) => {
  console.info(chalk.cyan.apply(chalk, [figures.info].concat(messages)))
})

exports.success = spread((messages) => {
  console.log(chalk.green.apply(chalk, [figures.tick].concat(messages)))
})

exports.warn = spread((messages) => {
  console.warn(chalk.yellow.apply(chalk, [figures.warning].concat(messages)))
})


================================================
FILE: build/scripts/compile.js
================================================
const fs = require('fs-extra')
const path = require('path')
const chalk = require('chalk')
const webpack = require('webpack')
const logger = require('../lib/logger')
const webpackConfig = require('../webpack.config')
const project = require('../../project.config')

const runWebpackCompiler = (webpackConfig) =>
  new Promise((resolve, reject) => {
    webpack(webpackConfig).run((err, stats) => {
      if (err) {
        logger.error('Webpack compiler encountered a fatal error.', err)
        return reject(err)
      }

      const jsonStats = stats.toJson()
      if (jsonStats.errors.length > 0) {
        logger.error('Webpack compiler encountered errors.')
        logger.log(jsonStats.errors.join('\n'))
        return reject(new Error('Webpack compiler encountered errors'))
      } else if (jsonStats.warnings.length > 0) {
        logger.warn('Webpack compiler encountered warnings.')
        logger.log(jsonStats.warnings.join('\n'))
      }
      resolve(stats)
    })
  })

const compile = () => Promise.resolve()
  .then(() => logger.info('Starting compiler...'))
  .then(() => logger.info('Target application environment: ' + chalk.bold(project.env)))
  .then(() => runWebpackCompiler(webpackConfig))
  .then((stats) => {
    logger.info(`Copying static assets from ./public to ./${project.outDir}.`)
    fs.copySync(
      path.resolve(project.basePath, 'public'),
      path.resolve(project.basePath, project.outDir)
    )
    return stats
  })
  .then((stats) => {
    if (project.verbose) {
      logger.log(stats.toString({
        colors: true,
        chunks: false,
      }))
    }
    logger.success(`Compiler finished successfully! See ./${project.outDir}.`)
  })
  .catch((err) => logger.error('Compiler encountered errors.', err))

compile()


================================================
FILE: build/scripts/start.js
================================================
const logger = require('../lib/logger')

logger.info('Starting server...')
require('../../server/main').listen(3000, () => {
  logger.success('Server is running at http://localhost:3000')
})


================================================
FILE: build/webpack.config.js
================================================
const path = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const project = require('../project.config')

const inProject = path.resolve.bind(path, project.basePath)
const inProjectSrc = (file) => inProject(project.srcDir, file)

const __DEV__ = project.env === 'development'
const __TEST__ = project.env === 'test'
const __PROD__ = project.env === 'production'

const config = {
  entry: {
    normalize: [
      inProjectSrc('normalize'),
    ],
    main: [
      inProjectSrc(project.main),
    ],
  },
  devtool: project.sourcemaps ? 'source-map' : false,
  output: {
    path: inProject(project.outDir),
    filename: __DEV__ ? '[name].js' : '[name].[chunkhash].js',
    publicPath: project.publicPath,
  },
  resolve: {
    modules: [
      inProject(project.srcDir),
      'node_modules',
    ],
    extensions: ['*', '.js', '.jsx', '.json'],
  },
  externals: project.externals,
  module: {
    rules: [],
  },
  plugins: [
    new webpack.DefinePlugin(Object.assign({
      'process.env': { NODE_ENV: JSON.stringify(project.env) },
      __DEV__,
      __TEST__,
      __PROD__,
    }, project.globals))
  ],
}

// JavaScript
// ------------------------------------
config.module.rules.push({
  test: /\.(js|jsx)$/,
  exclude: /node_modules/,
  use: [{
    loader: 'babel-loader',
    query: {
      cacheDirectory: true,
      plugins: [
        'babel-plugin-transform-class-properties',
        'babel-plugin-syntax-dynamic-import',
        [
          'babel-plugin-transform-runtime',
          {
            helpers: true,
            polyfill: false, // we polyfill needed features in src/normalize.js
            regenerator: true,
          },
        ],
        [
          'babel-plugin-transform-object-rest-spread',
          {
            useBuiltIns: true // we polyfill Object.assign in src/normalize.js
          },
        ],
      ],
      presets: [
        'babel-preset-react',
        ['babel-preset-env', {
          modules: false,
          targets: {
            ie9: true,
          },
          uglify: true,
        }],
      ]
    },
  }],
})

// Styles
// ------------------------------------
const extractStyles = new ExtractTextPlugin({
  filename: 'styles/[name].[contenthash].css',
  allChunks: true,
  disable: __DEV__,
})

config.module.rules.push({
  test: /\.(sass|scss)$/,
  loader: extractStyles.extract({
    fallback: 'style-loader',
    use: [
      {
        loader: 'css-loader',
        options: {
          sourceMap: project.sourcemaps,
          minimize: {
            autoprefixer: {
              add: true,
              remove: true,
              browsers: ['last 2 versions'],
            },
            discardComments: {
              removeAll : true,
            },
            discardUnused: false,
            mergeIdents: false,
            reduceIdents: false,
            safe: true,
            sourcemap: project.sourcemaps,
          },
        },
      },
      {
        loader: 'sass-loader',
        options: {
          sourceMap: project.sourcemaps,
          includePaths: [
            inProjectSrc('styles'),
          ],
        },
      }
    ],
  })
})
config.plugins.push(extractStyles)

// Images
// ------------------------------------
config.module.rules.push({
  test    : /\.(png|jpg|gif)$/,
  loader  : 'url-loader',
  options : {
    limit : 8192,
  },
})

// Fonts
// ------------------------------------
;[
  ['woff', 'application/font-woff'],
  ['woff2', 'application/font-woff2'],
  ['otf', 'font/opentype'],
  ['ttf', 'application/octet-stream'],
  ['eot', 'application/vnd.ms-fontobject'],
  ['svg', 'image/svg+xml'],
].forEach((font) => {
  const extension = font[0]
  const mimetype = font[1]

  config.module.rules.push({
    test    : new RegExp(`\\.${extension}$`),
    loader  : 'url-loader',
    options : {
      name  : 'fonts/[name].[ext]',
      limit : 10000,
      mimetype,
    },
  })
})

// HTML Template
// ------------------------------------
config.plugins.push(new HtmlWebpackPlugin({
  template: inProjectSrc('index.html'),
  inject: true,
  minify: {
    collapseWhitespace: true,
  },
}))

// Development Tools
// ------------------------------------
if (__DEV__) {
  config.entry.main.push(
    `webpack-hot-middleware/client.js?path=${config.output.publicPath}__webpack_hmr`
  )
  config.plugins.push(
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NamedModulesPlugin()
  )
}

// Bundle Splitting
// ------------------------------------
if (!__TEST__) {
  const bundles = ['normalize', 'manifest']

  if (project.vendors && project.vendors.length) {
    bundles.unshift('vendor')
    config.entry.vendor = project.vendors
  }
  config.plugins.push(new webpack.optimize.CommonsChunkPlugin({ names: bundles }))
}

// Production Optimizations
// ------------------------------------
if (__PROD__) {
  config.plugins.push(
    new webpack.LoaderOptionsPlugin({
      minimize: true,
      debug: false,
    }),
    new webpack.optimize.UglifyJsPlugin({
      sourceMap: !!config.devtool,
      comments: false,
      compress: {
        warnings: false,
        screw_ie8: true,
        conditionals: true,
        unused: true,
        comparisons: true,
        sequences: true,
        dead_code: true,
        evaluate: true,
        if_return: true,
        join_vars: true,
      },
    })
  )
}

module.exports = config


================================================
FILE: package.json
================================================
{
  "name": "react-redux-starter-kit",
  "version": "3.0.1",
  "description": "Get started with React, Redux, and React-Router!",
  "main": "index.js",
  "scripts": {
    "clean": "rimraf dist",
    "compile": "node build/scripts/compile",
    "build": "npm run clean && cross-env NODE_ENV=production npm run compile",
    "start": "cross-env NODE_ENV=development node build/scripts/start",
    "test": "cross-env NODE_ENV=test karma start build/karma.config",
    "test:watch": "npm test -- --watch",
    "lint": "eslint .",
    "lint:fix": "npm run lint -- --fix"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/davezuko/react-redux-starter-kit.git"
  },
  "author": "David Zukowski <david@zuko.me> (http://zuko.me)",
  "license": "MIT",
  "dependencies": {
    "bootstrap": "^4.0.0-alpha",
    "compression": "^1.6.2",
    "express": "^4.14.0",
    "object-assign": "^4.1.1",
    "promise": "^7.1.1",
    "prop-types": "^15.5.10",
    "react": "^15.5.4",
    "react-dom": "^15.5.4",
    "react-redux": "^5.0.4",
    "react-router": "^3.0.0",
    "redbox-react": "^1.3.6",
    "redux": "^3.6.0",
    "redux-thunk": "^2.2.0",
    "whatwg-fetch": "^2.0.3"
  },
  "devDependencies": {
    "babel-core": "^6.24.1",
    "babel-eslint": "^7.2.3",
    "babel-loader": "^7.0.0",
    "babel-plugin-syntax-dynamic-import": "^6.18.0",
    "babel-plugin-transform-class-properties": "^6.24.1",
    "babel-plugin-transform-object-rest-spread": "^6.23.0",
    "babel-plugin-transform-runtime": "^6.15.0",
    "babel-preset-env": "^1.4.0",
    "babel-preset-react": "^6.24.1",
    "babel-runtime": "^6.20.0",
    "chai": "^3.5.0",
    "chai-as-promised": "^6.0.0",
    "chai-enzyme": "^0.6.1",
    "chalk": "^1.1.3",
    "codecov": "^2.2.0",
    "connect-history-api-fallback": "^1.3.0",
    "cross-env": "^5.0.0",
    "css-loader": "^0.28.1",
    "dirty-chai": "^1.2.2",
    "enzyme": "^2.8.2",
    "eslint": "^3.19.0",
    "eslint-config-standard": "^10.2.1",
    "eslint-config-standard-react": "^5.0.0",
    "eslint-plugin-babel": "^4.1.1",
    "eslint-plugin-import": "^2.2.0",
    "eslint-plugin-node": "^4.2.2",
    "eslint-plugin-promise": "^3.5.0",
    "eslint-plugin-react": "^7.0.1",
    "eslint-plugin-standard": "^3.0.1",
    "extract-text-webpack-plugin": "^2.1.0",
    "figures": "^2.0.0",
    "file-loader": "^0.11.1",
    "fs-extra": "^3.0.1",
    "html-webpack-plugin": "^2.24.1",
    "karma": "^1.7.0",
    "karma-coverage": "^1.1.1",
    "karma-mocha": "^1.3.0",
    "karma-mocha-reporter": "^2.2.1",
    "karma-phantomjs-launcher": "^1.0.4",
    "karma-webpack-with-fast-source-maps": "^1.10.0",
    "mocha": "^3.2.0",
    "node-sass": "^4.5.3",
    "phantomjs-prebuilt": "^2.1.14",
    "react-addons-test-utils": "^15.5.1",
    "react-test-renderer": "^15.5.4",
    "rimraf": "^2.6.1",
    "sass-loader": "^6.0.5",
    "sinon": "^2.2.0",
    "sinon-chai": "^2.10.0",
    "style-loader": "^0.17.0",
    "url-loader": "^0.5.8",
    "webpack": "^2.5.1",
    "webpack-dev-middleware": "^1.8.4",
    "webpack-hot-middleware": "^2.13.2",
    "yargs": "^8.0.1"
  }
}


================================================
FILE: project.config.js
================================================
const NODE_ENV = process.env.NODE_ENV || 'development'

module.exports = {
  /** The environment to use when building the project */
  env: NODE_ENV,
  /** The full path to the project's root directory */
  basePath: __dirname,
  /** The name of the directory containing the application source code */
  srcDir: 'src',
  /** The file name of the application's entry point */
  main: 'main',
  /** The name of the directory in which to emit compiled assets */
  outDir: 'dist',
  /** The base path for all projects assets (relative to the website root) */
  publicPath: '/',
  /** Whether to generate sourcemaps */
  sourcemaps: true,
  /** A hash map of keys that the compiler should treat as external to the project */
  externals: {},
  /** A hash map of variables and their values to expose globally */
  globals: {},
  /** Whether to enable verbose logging */
  verbose: false,
  /** The list of modules to bundle separately from the core application code */
  vendors: [
    'react',
    'react-dom',
    'redux',
    'react-redux',
    'redux-thunk',
    'react-router',
  ],
}


================================================
FILE: public/humans.txt
================================================
# Check it out: http://humanstxt.org/

# TEAM

    <name> -- <role> -- <twitter>

# THANKS

    <name>


================================================
FILE: public/robots.txt
================================================
User-agent: *
Disallow:


================================================
FILE: server/main.js
================================================
const express = require('express')
const path = require('path')
const webpack = require('webpack')
const logger = require('../build/lib/logger')
const webpackConfig = require('../build/webpack.config')
const project = require('../project.config')
const compress = require('compression')

const app = express()
app.use(compress())

// ------------------------------------
// Apply Webpack HMR Middleware
// ------------------------------------
if (project.env === 'development') {
  const compiler = webpack(webpackConfig)

  logger.info('Enabling webpack development and HMR middleware')
  app.use(require('webpack-dev-middleware')(compiler, {
    publicPath  : webpackConfig.output.publicPath,
    contentBase : path.resolve(project.basePath, project.srcDir),
    hot         : true,
    quiet       : false,
    noInfo      : false,
    lazy        : false,
    stats       : 'normal',
  }))
  app.use(require('webpack-hot-middleware')(compiler, {
    path: '/__webpack_hmr'
  }))

  // Serve static assets from ~/public since Webpack is unaware of
  // these files. This middleware doesn't need to be enabled outside
  // of development since this directory will be copied into ~/dist
  // when the application is compiled.
  app.use(express.static(path.resolve(project.basePath, 'public')))

  // This rewrites all routes requests to the root /index.html file
  // (ignoring file requests). If you want to implement universal
  // rendering, you'll want to remove this middleware.
  app.use('*', function (req, res, next) {
    const filename = path.join(compiler.outputPath, 'index.html')
    compiler.outputFileSystem.readFile(filename, (err, result) => {
      if (err) {
        return next(err)
      }
      res.set('content-type', 'text/html')
      res.send(result)
      res.end()
    })
  })
} else {
  logger.warn(
    'Server is being run outside of live development mode, meaning it will ' +
    'only serve the compiled application bundle in ~/dist. Generally you ' +
    'do not need an application server for this and can instead use a web ' +
    'server such as nginx to serve your static files. See the "deployment" ' +
    'section in the README for more information on deployment strategies.'
  )

  // Serving ~/dist by default. Ideally these files should be served by
  // the web server and not the app server, but this helps to demo the
  // server in production.
  app.use(express.static(path.resolve(project.basePath, project.outDir)))
}

module.exports = app


================================================
FILE: src/components/App.js
================================================
import React from 'react'
import { browserHistory, Router } from 'react-router'
import { Provider } from 'react-redux'
import PropTypes from 'prop-types'

class App extends React.Component {
  static propTypes = {
    store: PropTypes.object.isRequired,
    routes: PropTypes.object.isRequired,
  }

  shouldComponentUpdate () {
    return false
  }

  render () {
    return (
      <Provider store={this.props.store}>
        <div style={{ height: '100%' }}>
          <Router history={browserHistory} children={this.props.routes} />
        </div>
      </Provider>
    )
  }
}

export default App


================================================
FILE: src/index.html
================================================
<!doctype html>
<html lang="en">
<head>
  <title>React Redux Starter Kit</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
  <div id="root" style="height: 100%"></div>
</body>
</html>


================================================
FILE: src/layouts/PageLayout/PageLayout.js
================================================
import React from 'react'
import { IndexLink, Link } from 'react-router'
import PropTypes from 'prop-types'
import './PageLayout.scss'

export const PageLayout = ({ children }) => (
  <div className='container text-center'>
    <h1>React Redux Starter Kit</h1>
    <IndexLink to='/' activeClassName='page-layout__nav-item--active'>Home</IndexLink>
    {' · '}
    <Link to='/counter' activeClassName='page-layout__nav-item--active'>Counter</Link>
    <div className='page-layout__viewport'>
      {children}
    </div>
  </div>
)
PageLayout.propTypes = {
  children: PropTypes.node,
}

export default PageLayout


================================================
FILE: src/layouts/PageLayout/PageLayout.scss
================================================
.page-layout__viewport {
  padding-top: 4rem;
}

.page-layout__nav-item--active {
  font-weight: bold;
  text-decoration: underline;
}


================================================
FILE: src/main.js
================================================
import React from 'react'
import ReactDOM from 'react-dom'
import createStore from './store/createStore'
import './styles/main.scss'

// Store Initialization
// ------------------------------------
const store = createStore(window.__INITIAL_STATE__)

// Render Setup
// ------------------------------------
const MOUNT_NODE = document.getElementById('root')

let render = () => {
  const App = require('./components/App').default
  const routes = require('./routes/index').default(store)

  ReactDOM.render(
    <App store={store} routes={routes} />,
    MOUNT_NODE
  )
}

// Development Tools
// ------------------------------------
if (__DEV__) {
  if (module.hot) {
    const renderApp = render
    const renderError = (error) => {
      const RedBox = require('redbox-react').default

      ReactDOM.render(<RedBox error={error} />, MOUNT_NODE)
    }

    render = () => {
      try {
        renderApp()
      } catch (e) {
        console.error(e)
        renderError(e)
      }
    }

    // Setup hot module replacement
    module.hot.accept([
      './components/App',
      './routes/index',
    ], () =>
      setImmediate(() => {
        ReactDOM.unmountComponentAtNode(MOUNT_NODE)
        render()
      })
    )
  }
}

// Let's Go!
// ------------------------------------
if (!__TEST__) render()


================================================
FILE: src/normalize.js
================================================
/* ========================================================

   ** Browser Normalizer **

   This file is responsible for normalizing the browser environment before
   the application starts. Doing this allows us to safely use modern language
   features even when the end user is running an older browser.

   The following polyfills are included by default:

   1) Object.assign
   2) Promise
   3) Fetch

   ====================================================== */

// 1) Object.assign
// ------------------------------------
// We can't rely on Object.assign being a function since it may be buggy, so
// defer to `object-assign`. If our Object.assign implementation is correct
// (determined by `object-assign` internally) the polyfill will be discarded
// and the native implementation used.
Object.assign = require('object-assign')

// 2) Promise
// ------------------------------------
if (typeof Promise === 'undefined') {
  require('promise/lib/rejection-tracking').enable()
  window.Promise = require('promise/lib/es6-extensions.js')
}

// 3) Fetch
// ------------------------------------
// Fetch polyfill depends on a Promise implementation, so it must come after
// the feature check / polyfill above.
if (typeof window.fetch === 'undefined') {
  require('whatwg-fetch')
}


================================================
FILE: src/routes/Counter/components/Counter.js
================================================
import React from 'react'
import PropTypes from 'prop-types'

export const Counter = ({ counter, increment, doubleAsync }) => (
  <div style={{ margin: '0 auto' }} >
    <h2>Counter: {counter}</h2>
    <button className='btn btn-primary' onClick={increment}>
      Increment
    </button>
    {' '}
    <button className='btn btn-secondary' onClick={doubleAsync}>
      Double (Async)
    </button>
  </div>
)
Counter.propTypes = {
  counter: PropTypes.number.isRequired,
  increment: PropTypes.func.isRequired,
  doubleAsync: PropTypes.func.isRequired,
}

export default Counter


================================================
FILE: src/routes/Counter/containers/CounterContainer.js
================================================
import { connect } from 'react-redux'
import { increment, doubleAsync } from '../modules/counter'

/*  This is a container component. Notice it does not contain any JSX,
    nor does it import React. This component is **only** responsible for
    wiring in the actions and state necessary to render a presentational
    component - in this case, the counter:   */

import Counter from '../components/Counter'

/*  Object of action creators (can also be function that returns object).
    Keys will be passed as props to presentational components. Here we are
    implementing our wrapper around increment; the component doesn't care   */

const mapDispatchToProps = {
  increment : () => increment(1),
  doubleAsync
}

const mapStateToProps = (state) => ({
  counter : state.counter
})

/*  Note: mapStateToProps is where you should use `reselect` to create selectors, ie:

    import { createSelector } from 'reselect'
    const counter = (state) => state.counter
    const tripleCount = createSelector(counter, (count) => count * 3)
    const mapStateToProps = (state) => ({
      counter: tripleCount(state)
    })

    Selectors can compute derived data, allowing Redux to store the minimal possible state.
    Selectors are efficient. A selector is not recomputed unless one of its arguments change.
    Selectors are composable. They can be used as input to other selectors.
    https://github.com/reactjs/reselect    */

export default connect(mapStateToProps, mapDispatchToProps)(Counter)


================================================
FILE: src/routes/Counter/index.js
================================================
import { injectReducer } from '../../store/reducers'

export default (store) => ({
  path : 'counter',
  /*  Async getComponent is only invoked when route matches   */
  getComponent (nextState, cb) {
    /*  Webpack - use 'require.ensure' to create a split point
        and embed an async module loader (jsonp) when bundling   */
    require.ensure([], (require) => {
      /*  Webpack - use require callback to define
          dependencies for bundling   */
      const Counter = require('./containers/CounterContainer').default
      const reducer = require('./modules/counter').default

      /*  Add the reducer to the store on key 'counter'  */
      injectReducer(store, { key: 'counter', reducer })

      /*  Return getComponent   */
      cb(null, Counter)

    /* Webpack named bundle   */
    }, 'counter')
  }
})


================================================
FILE: src/routes/Counter/modules/counter.js
================================================
// ------------------------------------
// Constants
// ------------------------------------
export const COUNTER_INCREMENT = 'COUNTER_INCREMENT'
export const COUNTER_DOUBLE_ASYNC = 'COUNTER_DOUBLE_ASYNC'

// ------------------------------------
// Actions
// ------------------------------------
export function increment (value = 1) {
  return {
    type    : COUNTER_INCREMENT,
    payload : value
  }
}

/*  This is a thunk, meaning it is a function that immediately
    returns a function for lazy evaluation. It is incredibly useful for
    creating async actions, especially when combined with redux-thunk! */

export const doubleAsync = () => {
  return (dispatch, getState) => {
    return new Promise((resolve) => {
      setTimeout(() => {
        dispatch({
          type    : COUNTER_DOUBLE_ASYNC,
          payload : getState().counter
        })
        resolve()
      }, 200)
    })
  }
}

export const actions = {
  increment,
  doubleAsync
}

// ------------------------------------
// Action Handlers
// ------------------------------------
const ACTION_HANDLERS = {
  [COUNTER_INCREMENT]    : (state, action) => state + action.payload,
  [COUNTER_DOUBLE_ASYNC] : (state, action) => state * 2
}

// ------------------------------------
// Reducer
// ------------------------------------
const initialState = 0
export default function counterReducer (state = initialState, action) {
  const handler = ACTION_HANDLERS[action.type]

  return handler ? handler(state, action) : state
}


================================================
FILE: src/routes/Home/components/HomeView.js
================================================
import React from 'react'
import DuckImage from '../assets/Duck.jpg'
import './HomeView.scss'

export const HomeView = () => (
  <div>
    <h4>Welcome!</h4>
    <img alt='This is a duck, because Redux!' className='duck' src={DuckImage} />
  </div>
)

export default HomeView


================================================
FILE: src/routes/Home/components/HomeView.scss
================================================
.duck {
  display: block;
  width: 120px;
  margin: 1.5rem auto;
}


================================================
FILE: src/routes/Home/index.js
================================================
import HomeView from './components/HomeView'

// Sync route definition
export default {
  component : HomeView
}


================================================
FILE: src/routes/index.js
================================================
// We only need to import the modules necessary for initial render
import CoreLayout from '../layouts/PageLayout/PageLayout'
import Home from './Home'
import CounterRoute from './Counter'

/*  Note: Instead of using JSX, we recommend using react-router
    PlainRoute objects to build route definitions.   */

export const createRoutes = (store) => ({
  path        : '/',
  component   : CoreLayout,
  indexRoute  : Home,
  childRoutes : [
    CounterRoute(store)
  ]
})

/*  Note: childRoutes can be chunked or otherwise loaded programmatically
    using getChildRoutes with the following signature:

    getChildRoutes (location, cb) {
      require.ensure([], (require) => {
        cb(null, [
          // Remove imports!
          require('./Counter').default(store)
        ])
      })
    }

    However, this is not necessary for code-splitting! It simply provides
    an API for async route definitions. Your code splitting should occur
    inside the route `getComponent` function, since it is only invoked
    when the route exists and matches.
*/

export default createRoutes


================================================
FILE: src/store/createStore.js
================================================
import { applyMiddleware, compose, createStore as createReduxStore } from 'redux'
import thunk from 'redux-thunk'
import { browserHistory } from 'react-router'
import makeRootReducer from './reducers'
import { updateLocation } from './location'

const createStore = (initialState = {}) => {
  // ======================================================
  // Middleware Configuration
  // ======================================================
  const middleware = [thunk]

  // ======================================================
  // Store Enhancers
  // ======================================================
  const enhancers = []
  let composeEnhancers = compose

  if (__DEV__) {
    if (typeof window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ === 'function') {
      composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
    }
  }

  // ======================================================
  // Store Instantiation and HMR Setup
  // ======================================================
  const store = createReduxStore(
    makeRootReducer(),
    initialState,
    composeEnhancers(
      applyMiddleware(...middleware),
      ...enhancers
    )
  )
  store.asyncReducers = {}

  // To unsubscribe, invoke `store.unsubscribeHistory()` anytime
  store.unsubscribeHistory = browserHistory.listen(updateLocation(store))

  if (module.hot) {
    module.hot.accept('./reducers', () => {
      const reducers = require('./reducers').default
      store.replaceReducer(reducers(store.asyncReducers))
    })
  }

  return store
}

export default createStore


================================================
FILE: src/store/location.js
================================================
import browserHistory from 'react-router/lib/browserHistory'

// ------------------------------------
// Constants
// ------------------------------------
export const LOCATION_CHANGE = 'LOCATION_CHANGE'

// ------------------------------------
// Actions
// ------------------------------------
export function locationChange (location = '/') {
  return {
    type    : LOCATION_CHANGE,
    payload : location
  }
}

// ------------------------------------
// Specialized Action Creator
// ------------------------------------
export const updateLocation = ({ dispatch }) => {
  return (nextLocation) => dispatch(locationChange(nextLocation))
}

// ------------------------------------
// Reducer
// ------------------------------------
const initialState = browserHistory.getCurrentLocation()
export default function locationReducer (state = initialState, action) {
  return action.type === LOCATION_CHANGE
    ? action.payload
    : state
}


================================================
FILE: src/store/reducers.js
================================================
import { combineReducers } from 'redux'
import locationReducer from './location'

export const makeRootReducer = (asyncReducers) => {
  return combineReducers({
    location: locationReducer,
    ...asyncReducers
  })
}

export const injectReducer = (store, { key, reducer }) => {
  if (Object.hasOwnProperty.call(store.asyncReducers, key)) return

  store.asyncReducers[key] = reducer
  store.replaceReducer(makeRootReducer(store.asyncReducers))
}

export default makeRootReducer


================================================
FILE: src/styles/_base.scss
================================================
/*
Application Settings Go Here
------------------------------------
This file acts as a bundler for all variables/mixins/themes, so they
can easily be swapped out without `core.scss` ever having to know.

For example:

@import './variables/colors';
@import './variables/components';
@import './themes/default';
*/


================================================
FILE: src/styles/main.scss
================================================
@import 'base';
@import '~bootstrap/scss/bootstrap.scss';

// Some best-practice CSS that's useful for most apps
// Just remove them if they're not what you want
html {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
  height: 100%;
}

*,
*:before,
*:after {
  box-sizing: inherit;
}


================================================
FILE: tests/.eslintrc
================================================
{
  "extends" : "../.eslintrc",
  "env"     : {
    "mocha" : true
  },
  "globals" : {
    "expect" : false,
    "should" : false,
    "sinon"  : false
  }
}


================================================
FILE: tests/layouts/PageLayout.spec.js
================================================
import React from 'react'
import PageLayout from 'layouts/PageLayout/PageLayout'
import { shallow } from 'enzyme'

describe('(Layout) PageLayout', () => {
  it('renders as a <div>', () => {
    shallow(<PageLayout />).should.have.tagName('div')
  })

  it('renders a project title', () => {
    shallow(<PageLayout />).find('h1').should.have.text('React Redux Starter Kit')
  })

  it('renders its children inside of the viewport', () => {
    const Child = () => <h2>child</h2>
    shallow(
      <PageLayout>
        <Child />
      </PageLayout>
    )
      .find('.page-layout__viewport')
      .should.contain(<Child />)
  })
})


================================================
FILE: tests/routes/Counter/components/Counter.spec.js
================================================
import React from 'react'
import { bindActionCreators } from 'redux'
import { Counter } from 'routes/Counter/components/Counter'
import { shallow } from 'enzyme'

describe('(Component) Counter', () => {
  let _props, _spies, _wrapper

  beforeEach(() => {
    _spies = {}
    _props = {
      counter : 5,
      ...bindActionCreators({
        doubleAsync : (_spies.doubleAsync = sinon.spy()),
        increment   : (_spies.increment = sinon.spy())
      }, _spies.dispatch = sinon.spy())
    }
    _wrapper = shallow(<Counter {..._props} />)
  })

  it('renders as a <div>.', () => {
    expect(_wrapper.is('div')).to.equal(true)
  })

  it('renders with an <h2> that includes Counter label.', () => {
    expect(_wrapper.find('h2').text()).to.match(/Counter:/)
  })

  it('renders {props.counter} at the end of the sample counter <h2>.', () => {
    expect(_wrapper.find('h2').text()).to.match(/5$/)
    _wrapper.setProps({ counter: 8 })
    expect(_wrapper.find('h2').text()).to.match(/8$/)
  })

  it('renders exactly two buttons.', () => {
    expect(_wrapper.find('button')).to.have.length(2)
  })

  describe('Increment', () => {
    let _button

    beforeEach(() => {
      _button = _wrapper.find('button').filterWhere(a => a.text() === 'Increment')
    })

    it('exists', () => {
      expect(_button).to.exist()
    })

    it('is a primary button', () => {
      expect(_button.hasClass('btn btn-primary')).to.be.true()
    })

    it('Calls props.increment when clicked', () => {
      _spies.dispatch.should.have.not.been.called()

      _button.simulate('click')

      _spies.dispatch.should.have.been.called()
      _spies.increment.should.have.been.called()
    })
  })

  describe('Double Async Button', () => {
    let _button

    beforeEach(() => {
      _button = _wrapper.find('button').filterWhere(a => a.text() === 'Double (Async)')
    })

    it('exists', () => {
      expect(_button).to.exist()
    })

    it('is a secondary button', () => {
      expect(_button.hasClass('btn btn-secondary')).to.be.true()
    })

    it('Calls props.doubleAsync when clicked', () => {
      _spies.dispatch.should.have.not.been.called()

      _button.simulate('click')

      _spies.dispatch.should.have.been.called()
      _spies.doubleAsync.should.have.been.called()
    })
  })
})


================================================
FILE: tests/routes/Counter/index.spec.js
================================================
import CounterRoute from 'routes/Counter'

describe('(Route) Counter', () => {
  it('returns a route configuration object', () => {
    expect(typeof CounterRoute({})).to.equal('object')
  })

  it('has a path \'counter\'', () => {
    expect(CounterRoute({}).path).to.equal('counter')
  })
})


================================================
FILE: tests/routes/Counter/modules/counter.spec.js
================================================
import {
  COUNTER_INCREMENT,
  increment,
  doubleAsync,
  default as counterReducer
} from 'routes/Counter/modules/counter'

describe('(Redux Module) Counter', () => {
  it('Should export a constant COUNTER_INCREMENT.', () => {
    expect(COUNTER_INCREMENT).to.equal('COUNTER_INCREMENT')
  })

  describe('(Reducer)', () => {
    it('Should be a function.', () => {
      expect(counterReducer).to.be.a('function')
    })

    it('Should initialize with a state of 0 (Number).', () => {
      expect(counterReducer(undefined, {})).to.equal(0)
    })

    it('Should return the previous state if an action was not matched.', () => {
      let state = counterReducer(undefined, {})
      expect(state).to.equal(0)
      state = counterReducer(state, { type: '@@@@@@@' })
      expect(state).to.equal(0)
      state = counterReducer(state, increment(5))
      expect(state).to.equal(5)
      state = counterReducer(state, { type: '@@@@@@@' })
      expect(state).to.equal(5)
    })
  })

  describe('(Action Creator) increment', () => {
    it('Should be exported as a function.', () => {
      expect(increment).to.be.a('function')
    })

    it('Should return an action with type "COUNTER_INCREMENT".', () => {
      expect(increment()).to.have.property('type', COUNTER_INCREMENT)
    })

    it('Should assign the first argument to the "payload" property.', () => {
      expect(increment(5)).to.have.property('payload', 5)
    })

    it('Should default the "payload" property to 1 if not provided.', () => {
      expect(increment()).to.have.property('payload', 1)
    })
  })

  describe('(Action Creator) doubleAsync', () => {
    let _globalState
    let _dispatchSpy
    let _getStateSpy

    beforeEach(() => {
      _globalState = {
        counter : counterReducer(undefined, {})
      }
      _dispatchSpy = sinon.spy((action) => {
        _globalState = {
          ..._globalState,
          counter : counterReducer(_globalState.counter, action)
        }
      })
      _getStateSpy = sinon.spy(() => {
        return _globalState
      })
    })

    it('Should be exported as a function.', () => {
      expect(doubleAsync).to.be.a('function')
    })

    it('Should return a function (is a thunk).', () => {
      expect(doubleAsync()).to.be.a('function')
    })

    it('Should return a promise from that thunk that gets fulfilled.', () => {
      return doubleAsync()(_dispatchSpy, _getStateSpy).should.eventually.be.fulfilled
    })

    it('Should call dispatch and getState exactly once.', () => {
      return doubleAsync()(_dispatchSpy, _getStateSpy)
        .then(() => {
          _dispatchSpy.should.have.been.calledOnce()
          _getStateSpy.should.have.been.calledOnce()
        })
    })

    it('Should produce a state that is double the previous state.', () => {
      _globalState = { counter: 2 }

      return doubleAsync()(_dispatchSpy, _getStateSpy)
        .then(() => {
          _dispatchSpy.should.have.been.calledOnce()
          _getStateSpy.should.have.been.calledOnce()
          expect(_globalState.counter).to.equal(4)
          return doubleAsync()(_dispatchSpy, _getStateSpy)
        })
        .then(() => {
          _dispatchSpy.should.have.been.calledTwice()
          _getStateSpy.should.have.been.calledTwice()
          expect(_globalState.counter).to.equal(8)
        })
    })
  })

  // NOTE: if you have a more complex state, you will probably want to verify
  // that you did not mutate the state. In this case our state is just a number
  // (which cannot be mutated).
  describe('(Action Handler) COUNTER_INCREMENT', () => {
    it('Should increment the state by the action payload\'s "value" property.', () => {
      let state = counterReducer(undefined, {})
      expect(state).to.equal(0)
      state = counterReducer(state, increment(1))
      expect(state).to.equal(1)
      state = counterReducer(state, increment(2))
      expect(state).to.equal(3)
      state = counterReducer(state, increment(-3))
      expect(state).to.equal(0)
    })
  })
})


================================================
FILE: tests/routes/Home/components/HomeView.spec.js
================================================
import React from 'react'
import { HomeView } from 'routes/Home/components/HomeView'
import { render } from 'enzyme'

describe('(View) Home', () => {
  let _component

  beforeEach(() => {
    _component = render(<HomeView />)
  })

  it('Renders a welcome message', () => {
    const welcome = _component.find('h4')
    expect(welcome).to.exist()
    expect(welcome.text()).to.match(/Welcome!/)
  })

  it('Renders an awesome duck image', () => {
    const duck = _component.find('img')
    expect(duck).to.exist()
    expect(duck.attr('alt')).to.match(/This is a duck, because Redux!/)
  })
})


================================================
FILE: tests/routes/Home/index.spec.js
================================================
import HomeRoute from 'routes/Home'

describe('(Route) Home', () => {
  let _component

  beforeEach(() => {
    _component = HomeRoute.component()
  })

  it('Should return a route configuration object', () => {
    expect(typeof HomeRoute).to.equal('object')
  })

  it('Should define a route component', () => {
    expect(_component.type).to.equal('div')
  })
})


================================================
FILE: tests/store/createStore.spec.js
================================================
import {
  default as createStore
} from 'store/createStore'

describe('(Store) createStore', () => {
  let store

  before(() => {
    store = createStore()
  })

  it('should have an empty asyncReducers object', () => {
    expect(store.asyncReducers).to.be.an('object')
    expect(store.asyncReducers).to.be.empty()
  })

  describe('(Location)', () => {
    it('store should be initialized with Location state', () => {
      const location = {
        pathname : '/echo'
      }
      store.dispatch({
        type    : 'LOCATION_CHANGE',
        payload : location
      })
      expect(store.getState().location).to.deep.equal(location)
    })
  })
})


================================================
FILE: tests/store/location.spec.js
================================================
import {
  LOCATION_CHANGE,
  locationChange,
  updateLocation,
  default as locationReducer
} from 'store/location'

describe('(Internal Module) Location', () => {
  it('Should export a constant LOCATION_CHANGE.', () => {
    expect(LOCATION_CHANGE).to.equal('LOCATION_CHANGE')
  })

  describe('(Reducer)', () => {
    it('Should be a function.', () => {
      expect(locationReducer).to.be.a('function')
    })

    it('Should initialize with a location object.', () => {
      expect(locationReducer(undefined, {})).to.be.an('object')
      expect(locationReducer(undefined, {})).to.have.property('pathname')
    })

    it('Should return the previous state if an action was not matched.', () => {
      let state = locationReducer(undefined, {})
      expect(state).to.be.an('object')
      expect(state).to.have.property('pathname')
      expect(state).to.have.property('pathname', '/context.html')
      state = locationReducer(state, { type: '@@@@@@@' })
      expect(state).to.have.property('pathname', '/context.html')

      const locationState = { pathname: '/yup' }
      state = locationReducer(state, locationChange(locationState))
      expect(state).to.equal(locationState)
      expect(state).to.have.property('pathname', '/yup')
      state = locationReducer(state, { type: '@@@@@@@' })
      expect(state).to.equal(locationState)
      expect(state).to.have.property('pathname', '/yup')
    })
  })

  describe('(Action Creator) locationChange', () => {
    it('Should be exported as a function.', () => {
      expect(locationChange).to.be.a('function')
    })

    it('Should return an action with type "LOCATION_CHANGE".', () => {
      expect(locationChange()).to.have.property('type', LOCATION_CHANGE)
    })

    it('Should assign the first argument to the "payload" property.', () => {
      const locationState = { pathname: '/yup' }
      expect(locationChange(locationState)).to.have.property('payload', locationState)
    })

    it('Should default the "payload" property to "/" if not provided.', () => {
      expect(locationChange()).to.have.property('payload', '/')
    })
  })

  describe('(Specialized Action Creator) updateLocation', () => {
    let _globalState
    let _dispatchSpy

    beforeEach(() => {
      _globalState = {
        location : locationReducer(undefined, {})
      }
      _dispatchSpy = sinon.spy((action) => {
        _globalState = {
          ..._globalState,
          location : locationReducer(_globalState.location, action)
        }
      })
    })

    it('Should be exported as a function.', () => {
      expect(updateLocation).to.be.a('function')
    })

    it('Should return a function (is a thunk).', () => {
      expect(updateLocation({ dispatch: _dispatchSpy })).to.be.a('function')
    })

    it('Should call dispatch exactly once.', () => {
      updateLocation({ dispatch: _dispatchSpy })('/')
      expect(_dispatchSpy.should.have.been.calledOnce)
    })
  })
})


================================================
FILE: tests/test-bundler.js
================================================
import 'normalize.js'
import chai from 'chai'
import sinon from 'sinon'
import dirtyChai from 'dirty-chai'
import chaiAsPromised from 'chai-as-promised'
import sinonChai from 'sinon-chai'
import chaiEnzyme from 'chai-enzyme'

// Mocha / Chai
// ------------------------------------
mocha.setup({ ui: 'bdd' })
chai.should()

global.chai = chai
global.expect = chai.expect
global.sinon = sinon

// Chai Plugins
// ------------------------------------
chai.use(chaiEnzyme())
chai.use(dirtyChai)
chai.use(chaiAsPromised)
chai.use(sinonChai)

// Test Importer
// ------------------------------------
// We use a Webpack global here as it is replaced with a string during compile.
// Using a regular JS variable is not statically analyzable so webpack will throw warnings.
const testsContext = require.context('./', true, /\.(spec|test)\.(js|ts|tsx)$/)

// When a test file changes, only rerun that spec file. If something outside of a
// test file changed, rerun all tests.
// https://www.npmjs.com/package/karma-webpack-with-fast-source-maps
const __karmaWebpackManifest__ = []
const allTests = testsContext.keys()
const changedTests = allTests.filter(path => {
  return __karmaWebpackManifest__.indexOf(path) !== -1
})

;(changedTests.length ? changedTests : allTests).forEach(testsContext)
Download .txt
gitextract_602yozfj/

├── .editorconfig
├── .eslintignore
├── .eslintrc
├── .gitignore
├── .travis.yml
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── build/
│   ├── karma.config.js
│   ├── lib/
│   │   └── logger.js
│   ├── scripts/
│   │   ├── compile.js
│   │   └── start.js
│   └── webpack.config.js
├── package.json
├── project.config.js
├── public/
│   ├── humans.txt
│   └── robots.txt
├── server/
│   └── main.js
├── src/
│   ├── components/
│   │   └── App.js
│   ├── index.html
│   ├── layouts/
│   │   └── PageLayout/
│   │       ├── PageLayout.js
│   │       └── PageLayout.scss
│   ├── main.js
│   ├── normalize.js
│   ├── routes/
│   │   ├── Counter/
│   │   │   ├── components/
│   │   │   │   └── Counter.js
│   │   │   ├── containers/
│   │   │   │   └── CounterContainer.js
│   │   │   ├── index.js
│   │   │   └── modules/
│   │   │       └── counter.js
│   │   ├── Home/
│   │   │   ├── components/
│   │   │   │   ├── HomeView.js
│   │   │   │   └── HomeView.scss
│   │   │   └── index.js
│   │   └── index.js
│   ├── store/
│   │   ├── createStore.js
│   │   ├── location.js
│   │   └── reducers.js
│   └── styles/
│       ├── _base.scss
│       └── main.scss
└── tests/
    ├── .eslintrc
    ├── layouts/
    │   └── PageLayout.spec.js
    ├── routes/
    │   ├── Counter/
    │   │   ├── components/
    │   │   │   └── Counter.spec.js
    │   │   ├── index.spec.js
    │   │   └── modules/
    │   │       └── counter.spec.js
    │   └── Home/
    │       ├── components/
    │       │   └── HomeView.spec.js
    │       └── index.spec.js
    ├── store/
    │   ├── createStore.spec.js
    │   └── location.spec.js
    └── test-bundler.js
Download .txt
SYMBOL INDEX (15 symbols across 7 files)

FILE: build/karma.config.js
  constant TEST_BUNDLER (line 4) | const TEST_BUNDLER = './tests/test-bundler.js'

FILE: project.config.js
  constant NODE_ENV (line 1) | const NODE_ENV = process.env.NODE_ENV || 'development'

FILE: src/components/App.js
  class App (line 6) | class App extends React.Component {
    method shouldComponentUpdate (line 12) | shouldComponentUpdate () {
    method render (line 16) | render () {

FILE: src/main.js
  constant MOUNT_NODE (line 12) | const MOUNT_NODE = document.getElementById('root')

FILE: src/routes/Counter/index.js
  method getComponent (line 6) | getComponent (nextState, cb) {

FILE: src/routes/Counter/modules/counter.js
  constant COUNTER_INCREMENT (line 4) | const COUNTER_INCREMENT = 'COUNTER_INCREMENT'
  constant COUNTER_DOUBLE_ASYNC (line 5) | const COUNTER_DOUBLE_ASYNC = 'COUNTER_DOUBLE_ASYNC'
  function increment (line 10) | function increment (value = 1) {
  constant ACTION_HANDLERS (line 43) | const ACTION_HANDLERS = {
  function counterReducer (line 52) | function counterReducer (state = initialState, action) {

FILE: src/store/location.js
  constant LOCATION_CHANGE (line 6) | const LOCATION_CHANGE = 'LOCATION_CHANGE'
  function locationChange (line 11) | function locationChange (location = '/') {
  function locationReducer (line 29) | function locationReducer (state = initialState, action) {
Condensed preview — 48 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (85K chars).
[
  {
    "path": ".editorconfig",
    "chars": 781,
    "preview": "# http://editorconfig.org\n\n# A special property that should be specified at the top of the file outside of\n# any section"
  },
  {
    "path": ".eslintignore",
    "chars": 51,
    "preview": "coverage/**\nnode_modules/**\ndist/**\nsrc/index.html\n"
  },
  {
    "path": ".eslintrc",
    "chars": 542,
    "preview": "{\n  \"parser\": \"babel-eslint\",\n  \"extends\": [\n    \"standard\",\n    \"standard-react\"\n  ],\n  \"plugins\": [\n    \"babel\",\n    \""
  },
  {
    "path": ".gitignore",
    "chars": 62,
    "preview": ".DS_STORE\n*.log\nnode_modules\ndist\ncoverage\n.idea/\n.yarn-cache\n"
  },
  {
    "path": ".travis.yml",
    "chars": 195,
    "preview": "sudo: false\nlanguage: node_js\nnode_js:\n  - \"5\"\n  - \"6\"\n\ncache:\n  yarn: true\n  directories:\n    - node_modules\n\nscript:\n "
  },
  {
    "path": "CHANGELOG.md",
    "chars": 19646,
    "preview": "Changelog\n=========\n\n3.0.1\n-------------\n\n### Improvements\n* Added Node `^5.0.0` to CI build\n\n### Fixes\n* Removed usage "
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 1957,
    "preview": "# Contributing Guidelines\n\nSome basic conventions for contributing to this project.\n\n### General\n\nPlease make sure that "
  },
  {
    "path": "LICENSE",
    "chars": 1081,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2015 David Zukowski\n\nPermission is hereby granted, free of charge, to any person ob"
  },
  {
    "path": "README.md",
    "chars": 11766,
    "preview": "# Deprecation Warning\n\nThis project was started at the advent of the Redux ecosystem, and was intended to help users get"
  },
  {
    "path": "build/karma.config.js",
    "chars": 1098,
    "preview": "const argv = require('yargs').argv\nconst webpackConfig = require('./webpack.config')\n\nconst TEST_BUNDLER = './tests/test"
  },
  {
    "path": "build/lib/logger.js",
    "chars": 736,
    "preview": "const chalk = require('chalk')\nconst figures = require('figures')\n\n// Need to support Node versions that don't support s"
  },
  {
    "path": "build/scripts/compile.js",
    "chars": 1771,
    "preview": "const fs = require('fs-extra')\nconst path = require('path')\nconst chalk = require('chalk')\nconst webpack = require('webp"
  },
  {
    "path": "build/scripts/start.js",
    "chars": 191,
    "preview": "const logger = require('../lib/logger')\n\nlogger.info('Starting server...')\nrequire('../../server/main').listen(3000, () "
  },
  {
    "path": "build/webpack.config.js",
    "chars": 5494,
    "preview": "const path = require('path')\nconst webpack = require('webpack')\nconst HtmlWebpackPlugin = require('html-webpack-plugin')"
  },
  {
    "path": "package.json",
    "chars": 3098,
    "preview": "{\n  \"name\": \"react-redux-starter-kit\",\n  \"version\": \"3.0.1\",\n  \"description\": \"Get started with React, Redux, and React-"
  },
  {
    "path": "project.config.js",
    "chars": 1084,
    "preview": "const NODE_ENV = process.env.NODE_ENV || 'development'\n\nmodule.exports = {\n  /** The environment to use when building th"
  },
  {
    "path": "public/humans.txt",
    "chars": 103,
    "preview": "# Check it out: http://humanstxt.org/\n\n# TEAM\n\n    <name> -- <role> -- <twitter>\n\n# THANKS\n\n    <name>\n"
  },
  {
    "path": "public/robots.txt",
    "chars": 24,
    "preview": "User-agent: *\nDisallow:\n"
  },
  {
    "path": "server/main.js",
    "chars": 2491,
    "preview": "const express = require('express')\nconst path = require('path')\nconst webpack = require('webpack')\nconst logger = requir"
  },
  {
    "path": "src/components/App.js",
    "chars": 601,
    "preview": "import React from 'react'\nimport { browserHistory, Router } from 'react-router'\nimport { Provider } from 'react-redux'\ni"
  },
  {
    "path": "src/index.html",
    "chars": 253,
    "preview": "<!doctype html>\n<html lang=\"en\">\n<head>\n  <title>React Redux Starter Kit</title>\n  <meta charset=\"utf-8\">\n  <meta name=\""
  },
  {
    "path": "src/layouts/PageLayout/PageLayout.js",
    "chars": 612,
    "preview": "import React from 'react'\nimport { IndexLink, Link } from 'react-router'\nimport PropTypes from 'prop-types'\nimport './Pa"
  },
  {
    "path": "src/layouts/PageLayout/PageLayout.scss",
    "chars": 135,
    "preview": ".page-layout__viewport {\n  padding-top: 4rem;\n}\n\n.page-layout__nav-item--active {\n  font-weight: bold;\n  text-decoration"
  },
  {
    "path": "src/main.js",
    "chars": 1310,
    "preview": "import React from 'react'\nimport ReactDOM from 'react-dom'\nimport createStore from './store/createStore'\nimport './style"
  },
  {
    "path": "src/normalize.js",
    "chars": 1288,
    "preview": "/* ========================================================\n\n   ** Browser Normalizer **\n\n   This file is responsible fo"
  },
  {
    "path": "src/routes/Counter/components/Counter.js",
    "chars": 580,
    "preview": "import React from 'react'\nimport PropTypes from 'prop-types'\n\nexport const Counter = ({ counter, increment, doubleAsync "
  },
  {
    "path": "src/routes/Counter/containers/CounterContainer.js",
    "chars": 1497,
    "preview": "import { connect } from 'react-redux'\nimport { increment, doubleAsync } from '../modules/counter'\n\n/*  This is a contain"
  },
  {
    "path": "src/routes/Counter/index.js",
    "chars": 828,
    "preview": "import { injectReducer } from '../../store/reducers'\n\nexport default (store) => ({\n  path : 'counter',\n  /*  Async getCo"
  },
  {
    "path": "src/routes/Counter/modules/counter.js",
    "chars": 1503,
    "preview": "// ------------------------------------\n// Constants\n// ------------------------------------\nexport const COUNTER_INCREM"
  },
  {
    "path": "src/routes/Home/components/HomeView.js",
    "chars": 275,
    "preview": "import React from 'react'\nimport DuckImage from '../assets/Duck.jpg'\nimport './HomeView.scss'\n\nexport const HomeView = ("
  },
  {
    "path": "src/routes/Home/components/HomeView.scss",
    "chars": 67,
    "preview": ".duck {\n  display: block;\n  width: 120px;\n  margin: 1.5rem auto;\n}\n"
  },
  {
    "path": "src/routes/Home/index.js",
    "chars": 113,
    "preview": "import HomeView from './components/HomeView'\n\n// Sync route definition\nexport default {\n  component : HomeView\n}\n"
  },
  {
    "path": "src/routes/index.js",
    "chars": 1089,
    "preview": "// We only need to import the modules necessary for initial render\nimport CoreLayout from '../layouts/PageLayout/PageLay"
  },
  {
    "path": "src/store/createStore.js",
    "chars": 1566,
    "preview": "import { applyMiddleware, compose, createStore as createReduxStore } from 'redux'\nimport thunk from 'redux-thunk'\nimport"
  },
  {
    "path": "src/store/location.js",
    "chars": 944,
    "preview": "import browserHistory from 'react-router/lib/browserHistory'\n\n// ------------------------------------\n// Constants\n// --"
  },
  {
    "path": "src/store/reducers.js",
    "chars": 481,
    "preview": "import { combineReducers } from 'redux'\nimport locationReducer from './location'\n\nexport const makeRootReducer = (asyncR"
  },
  {
    "path": "src/styles/_base.scss",
    "chars": 315,
    "preview": "/*\nApplication Settings Go Here\n------------------------------------\nThis file acts as a bundler for all variables/mixin"
  },
  {
    "path": "src/styles/main.scss",
    "chars": 305,
    "preview": "@import 'base';\n@import '~bootstrap/scss/bootstrap.scss';\n\n// Some best-practice CSS that's useful for most apps\n// Just"
  },
  {
    "path": "tests/.eslintrc",
    "chars": 159,
    "preview": "{\n  \"extends\" : \"../.eslintrc\",\n  \"env\"     : {\n    \"mocha\" : true\n  },\n  \"globals\" : {\n    \"expect\" : false,\n    \"shoul"
  },
  {
    "path": "tests/layouts/PageLayout.spec.js",
    "chars": 634,
    "preview": "import React from 'react'\nimport PageLayout from 'layouts/PageLayout/PageLayout'\nimport { shallow } from 'enzyme'\n\ndescr"
  },
  {
    "path": "tests/routes/Counter/components/Counter.spec.js",
    "chars": 2304,
    "preview": "import React from 'react'\nimport { bindActionCreators } from 'redux'\nimport { Counter } from 'routes/Counter/components/"
  },
  {
    "path": "tests/routes/Counter/index.spec.js",
    "chars": 294,
    "preview": "import CounterRoute from 'routes/Counter'\n\ndescribe('(Route) Counter', () => {\n  it('returns a route configuration objec"
  },
  {
    "path": "tests/routes/Counter/modules/counter.spec.js",
    "chars": 4024,
    "preview": "import {\n  COUNTER_INCREMENT,\n  increment,\n  doubleAsync,\n  default as counterReducer\n} from 'routes/Counter/modules/cou"
  },
  {
    "path": "tests/routes/Home/components/HomeView.spec.js",
    "chars": 596,
    "preview": "import React from 'react'\nimport { HomeView } from 'routes/Home/components/HomeView'\nimport { render } from 'enzyme'\n\nde"
  },
  {
    "path": "tests/routes/Home/index.spec.js",
    "chars": 367,
    "preview": "import HomeRoute from 'routes/Home'\n\ndescribe('(Route) Home', () => {\n  let _component\n\n  beforeEach(() => {\n    _compon"
  },
  {
    "path": "tests/store/createStore.spec.js",
    "chars": 659,
    "preview": "import {\n  default as createStore\n} from 'store/createStore'\n\ndescribe('(Store) createStore', () => {\n  let store\n\n  bef"
  },
  {
    "path": "tests/store/location.spec.js",
    "chars": 2947,
    "preview": "import {\n  LOCATION_CHANGE,\n  locationChange,\n  updateLocation,\n  default as locationReducer\n} from 'store/location'\n\nde"
  },
  {
    "path": "tests/test-bundler.js",
    "chars": 1288,
    "preview": "import 'normalize.js'\nimport chai from 'chai'\nimport sinon from 'sinon'\nimport dirtyChai from 'dirty-chai'\nimport chaiAs"
  }
]

About this extraction

This page contains the full source code of the dvdzkwsk/react-redux-starter-kit GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 48 files (77.3 KB), approximately 20.5k tokens, and a symbol index with 15 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!