diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..7e3649a
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,16 @@
+# http://editorconfig.org
+root = true
+
+[*]
+indent_style = space
+indent_size = 2
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+[*.md]
+trim_trailing_whitespace = false
+
+[Makefile]
+indent_style = tab
diff --git a/.gitignore b/.gitignore
index 7595163..56b6cc8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,14 @@
-.DS_Store
+# See http://help.github.com/ignore-files/ for more about ignoring files.
+
+# dependencies
node_modules
+
+# testing
+coverage
+
+# production
+build
+
+# misc
+.DS_Store
npm-debug.log
diff --git a/.jscsrc b/.jscsrc
deleted file mode 100644
index f1f3b40..0000000
--- a/.jscsrc
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "preset": "airbnb",
- "validateIndentation": 4,
- "excludeFiles": ["**/node_modules/**"],
- "disallowMixedSpacesAndTabs": true,
- "disallowMultipleLineBreaks": true,
- "disallowMultipleLineStrings": true,
- "disallowMultipleSpaces": true,
- "disallowMultipleVarDecl": true,
- "disallowNewlineBeforeBlockStatements": true,
- "disallowOperatorBeforeLineBreak": [
- "+",
- "."
- ],
- "requireTrailingComma": false,
- "validateParameterSeparator": ", ",
- "validateQuoteMarks": "'",
- "requireSpaceBetweenArguments": true,
- "requirePaddingNewLinesAfterBlocks": {
- "allExcept": [
- "inCallExpressions",
- "inArrayExpressions",
- "inProperties"
- ]
- },
- "disallowPaddingNewlinesBeforeKeywords": [
- "else",
- "catch",
- "void",
- "typeof"
- ]
-}
\ No newline at end of file
diff --git a/.scss-lint.yml b/.scss-lint.yml
index 0384c19..129253f 100644
--- a/.scss-lint.yml
+++ b/.scss-lint.yml
@@ -21,8 +21,6 @@ linters:
DuplicateProperty:
enabled: true
- exclude:
- - bower_components/**/*.scss
EmptyLineBetweenBlocks:
enabled: false
@@ -38,7 +36,7 @@ linters:
Indentation:
enabled: true
- width: 4
+ width: 2
LeadingZero:
enabled: true
diff --git a/README.md b/README.md
index cd4abd8..79884de 100644
--- a/README.md
+++ b/README.md
@@ -1,30 +1,22 @@
-# NEVERBUILD generator
+# Neverbuild V2
-[Yeoman](http://yeoman.io) generator that scaffolds out a front-end web app.
+Kickstarts a new React app
## Features
-* Grunt
- - Automagically compile your SCSS
- - Image optimization
-* libsass
-* Bourbon for Sass - A simple and lightweight mixin library for SASS
-* Neat for Bourbon - A lightweight semantic grid framework for SASS and Bourbon
-* jQuery
-* Basic .editorconfig file for consistency across editors/IDEs
-* jscsrc and scss-lint rules
+* React
+* React Router
+* Webpack
+* SCSS
-For more information on what `generator-neverbuild` can do for you, take a look at the [Grunt tasks](https://github.com/vslio/generator-neverbuild/blob/master/app/templates/_package.json) used in the `package.json`.
-
-
-## Getting Started
-
-- Install: `npm install -g generator-neverbuild`
-- Create project directory and cd into it: `mkdir project-name && cd $_`
-- Run: `yo neverbuild`
-- Run `grunt` for building & watch + compile your SCSS files
+## Getting started
+- Install: `npm install`
+- Start dev: `npm start`
+- Production build: `npm run build`
## License
-[MIT license](http://opensource.org/licenses/MIT)
\ No newline at end of file
+[MIT license](http://opensource.org/licenses/MIT)
+
+This project was bootstrapped with [Create React App](https://github.com/facebookincubator/create-react-app).
diff --git a/app/index.js b/app/index.js
deleted file mode 100644
index 1d111fe..0000000
--- a/app/index.js
+++ /dev/null
@@ -1,56 +0,0 @@
-'use strict';
-
-var path = require('path');
-var yeoman = require('yeoman-generator');
-var chalk = require('chalk');
-var mkdirp = require('mkdirp');
-var _s = require('underscore.string');
-
-var NEVERGenerator = yeoman.generators.Base.extend({
- init: function() {
- this.pkg = require('../package.json');
- },
-
- app: function() {
- this.slugName = _s.slugify(this.appname);
-
- this.imagesFolder = 'images';
- this.scssFolder = 'scss';
- this.cssFolder = 'css';
- this.jsFolder = 'javascript';
-
- this.log(chalk.magenta(
- '[ Creating the structure. ]' +
- ' '
- ));
-
- // Creating all the project folders
- mkdirp(this.imagesFolder);
- mkdirp(this.scssFolder);
- mkdirp(this.cssFolder);
- mkdirp(this.jsFolder);
-
- // Moving the right files/folders to the right folders
- this.template('_package.json', 'package.json');
- this.copy('_Gruntfile.js', 'Gruntfile.js');
- this.copy('_gitignore', '.gitignore');
- this.copy('_editorconfig', '.editorconfig');
- this.copy('_jscsrc', '.jscsrc');
- this.copy('_scss-lint.yml', '.scss-lint.yml');
- },
-
- projectfiles: function() {
- this.template('_index.html', 'index.html');
- this.directory('_scss', this.scssFolder);
- },
-
- install: function() {
- this.log(chalk.green(
- '[ Cool. ]'
- ));
-
- this.installDependencies();
- }
-});
-
-module.exports = NEVERGenerator;
diff --git a/app/templates/_Gruntfile.js b/app/templates/_Gruntfile.js
deleted file mode 100644
index 6b97217..0000000
--- a/app/templates/_Gruntfile.js
+++ /dev/null
@@ -1,95 +0,0 @@
-module.exports = function(grunt) {
- grunt.project = {
- name: '<%= slugName %>',
- assetsFolder: ''
- };
-
- grunt.initConfig({
- pkg: grunt.file.readJSON('package.json'),
- connect: {
- dist: {
- options: {
- port: 8888,
-
- // Change this to '0.0.0.0' to access the server from outside
- hostname: 'localhost'
- }
- }
- },
- sass: {
- dev: {
- options: {
- outputStyle: 'nested',
- sourcemap: true
- },
- files: [{
- expand: true,
- cwd: grunt.project.assetsFolder + 'scss',
- src: ['app.scss'],
- dest: grunt.project.assetsFolder + 'css',
- ext: '.css'
- }]
- },
- dist: {
- options: {
- outputStyle: 'compressed',
- sourcemap: false
- },
- files: [{
- expand: true,
- cwd: grunt.project.assetsFolder + 'scss',
- src: ['app.scss'],
- dest: grunt.project.assetsFolder + 'css',
- ext: '.css'
- }]
- }
- },
- stripCssComments: {
- dist: {
- files: {
- 'css/app.css': 'css/app.css'
- }
- }
- },
- watch: {
- options: {
- livereload: true
- },
- sass: {
- files: grunt.project.assetsFolder + 'scss/{,**/}*.scss',
- tasks: ['sass:dev']
- }
- },
- imagemin: {
- dist: {
- files: [{
- expand: true,
- cwd: grunt.project.assetsFolder + 'images',
- src: '{,*/}*.{gif,jpeg,jpg,png}',
- dest: grunt.project.assetsFolder + 'images'
- }]
- }
- }
- });
-
- require('load-grunt-tasks')(grunt);
-
- // Time how long tasks take. Can help when optimizing build times
- require('time-grunt')(grunt);
-
- grunt.registerTask('default', [
- 'sass:dev',
- 'watch'
- ]);
-
- grunt.registerTask('dist', [
- 'sass:dist',
- 'stripCssComments:dist'
- ]);
-
- grunt.registerTask('serve', [
- 'sass:dev',
- 'connect:dist',
- 'watch'
- ]);
-};
diff --git a/app/templates/_editorconfig b/app/templates/_editorconfig
deleted file mode 100644
index 304901d..0000000
--- a/app/templates/_editorconfig
+++ /dev/null
@@ -1,30 +0,0 @@
-# This is our root editor config file
-root = true
-
-# All files
-# Linefeeds please
-# Always end on a new line
-# Always do UTF-8
-# Indent with 4 spaces
-# No messy whitespace at the end of lines
-[*]
-end_of_line = lf
-insert_final_newline = true
-charset = utf-8
-indent_style = space
-indent_size = 4
-trim_trailing_whitespace = true
-
-# YAML files only
-# Indent with 2 spaces in YAML, easier to read
-[*.yml]
-indent_size = 2
-
-# Don't strip trailing whitespace in MarkDown files
-[*.md]
-trim_trailing_whitespace = false
-
-# Makefiles
-# make requires tabs
-[Makefile]
-indent_style = tab
diff --git a/app/templates/_gitignore b/app/templates/_gitignore
deleted file mode 100644
index 5d36fab..0000000
--- a/app/templates/_gitignore
+++ /dev/null
@@ -1,5 +0,0 @@
-node_modules
-dist
-.tmp
-.sass-cache
-bower_components
\ No newline at end of file
diff --git a/app/templates/_index.html b/app/templates/_index.html
deleted file mode 100755
index 95012dc..0000000
--- a/app/templates/_index.html
+++ /dev/null
@@ -1,32 +0,0 @@
-
-
-
-
-
-
-
-
-
- <%= slugName %>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/templates/_jscsrc b/app/templates/_jscsrc
deleted file mode 100644
index f1f3b40..0000000
--- a/app/templates/_jscsrc
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "preset": "airbnb",
- "validateIndentation": 4,
- "excludeFiles": ["**/node_modules/**"],
- "disallowMixedSpacesAndTabs": true,
- "disallowMultipleLineBreaks": true,
- "disallowMultipleLineStrings": true,
- "disallowMultipleSpaces": true,
- "disallowMultipleVarDecl": true,
- "disallowNewlineBeforeBlockStatements": true,
- "disallowOperatorBeforeLineBreak": [
- "+",
- "."
- ],
- "requireTrailingComma": false,
- "validateParameterSeparator": ", ",
- "validateQuoteMarks": "'",
- "requireSpaceBetweenArguments": true,
- "requirePaddingNewLinesAfterBlocks": {
- "allExcept": [
- "inCallExpressions",
- "inArrayExpressions",
- "inProperties"
- ]
- },
- "disallowPaddingNewlinesBeforeKeywords": [
- "else",
- "catch",
- "void",
- "typeof"
- ]
-}
\ No newline at end of file
diff --git a/app/templates/_package.json b/app/templates/_package.json
deleted file mode 100644
index 6057fd7..0000000
--- a/app/templates/_package.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "name": "<%= slugName %>",
- "version": "0.0.1",
- "license": "MIT",
- "engines": {
- "node": ">=0.11.0"
- },
- "dependencies": {},
- "devDependencies": {
- "grunt-cli": "~0.1.13",
- "grunt": "~0.4.5",
- "grunt-sass": "^1.1.0",
- "grunt-contrib-watch": "~0.6.1",
- "load-grunt-tasks": "~3.1.0",
- "grunt-concurrent": "^1.0.0",
- "grunt-contrib-connect": "~0.9.0",
- "grunt-contrib-imagemin": "^0.9.3",
- "grunt-strip-css-comments": "~1.2.0",
- "time-grunt": "^1.0.0",
- "bourbon": "~4.2.6",
- "bourbon-neat": "~1.7.2"
- }
-}
diff --git a/app/templates/_scss-lint.yml b/app/templates/_scss-lint.yml
deleted file mode 100644
index 0384c19..0000000
--- a/app/templates/_scss-lint.yml
+++ /dev/null
@@ -1,106 +0,0 @@
-# Documentation: https://github.com/brigade/scss-lint/blob/master/lib/scss_lint/linter/README.md
-linters:
- BorderZero:
- enabled: true
- convention: none
-
- ColorKeyword:
- enabled: true
-
- ColorVariable:
- enabled: false
-
- Comment:
- enabled: false
-
- DebugStatement:
- enabled: true
-
- DeclarationOrder:
- enabled: true
-
- DuplicateProperty:
- enabled: true
- exclude:
- - bower_components/**/*.scss
-
- EmptyLineBetweenBlocks:
- enabled: false
-
- EmptyRule:
- enabled: true
-
- HexNotation:
- enabled: false
-
- ImportantRule:
- enabled: false
-
- Indentation:
- enabled: true
- width: 4
-
- LeadingZero:
- enabled: true
- style: include_zero
-
- NestingDepth:
- enabled: true
-
- PlaceholderInExtend:
- enabled: true
-
- PropertySortOrder:
- enabled: false
-
- QualifyingElement:
- enabled: true
- allow_element_with_attribute: true
-
- SelectorDepth:
- enabled: true
-
- SelectorFormat:
- enabled: true
- convention: hyphenated_BEM
-
- SingleLinePerProperty:
- enabled: true
- allow_single_line_rule_sets: false
-
- SingleLinePerSelector:
- enabled: true
-
- SpaceAfterComma:
- enabled: true
-
- SpaceAfterPropertyColon:
- enabled: true
- style: one_space
-
- SpaceBeforeBrace:
- enabled: true
- allow_single_line_padding: true
- style: space
-
- SpaceBetweenParens:
- enabled: true
- spaces: 0
-
- StringQuotes:
- enabled: true
- style: double_quotes
-
- TrailingSemicolon:
- enabled: true
-
- UnnecessaryMantissa:
- enabled: true
-
- UrlQuotes:
- enabled: true
-
- VariableForProperty:
- enabled: true
- properties:
- - color
diff --git a/app/templates/_scss/_base/_grid-settings.scss b/app/templates/_scss/_base/_grid-settings.scss
deleted file mode 100755
index 3268210..0000000
--- a/app/templates/_scss/_base/_grid-settings.scss
+++ /dev/null
@@ -1,9 +0,0 @@
-/**
- * Base styles ~ Grid options
- */
-$gutter: 0.3em;
-$border-box-sizing: true;
-$grid-columns: 12;
-$max-width: none;
-$visual-grid: false;
-$visual-grid-color: darken(#EFF7FB, 10%);
diff --git a/app/templates/_scss/_base/_grid.scss b/app/templates/_scss/_base/_grid.scss
deleted file mode 100644
index f991afe..0000000
--- a/app/templates/_scss/_base/_grid.scss
+++ /dev/null
@@ -1,16 +0,0 @@
-/**
- * Base styles ~ Grid
- */
-// .row { @include row; }
-// .one { @include span-columns(1); }
-// .two { @include span-columns(2); }
-// .three { @include span-columns(3); }
-// .four { @include span-columns(4); }
-// .five { @include span-columns(5); }
-// .six { @include span-columns(6); }
-// .seven { @include span-columns(7); }
-// .eight { @include span-columns(8); }
-// .nine { @include span-columns(9); }
-// .ten { @include span-columns(10); }
-// .eleven { @include span-columns(11); }
-// .twelve { @include span-columns(12); }
\ No newline at end of file
diff --git a/app/templates/_scss/_base/_type.scss b/app/templates/_scss/_base/_type.scss
deleted file mode 100644
index b695b8c..0000000
--- a/app/templates/_scss/_base/_type.scss
+++ /dev/null
@@ -1,116 +0,0 @@
-/**
- * Base ~ Type
- */
-
-/**
- * Type variables
- */
-$base-font: sans-serif !default;
-$alt-font: sans-serif !default;
-
-/**
- * Type styles
- */
-h1,
-.h1,
-%h1,
-h2,
-.h2,
-%h2,
-h3,
-.h3,
-%h3,
-h4,
-.h4,
-%h4,
-h5,
-.h5,
-%h5,
-h6,
-.h6,
-%h6 {
- margin: 14px 0;
- font-family: $alt-font;
- font-weight: normal;
- font-style: normal;
- color: $heading-colour;
- text-rendering: optimizeLegibility;
-}
-
-h1,
-.h1,
-%h1 {
- font-size: rem(44);
- line-height: 48.4px;
-}
-
-h2,
-.h2,
-%h2 {
- font-size: rem(37);
- line-height: 40.7px;
-}
-
-h3,
-.h3,
-%h3 {
- font-size: rem(27);
- line-height: 29.7px;
-}
-
-h4,
-.h4,
-%h4 {
- font-size: rem(23);
- line-height: 25.3px;
-}
-
-h5,
-.h5,
-%h5 {
- font-size: rem(17);
- line-height: 18.7px;
-}
-
-h6,
-.h6,
-%h6 {
- font-size: rem(14);
- line-height: 15.8px;
-}
-
-a {
- color: $link-colour;
- text-decoration: none;
-}
-
-p {
- margin-bottom: 17px;
- font-family: inherit;
- font-weight: normal;
-}
-
-hr {
- margin: 22px 0 21px;
- height: 0;
- border: solid $hr-colour;
- border-width: 1px 0 0;
- clear: both;
-}
-
-em,
-i {
- font-style: italic;
- line-height: inherit;
-}
-
-strong,
-b {
- font-weight: bold;
- line-height: inherit;
-}
-
-small {
- font-size: 60%;
- line-height: inherit;
-}
diff --git a/app/templates/_scss/app.scss b/app/templates/_scss/app.scss
deleted file mode 100644
index 5f37112..0000000
--- a/app/templates/_scss/app.scss
+++ /dev/null
@@ -1,45 +0,0 @@
-/**
- * Main Project imports
- */
-
-/**
- * Various project settings that need to be set globally
- */
-
-/**
- * Bourbon & Neat Libraries
- */
-@import "../node_modules/bourbon/app/assets/stylesheets/_bourbon";
-
-// Uncomment to enable Neat
-// @import "_base/_grid-settings";
-// @import "../node_modules/bourbon-neat/app/assets/stylesheets/_neat-helpers";
-// @import "../node_modules/bourbon-neat/app/assets/stylesheets/_neat";
-
-/**
- * Base styles
- */
-@import "_base/_colours";
-@import "_base/_easings";
-@import "_base/_normalize";
-@import "_base/_type";
-@import "_base/_grid";
-@import "_base/_forms";
-@import "_base/_base";
-
-/**
- * Reusable Component styles (header/footer/dropdowns etc)
- * Put them inside "common" folder
- */
-
-
-/**
- * Module styles (individual page styles)
- * Put them inside "modules" folder
- */
-
-
-/**
- * Plugin styles
- * Put them inside "plugins" folder
- */
diff --git a/config/babel.dev.js b/config/babel.dev.js
new file mode 100644
index 0000000..b40ff97
--- /dev/null
+++ b/config/babel.dev.js
@@ -0,0 +1,40 @@
+var path = require('path');
+var findCacheDir = require('find-cache-dir');
+
+module.exports = {
+ // Don't try to find .babelrc because we want to force this configuration.
+ babelrc: false,
+ // This is a feature of `babel-loader` for webpack (not Babel itself).
+ // It enables caching results in ./node_modules/.cache/react-scripts/
+ // directory for faster rebuilds. We use findCacheDir() because of:
+ // https://github.com/facebookincubator/create-react-app/issues/483
+ cacheDirectory: findCacheDir({
+ name: 'react-scripts'
+ }),
+ presets: [
+ // Latest stable ECMAScript features
+ require.resolve('babel-preset-latest'),
+ // JSX, Flow
+ require.resolve('babel-preset-react')
+ ],
+ plugins: [
+ // class { handleClick = () => { } }
+ require.resolve('babel-plugin-transform-class-properties'),
+ // { ...todo, completed: true }
+ require.resolve('babel-plugin-transform-object-rest-spread'),
+ // function* () { yield 42; yield 43; }
+ [require.resolve('babel-plugin-transform-regenerator'), {
+ // Async functions are converted to generators by babel-preset-latest
+ async: false
+ }],
+ // Polyfills the runtime needed for async/await and generators
+ [require.resolve('babel-plugin-transform-runtime'), {
+ helpers: false,
+ polyfill: false,
+ regenerator: true,
+ // Resolve the Babel runtime relative to the config.
+ // You can safely remove this after ejecting:
+ moduleName: path.dirname(require.resolve('babel-runtime/package'))
+ }]
+ ]
+};
diff --git a/config/babel.prod.js b/config/babel.prod.js
new file mode 100644
index 0000000..28fe233
--- /dev/null
+++ b/config/babel.prod.js
@@ -0,0 +1,38 @@
+var path = require('path');
+
+module.exports = {
+ // Don't try to find .babelrc because we want to force this configuration.
+ babelrc: false,
+ presets: [
+ // Latest stable ECMAScript features
+ require.resolve('babel-preset-latest'),
+ // JSX, Flow
+ require.resolve('babel-preset-react')
+ ],
+ plugins: [
+ // class { handleClick = () => { } }
+ require.resolve('babel-plugin-transform-class-properties'),
+ // { ...todo, completed: true }
+ require.resolve('babel-plugin-transform-object-rest-spread'),
+ // function* () { yield 42; yield 43; }
+ [require.resolve('babel-plugin-transform-regenerator'), {
+ // Async functions are converted to generators by babel-preset-latest
+ async: false
+ }],
+ // Polyfills the runtime needed for async/await and generators
+ [require.resolve('babel-plugin-transform-runtime'), {
+ helpers: false,
+ polyfill: false,
+ regenerator: true,
+ // Resolve the Babel runtime relative to the config.
+ // You can safely remove this after ejecting:
+ moduleName: path.dirname(require.resolve('babel-runtime/package'))
+ }],
+ // Optimization: hoist JSX that never changes out of render()
+ // Disabled because of issues:
+ // * https://github.com/facebookincubator/create-react-app/issues/525
+ // * https://phabricator.babeljs.io/search/query/pCNlnC2xzwzx/
+ // TODO: Enable again when these issues are resolved.
+ // require.resolve('babel-plugin-transform-react-constant-elements')
+ ]
+};
diff --git a/config/env.js b/config/env.js
new file mode 100644
index 0000000..846077f
--- /dev/null
+++ b/config/env.js
@@ -0,0 +1,15 @@
+// Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be
+// injected into the application via DefinePlugin in Webpack configuration.
+
+var REACT_APP = /^REACT_APP_/i;
+var NODE_ENV = JSON.stringify(process.env.NODE_ENV || 'development');
+
+module.exports = Object
+ .keys(process.env)
+ .filter(key => REACT_APP.test(key))
+ .reduce((env, key) => {
+ env['process.env.' + key] = JSON.stringify(process.env[key]);
+ return env;
+ }, {
+ 'process.env.NODE_ENV': NODE_ENV
+ });
diff --git a/config/eslint.js b/config/eslint.js
new file mode 100644
index 0000000..53361db
--- /dev/null
+++ b/config/eslint.js
@@ -0,0 +1,200 @@
+// Inspired by https://github.com/airbnb/javascript but less opinionated.
+
+// We use eslint-loader so even warnings are very visibile.
+// This is why we only use "WARNING" level for potential errors,
+// and we don't use "ERROR" level at all.
+
+// In the future, we might create a separate list of rules for production.
+// It would probably be more strict.
+
+module.exports = {
+ root: true,
+
+ parser: 'babel-eslint',
+
+ // import plugin is temporarily disabled, scroll below to see why
+ plugins: [/*'import', */'flowtype', 'jsx-a11y', 'react'],
+
+ env: {
+ browser: true,
+ commonjs: true,
+ es6: true,
+ jest: true,
+ node: true
+ },
+
+ parserOptions: {
+ ecmaVersion: 6,
+ sourceType: 'module',
+ ecmaFeatures: {
+ jsx: true,
+ generators: true,
+ experimentalObjectRestSpread: true
+ }
+ },
+
+ settings: {
+ 'import/ignore': [
+ 'node_modules',
+ '\\.(json|css|jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$',
+ ],
+ 'import/extensions': ['.js'],
+ 'import/resolver': {
+ node: {
+ extensions: ['.js', '.json']
+ }
+ }
+ },
+
+ rules: {
+ // http://eslint.org/docs/rules/
+ 'array-callback-return': 'warn',
+ 'default-case': ['warn', { commentPattern: '^no default$' }],
+ 'dot-location': ['warn', 'property'],
+ eqeqeq: ['warn', 'allow-null'],
+ 'guard-for-in': 'warn',
+ 'new-parens': 'warn',
+ 'no-array-constructor': 'warn',
+ 'no-caller': 'warn',
+ 'no-cond-assign': ['warn', 'always'],
+ 'no-const-assign': 'warn',
+ 'no-control-regex': 'warn',
+ 'no-delete-var': 'warn',
+ 'no-dupe-args': 'warn',
+ 'no-dupe-class-members': 'warn',
+ 'no-dupe-keys': 'warn',
+ 'no-duplicate-case': 'warn',
+ 'no-empty-character-class': 'warn',
+ 'no-empty-pattern': 'warn',
+ 'no-eval': 'warn',
+ 'no-ex-assign': 'warn',
+ 'no-extend-native': 'warn',
+ 'no-extra-bind': 'warn',
+ 'no-extra-label': 'warn',
+ 'no-fallthrough': 'warn',
+ 'no-func-assign': 'warn',
+ 'no-implied-eval': 'warn',
+ 'no-invalid-regexp': 'warn',
+ 'no-iterator': 'warn',
+ 'no-label-var': 'warn',
+ 'no-labels': ['warn', { allowLoop: false, allowSwitch: false }],
+ 'no-lone-blocks': 'warn',
+ 'no-loop-func': 'warn',
+ 'no-mixed-operators': ['warn', {
+ groups: [
+ ['&', '|', '^', '~', '<<', '>>', '>>>'],
+ ['==', '!=', '===', '!==', '>', '>=', '<', '<='],
+ ['&&', '||'],
+ ['in', 'instanceof']
+ ],
+ allowSamePrecedence: false
+ }],
+ 'no-multi-str': 'warn',
+ 'no-native-reassign': 'warn',
+ 'no-negated-in-lhs': 'warn',
+ 'no-new-func': 'warn',
+ 'no-new-object': 'warn',
+ 'no-new-symbol': 'warn',
+ 'no-new-wrappers': 'warn',
+ 'no-obj-calls': 'warn',
+ 'no-octal': 'warn',
+ 'no-octal-escape': 'warn',
+ 'no-redeclare': 'warn',
+ 'no-regex-spaces': 'warn',
+ 'no-restricted-syntax': [
+ 'warn',
+ 'LabeledStatement',
+ 'WithStatement',
+ ],
+ 'no-script-url': 'warn',
+ 'no-self-assign': 'warn',
+ 'no-self-compare': 'warn',
+ 'no-sequences': 'warn',
+ 'no-shadow-restricted-names': 'warn',
+ 'no-sparse-arrays': 'warn',
+ 'no-template-curly-in-string': 'warn',
+ 'no-this-before-super': 'warn',
+ 'no-throw-literal': 'warn',
+ 'no-undef': 'error',
+ 'no-unexpected-multiline': 'warn',
+ 'no-unreachable': 'warn',
+ 'no-unused-expressions': 'warn',
+ 'no-unused-labels': 'warn',
+ 'no-unused-vars': ['warn', {
+ vars: 'local',
+ varsIgnorePattern: '^_',
+ args: 'none'
+ }],
+ 'no-use-before-define': ['warn', 'nofunc'],
+ 'no-useless-computed-key': 'warn',
+ 'no-useless-concat': 'warn',
+ 'no-useless-constructor': 'warn',
+ 'no-useless-escape': 'warn',
+ 'no-useless-rename': ['warn', {
+ ignoreDestructuring: false,
+ ignoreImport: false,
+ ignoreExport: false,
+ }],
+ 'no-with': 'warn',
+ 'no-whitespace-before-property': 'warn',
+ 'operator-assignment': ['warn', 'always'],
+ radix: 'warn',
+ 'require-yield': 'warn',
+ 'rest-spread-spacing': ['warn', 'never'],
+ strict: ['warn', 'never'],
+ 'unicode-bom': ['warn', 'never'],
+ 'use-isnan': 'warn',
+ 'valid-typeof': 'warn',
+
+ // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/
+
+ // TODO: import rules are temporarily disabled because they don't play well
+ // with how eslint-loader only checks the file you change. So if module A
+ // imports module B, and B is missing a default export, the linter will
+ // record this as an issue in module A. Now if you fix module B, the linter
+ // will not be aware that it needs to re-lint A as well, so the error
+ // will stay until the next restart, which is really confusing.
+
+ // This is probably fixable with a patch to eslint-loader.
+ // When file A is saved, we want to invalidate all files that import it
+ // *and* that currently have lint errors. This should fix the problem.
+
+ // 'import/default': 'warn',
+ // 'import/export': 'warn',
+ // 'import/named': 'warn',
+ // 'import/namespace': 'warn',
+ // 'import/no-amd': 'warn',
+ // 'import/no-duplicates': 'warn',
+ // 'import/no-extraneous-dependencies': 'warn',
+ // 'import/no-named-as-default': 'warn',
+ // 'import/no-named-as-default-member': 'warn',
+ // 'import/no-unresolved': ['warn', { commonjs: true }],
+
+ // https://github.com/yannickcr/eslint-plugin-react/tree/master/docs/rules
+ 'react/jsx-equals-spacing': ['warn', 'never'],
+ 'react/jsx-no-duplicate-props': ['warn', { ignoreCase: true }],
+ 'react/jsx-no-undef': 'warn',
+ 'react/jsx-pascal-case': ['warn', {
+ allowAllCaps: true,
+ ignore: [],
+ }],
+ 'react/jsx-uses-react': 'warn',
+ 'react/jsx-uses-vars': 'warn',
+ 'react/no-deprecated': 'warn',
+ 'react/no-direct-mutation-state': 'warn',
+ 'react/no-is-mounted': 'warn',
+ 'react/react-in-jsx-scope': 'warn',
+ 'react/require-render-return': 'warn',
+
+ // https://github.com/evcohen/eslint-plugin-jsx-a11y/tree/master/docs/rules
+ 'jsx-a11y/aria-role': 'warn',
+ 'jsx-a11y/img-has-alt': 'warn',
+ 'jsx-a11y/img-redundant-alt': 'warn',
+ 'jsx-a11y/no-access-key': 'warn',
+
+ // https://github.com/gajus/eslint-plugin-flowtype
+ 'flowtype/define-flow-type': 'warn',
+ 'flowtype/require-valid-file-annotation': 'warn',
+ 'flowtype/use-flow-type': 'warn'
+ }
+};
diff --git a/config/flow/css.js.flow b/config/flow/css.js.flow
new file mode 100644
index 0000000..46e7f7c
--- /dev/null
+++ b/config/flow/css.js.flow
@@ -0,0 +1 @@
+// @flow
diff --git a/config/flow/file.js.flow b/config/flow/file.js.flow
new file mode 100644
index 0000000..701b670
--- /dev/null
+++ b/config/flow/file.js.flow
@@ -0,0 +1,2 @@
+// @flow
+declare export default string;
diff --git a/config/jest/CSSStub.js b/config/jest/CSSStub.js
new file mode 100644
index 0000000..f053ebf
--- /dev/null
+++ b/config/jest/CSSStub.js
@@ -0,0 +1 @@
+module.exports = {};
diff --git a/config/jest/FileStub.js b/config/jest/FileStub.js
new file mode 100644
index 0000000..0a445d0
--- /dev/null
+++ b/config/jest/FileStub.js
@@ -0,0 +1 @@
+module.exports = "test-file-stub";
diff --git a/config/jest/transform.js b/config/jest/transform.js
new file mode 100644
index 0000000..75f893c
--- /dev/null
+++ b/config/jest/transform.js
@@ -0,0 +1,4 @@
+const babelDev = require('../babel.dev');
+const babelJest = require('babel-jest');
+
+module.exports = babelJest.createTransformer(babelDev);
diff --git a/config/paths.js b/config/paths.js
new file mode 100644
index 0000000..4f721ef
--- /dev/null
+++ b/config/paths.js
@@ -0,0 +1,38 @@
+var path = require('path');
+var fs = require('fs');
+
+// Make sure any symlinks in the project folder are resolved:
+// https://github.com/facebookincubator/create-react-app/issues/637
+var appDirectory = fs.realpathSync(process.cwd());
+function resolveApp(relativePath) {
+ return path.resolve(appDirectory, relativePath);
+}
+
+// We support resolving modules according to `NODE_PATH`.
+// This lets you use absolute paths in imports inside large monorepos:
+// https://github.com/facebookincubator/create-react-app/issues/253.
+
+// It works similar to `NODE_PATH` in Node itself:
+// https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders
+
+// We will export `nodePaths` as an array of absolute paths.
+// It will then be used by Webpack configs.
+// Jest doesn’t need this because it already handles `NODE_PATH` out of the box.
+
+var nodePaths = (process.env.NODE_PATH || '')
+ .split(process.platform === 'win32' ? ';' : ':')
+ .filter(Boolean)
+ .map(resolveApp);
+
+// config after eject: we're in ./config/
+module.exports = {
+ appBuild: resolveApp('build'),
+ appHtml: resolveApp('index.html'),
+ appIndexJs: resolveApp('src/index.js'),
+ appPackageJson: resolveApp('package.json'),
+ appSrc: resolveApp('src'),
+ testsSetup: resolveApp('src/setupTests.js'),
+ appNodeModules: resolveApp('node_modules'),
+ ownNodeModules: resolveApp('node_modules'),
+ nodePaths: nodePaths
+};
diff --git a/config/polyfills.js b/config/polyfills.js
new file mode 100644
index 0000000..7e60150
--- /dev/null
+++ b/config/polyfills.js
@@ -0,0 +1,14 @@
+if (typeof Promise === 'undefined') {
+ // Rejection tracking prevents a common issue where React gets into an
+ // inconsistent state due to an error, but it gets swallowed by a Promise,
+ // and the user has no idea what causes React's erratic future behavior.
+ require('promise/lib/rejection-tracking').enable();
+ window.Promise = require('promise/lib/es6-extensions.js');
+}
+
+// fetch() polyfill for making API calls.
+require('whatwg-fetch');
+
+// Object.assign() is commonly used with React.
+// It will use the native implementation if it's present and isn't buggy.
+Object.assign = require('object-assign');
diff --git a/config/webpack.config.dev.js b/config/webpack.config.dev.js
new file mode 100644
index 0000000..87e5859
--- /dev/null
+++ b/config/webpack.config.dev.js
@@ -0,0 +1,214 @@
+var path = require('path');
+var autoprefixer = require('autoprefixer');
+var postcssFlexbugsFixes = require('postcss-flexbugs-fixes');
+var webpack = require('webpack');
+var HtmlWebpackPlugin = require('html-webpack-plugin');
+var ExtractTextPlugin = require("extract-text-webpack-plugin");
+var CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
+var WatchMissingNodeModulesPlugin = require('../scripts/utils/WatchMissingNodeModulesPlugin');
+var CopyWebpackPlugin = require('copy-webpack-plugin');
+var paths = require('./paths');
+var env = require('./env');
+
+var contentful = require('contentful');
+
+// This is the development configuration.
+// It is focused on developer experience and fast rebuilds.
+// The production configuration is different and lives in a separate file.
+module.exports = {
+ // This makes the bundle appear split into separate modules in the devtools.
+ // We don't use source maps here because they can be confusing:
+ // https://github.com/facebookincubator/create-react-app/issues/343#issuecomment-237241875
+ // You may want 'cheap-module-source-map' instead if you prefer source maps.
+ devtool: 'source-map',
+ // These are the "entry points" to our application.
+ // This means they will be the "root" imports that are included in JS bundle.
+ // The first two entry points enable "hot" CSS and auto-refreshes for JS.
+ entry: [
+ // Include WebpackDevServer client. It connects to WebpackDevServer via
+ // sockets and waits for recompile notifications. When WebpackDevServer
+ // recompiles, it sends a message to the client by socket. If only CSS
+ // was changed, the app reload just the CSS. Otherwise, it will refresh.
+ // The "?/" bit at the end tells the client to look for the socket at
+ // the root path, i.e. /sockjs-node/. Otherwise visiting a client-side
+ // route like /todos/42 would make it wrongly request /todos/42/sockjs-node.
+ // The socket server is a part of WebpackDevServer which we are using.
+ // The /sockjs-node/ path I'm referring to is hardcoded in WebpackDevServer.
+ require.resolve('webpack-dev-server/client') + '?/',
+ // Include Webpack hot module replacement runtime. Webpack is pretty
+ // low-level so we need to put all the pieces together. The runtime listens
+ // to the events received by the client above, and applies updates (such as
+ // new CSS) to the running application.
+ require.resolve('webpack/hot/dev-server'),
+ // We ship a few polyfills by default.
+ require.resolve('./polyfills'),
+ // Finally, this is your app's code:
+ paths.appIndexJs
+ // We include the app code last so that if there is a runtime error during
+ // initialization, it doesn't blow up the WebpackDevServer client, and
+ // changing JS code would still trigger a refresh.
+ ],
+ output: {
+ // Next line is not used in dev but WebpackDevServer crashes without it:
+ path: paths.appBuild,
+ // Add /* filename */ comments to generated require()s in the output.
+ pathinfo: true,
+ // This does not produce a real file. It's just the virtual path that is
+ // served by WebpackDevServer in development. This is the JS bundle
+ // containing code from all our entry points, and the Webpack runtime.
+ filename: 'static/js/bundle.js',
+ // In development, we always serve from the root. This makes config easier.
+ publicPath: '/'
+ },
+ resolve: {
+ // This allows you to set a fallback for where Webpack should look for modules.
+ // We read `NODE_PATH` environment variable in `paths.js` and pass paths here.
+ // We use `fallback` instead of `root` because we want `node_modules` to "win"
+ // if there any conflicts. This matches Node resolution mechanism.
+ // https://github.com/facebookincubator/create-react-app/issues/253
+ fallback: paths.nodePaths,
+ // These are the reasonable defaults supported by the Node ecosystem.
+ // We also include JSX as a common component filename extension to support
+ // some tools, although we do not recommend using it, see:
+ // https://github.com/facebookincubator/create-react-app/issues/290
+ extensions: ['.js', '.json', '.jsx', ''],
+ alias: {
+ // Support React Native Web
+ // https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
+ 'react-native': 'react-native-web'
+ }
+ },
+ // Resolve loaders (webpack plugins for CSS, images, transpilation) from the
+ // directory of `react-scripts` itself rather than the project directory.
+ // You can remove this after ejecting.
+ module: {
+ // First, run the linter.
+ // It's important to do this before Babel processes the JS.
+ preLoaders: [
+ {
+ test: /\.(js|jsx)$/,
+ loader: 'eslint',
+ include: paths.appSrc,
+ }
+ ],
+ loaders: [
+ {
+ test: /\.scss$/,
+ include: paths.appSrc,
+
+ // loader: 'style!css!postcss!sass'
+ loader: ExtractTextPlugin.extract('style', '!css!postcss!sass')
+ },
+ // Process JS with Babel.
+ {
+ test: /\.(js|jsx)$/,
+ include: paths.appSrc,
+ loader: 'babel',
+ query: require('./babel.dev')
+ },
+
+ // JSON is not enabled by default in Webpack but both Node and Browserify
+ // allow it implicitly so we also enable it.
+ {
+ test: /\.json$/,
+ loader: 'json'
+ },
+ // "file" loader makes sure those assets get served by WebpackDevServer.
+ // When you `import` an asset, you get its (virtual) filename.
+ // In production, they would get copied to the `build` folder.
+ {
+ test: /\.(ico|jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2)(\?.*)?$/,
+ exclude: /\/favicon.ico$/,
+ loader: 'file',
+ query: {
+ name: 'static/media/[name].[hash:8].[ext]'
+ }
+ },
+ // A special case for favicon.ico to place it into build root directory.
+ {
+ test: /\/favicon.ico$/,
+ include: [paths.appSrc],
+ loader: 'file',
+ query: {
+ name: 'favicon.ico?[hash:8]'
+ }
+ },
+ // "url" loader works just like "file" loader but it also embeds
+ // assets smaller than specified size as data URLs to avoid requests.
+ {
+ test: /\.(mp4|webm|wav|mp3|m4a|aac|oga)(\?.*)?$/,
+ loader: 'url',
+ query: {
+ limit: 10000,
+ name: 'static/media/[name].[hash:8].[ext]'
+ }
+ },
+ // "html" loader is used to process template page (index.html) to resolve
+ // resources linked with HTML tags.
+ {
+ test: /\.html$/,
+ loader: 'html',
+ query: {
+ attrs: ['link:href'],
+ }
+ }
+ ]
+ },
+ // Point ESLint to our predefined config.
+ eslint: {
+ configFile: path.join(__dirname, 'eslint.js'),
+ useEslintrc: false
+ },
+ // We use PostCSS for autoprefixing only.
+ postcss: function() {
+ return [
+ autoprefixer({
+ browsers: [
+ '>1%',
+ 'last 4 versions',
+ 'Firefox ESR',
+ 'not ie < 9', // React doesn't support IE8 anyway
+ ]
+ }),
+ postcssFlexbugsFixes
+ ];
+ },
+ plugins: [
+ new ExtractTextPlugin('app-[hash].css', {
+ allChunks: true
+ }),
+
+ // Generates an `index.html` file with the