├── PULL_REQUEST_TEMPLATE.md
├── README.md
├── .eslintignore
├── .gitattributes
├── src
├── routes
│ ├── HelloWorld
│ │ ├── constants
│ │ │ └── index.js
│ │ ├── controller
│ │ │ ├── action.js
│ │ │ └── reducer.js
│ │ └── index.js
│ ├── StartCoding
│ │ ├── constants
│ │ │ └── index.js
│ │ ├── controller
│ │ │ ├── action.js
│ │ │ └── reducer.js
│ │ └── index.js
│ └── index.js
├── .DS_Store
├── favicon.ico
├── controller
│ ├── history.js
│ ├── initialState.js
│ ├── actions.js
│ ├── middleware
│ │ ├── index.js
│ │ ├── reduxLogger.js
│ │ └── rootReducer.js
│ ├── reducers.js
│ └── store.js
├── components
│ ├── index.js
│ ├── Footer.js
│ ├── LoadingPlaceholder.js
│ ├── Header.js
│ └── Body.js
├── manifest.json
├── index.html
├── layout
│ └── index.js
├── container
│ └── index.js
├── index.js
└── styles
│ └── index.scss
├── .DS_Store
├── lerna.json
├── postcss.config.js
├── .gitignore
├── prettier.config.js
├── globals.js
├── .babelrc
├── setupTests.js
├── tsconfig.json
├── jest.config.js
├── .editorconfig
├── LICENSE
├── typings.d.ts
├── server
├── compiler.js
└── server.js
├── package.json
├── webpack.config.js
├── .stylelintrc
├── tslint.json
└── .eslintrc
/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # React-Redux-Suspense-Lazy-Memo-test
2 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | coverage/**
2 | node_modules/**
3 | dist/**
4 | src/index.html
5 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/src/routes/HelloWorld/constants/index.js:
--------------------------------------------------------------------------------
1 | export const COUNT_ADD = 'HelloWorld/COUNT_ADD';
2 |
--------------------------------------------------------------------------------
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiosBoy/React-Redux-Suspense-Lazy-Memo-test/HEAD/.DS_Store
--------------------------------------------------------------------------------
/src/routes/StartCoding/constants/index.js:
--------------------------------------------------------------------------------
1 | export const COUNT_ADD = 'StartCoding/COUNT_ADD';
2 |
--------------------------------------------------------------------------------
/src/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiosBoy/React-Redux-Suspense-Lazy-Memo-test/HEAD/src/.DS_Store
--------------------------------------------------------------------------------
/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiosBoy/React-Redux-Suspense-Lazy-Memo-test/HEAD/src/favicon.ico
--------------------------------------------------------------------------------
/lerna.json:
--------------------------------------------------------------------------------
1 | {
2 | "lerna": "2.11.0",
3 | "npmClient": "yarn",
4 | "useWorkspaces": false,
5 | "hoist": true
6 | }
7 |
--------------------------------------------------------------------------------
/src/controller/history.js:
--------------------------------------------------------------------------------
1 | import { createBrowserHistory } from 'history';
2 |
3 | const history = createBrowserHistory();
4 |
5 | export default history;
6 |
--------------------------------------------------------------------------------
/src/controller/initialState.js:
--------------------------------------------------------------------------------
1 | const initialState = {
2 | common: {
3 | appName: 'react-suspense'
4 | }
5 | };
6 |
7 | export default initialState;
8 |
--------------------------------------------------------------------------------
/src/controller/actions.js:
--------------------------------------------------------------------------------
1 | import { COUNT_ADD } from '../constants';
2 |
3 | const addCount = count => ({
4 | type: COUNT_ADD,
5 | count
6 | });
7 |
8 | export { addCount };
9 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | 'postcss-import': {},
4 | 'postcss-cssnext': {},
5 | 'postcss-preset-env': {},
6 | 'cssnano': {}
7 | }
8 | };
9 |
--------------------------------------------------------------------------------
/src/controller/middleware/index.js:
--------------------------------------------------------------------------------
1 | import logger from './reduxLogger';
2 | import makeRootReducer, { injectReducer } from './rootReducer';
3 |
4 | export { logger, makeRootReducer, injectReducer };
5 |
--------------------------------------------------------------------------------
/src/routes/HelloWorld/controller/action.js:
--------------------------------------------------------------------------------
1 | import { COUNT_ADD } from '../constants';
2 |
3 | const addCount = count => ({
4 | type: COUNT_ADD,
5 | count
6 | });
7 |
8 | export { addCount };
9 |
--------------------------------------------------------------------------------
/src/routes/StartCoding/controller/action.js:
--------------------------------------------------------------------------------
1 | import { COUNT_ADD } from '../constants';
2 |
3 | const addCount = count => ({
4 | type: COUNT_ADD,
5 | count
6 | });
7 |
8 | export { addCount };
9 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | // put here all file that you need to execlude from pushing on git platform.
2 |
3 | *.log
4 | node_modules
5 | dist
6 | coverage
7 | .idea
8 | package-lock.json
9 | .vscode
10 | .tmp
11 | .src
12 |
--------------------------------------------------------------------------------
/prettier.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | useTabs: false,
3 | printWidth: 120,
4 | tabWidth: 2,
5 | singleQuote: true,
6 | trailingComma: 'none',
7 | jsxBracketSameLine: false,
8 | semi: false
9 | };
10 |
--------------------------------------------------------------------------------
/src/controller/middleware/reduxLogger.js:
--------------------------------------------------------------------------------
1 | import { createLogger } from 'redux-logger';
2 |
3 | const logger = createLogger({
4 | collapsed: true,
5 | timestamp: false,
6 | diff: true
7 | });
8 |
9 | export default logger;
10 |
--------------------------------------------------------------------------------
/src/components/index.js:
--------------------------------------------------------------------------------
1 | import Header from './Header';
2 | import Body from './Body';
3 | import Footer from './Footer';
4 | import LoadingPlaceholder from './LoadingPlaceholder';
5 |
6 | export { Header, Body, Footer, LoadingPlaceholder };
7 |
--------------------------------------------------------------------------------
/src/components/Footer.js:
--------------------------------------------------------------------------------
1 | import React, { memo } from 'react';
2 | import styles from '../styles/index.scss';
3 |
4 | const Footer = () => {
5 | return
App Footer
;
6 | };
7 |
8 | export default memo(Footer);
9 |
--------------------------------------------------------------------------------
/globals.js:
--------------------------------------------------------------------------------
1 | // global variables for webpack and app hot-reload. Make them work more easly.
2 | global.__TEST__ = process.env.NODE_ENV === 'test';
3 | global.__DEV__ = process.env.NODE_ENV === 'development';
4 | global.__PROD__ = process.env.NODE_ENV === 'production';
5 | global.__NODE_ENV__ = process.env.NODE_ENV;
6 | global.__PORT__ = process.env.PORT;
7 |
--------------------------------------------------------------------------------
/src/components/LoadingPlaceholder.js:
--------------------------------------------------------------------------------
1 | import React, { memo } from 'react';
2 | import styles from '../styles/index.scss';
3 |
4 | const LoadingPlaceholder = () => {
5 | return (
6 |
7 | Loading...
8 |
9 | );
10 | };
11 |
12 | export default memo(LoadingPlaceholder);
13 |
--------------------------------------------------------------------------------
/src/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "Templater",
3 | "name": "Webpack4-React17 Templater",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": "./index.html",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | ["@babel/env", {
4 | "targets": {
5 | "browsers": ["last 2 versions"]
6 | }
7 | }],
8 | "@babel/react",
9 | "@babel/typescript"
10 | ],
11 | "plugins": [
12 | "@babel/plugin-proposal-class-properties",
13 | "@babel/plugin-syntax-dynamic-import",
14 | ["@babel/plugin-transform-async-to-generator", {
15 | "module": "bluebird",
16 | "method": "coroutine"
17 | }]
18 | ]
19 | }
20 |
--------------------------------------------------------------------------------
/src/components/Header.js:
--------------------------------------------------------------------------------
1 | import React, { Fragment, memo } from 'react';
2 | import { Link } from 'react-router-dom';
3 | import styles from '../styles/index.scss';
4 |
5 | const Header = () => {
6 | return (
7 |
8 |
9 |
10 | Home
11 | Next
12 |
13 |
App Headers
14 |
15 |
16 | );
17 | };
18 |
19 | export default memo(Header);
20 |
--------------------------------------------------------------------------------
/setupTests.js:
--------------------------------------------------------------------------------
1 | // TODO: Remove these polyfills once the below issue is solved.
2 | // It present here to allow Jest work with the last React environment.
3 | // https://github.com/facebookincubator/create-react-app/issues/3199#issuecomment-332842582
4 | global.requestAnimationFrame = cb => {
5 | setTimeout(cb, 0);
6 | };
7 |
8 | global.matchMedia = window.matchMedia || function() {
9 | return {
10 | matches: false,
11 | addListener: () => {},
12 | removeListener: () => {}
13 | };
14 | };
15 |
16 | import Enzyme from 'enzyme';
17 | import Adapter from 'enzyme-adapter-react-16';
18 |
19 | Enzyme.configure({ adapter: new Adapter() });
20 |
--------------------------------------------------------------------------------
/src/controller/reducers.js:
--------------------------------------------------------------------------------
1 | import { LOCATION_CHANGE } from 'connected-react-router';
2 | import initialState from './initialState';
3 |
4 | // ------------------------------------
5 | // Action Handlers
6 | // ------------------------------------
7 | const ACTION_HANDLERS = {
8 | [LOCATION_CHANGE]: (state, action) => ({
9 | ...state,
10 | locationChange: action.payload.location.pathname
11 | })
12 | };
13 |
14 | // ------------------------------------
15 | // Reducer
16 | // ------------------------------------
17 | const reducer = (state = initialState, action) => {
18 | const handler = ACTION_HANDLERS[action.type];
19 |
20 | return handler ? handler(state, action) : state;
21 | };
22 |
23 | export default reducer;
24 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "noUnusedLocals": true,
4 | "noUnusedParameters": true,
5 | "allowSyntheticDefaultImports": true,
6 | "esModuleInterop": true,
7 | "allowJs": true,
8 | "checkJs": false,
9 | "module": "esnext",
10 | "target": "es5",
11 | "jsx": "react",
12 | "moduleResolution": "node",
13 | "lib": ["es6", "dom"]
14 | },
15 | "typeAcquisition": {
16 | "enable": true
17 | },
18 | "typeRoots": [
19 | "./typings.d.ts",
20 | "./node_modules/@types"
21 | ],
22 | "include": [
23 | ".src/.ts",
24 | "src/**/*",
25 | "./typings.d.ts"
26 | ],
27 | "exclude": [
28 | "node_modules",
29 | "**/*.test.ts",
30 | "server",
31 | "dist"
32 | ]
33 | }
34 |
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Suspense + lazy React 16.7 Testing stent
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | // Jest tesitng config. Responce for app tests.
2 | module.exports = {
3 | cacheDirectory: '/.tmp/jest',
4 | coverageDirectory: './.tmp/coverage',
5 | moduleNameMapper: {
6 | '^.+\\.(scss)$': 'identity-obj-proxy'
7 | },
8 | modulePaths: [''],
9 | moduleFileExtensions: ['js', 'jsx', 'json'],
10 | globals: {
11 | NODE_ENV: 'test'
12 | },
13 | verbose: true,
14 | testRegex: '(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$',
15 | testPathIgnorePatterns: ['/node_modules/', '/__tests__/mocks/.*'],
16 | transformIgnorePatterns: ['.*(node_modules)(?!.*torn.*).*$'],
17 | transform: {
18 | '^.+\\.js$': 'babel-jest'
19 | },
20 | setupFiles: ['/setupTests.js'],
21 | snapshotSerializers: ['enzyme-to-json/serializer']
22 | };
23 |
--------------------------------------------------------------------------------
/src/routes/StartCoding/controller/reducer.js:
--------------------------------------------------------------------------------
1 | import { COUNT_ADD } from '../constants';
2 |
3 | // ------------------------------------
4 | // Action Handlers
5 | // ------------------------------------
6 | const ACTION_HANDLERS = {
7 | [COUNT_ADD]: (state, action) => ({
8 | ...state,
9 | count: action.count,
10 | countDoubl: action.count % 2 === 0 ? action.count : state.countDoubl
11 | })
12 | };
13 |
14 | const initialState = {
15 | count: 5,
16 | countDoubl: 2
17 | };
18 |
19 | // ------------------------------------
20 | // Reducer
21 | // ------------------------------------
22 | const reducer = (state = initialState, action) => {
23 | const handler = ACTION_HANDLERS[action.type];
24 |
25 | return handler ? handler(state, action) : state;
26 | };
27 |
28 | export default reducer;
29 |
--------------------------------------------------------------------------------
/src/routes/index.js:
--------------------------------------------------------------------------------
1 | import React, { lazy } from 'react';
2 | import { injectReducer } from '../controller/middleware';
3 | import rootStore from '../controller/store';
4 |
5 | const HelloWorld = lazy(() => import(/* webpackChunkName: "HelloWorld" */ './HelloWorld'));
6 | const StartCoding = lazy(() => import(/* webpackChunkName: "StartCoding" */ './StartCoding'));
7 |
8 | const Components = {
9 | HelloWorld,
10 | StartCoding
11 | };
12 |
13 | const AsyncComponent = props => {
14 | const { componentName } = props;
15 |
16 | import(`./${componentName}/controller/reducer`).then(({ default: reducer }) => {
17 | injectReducer(rootStore, { key: componentName, reducer });
18 | });
19 |
20 | const Component = Components[componentName];
21 |
22 | return ;
23 | };
24 |
25 | export default AsyncComponent;
26 |
--------------------------------------------------------------------------------
/src/routes/HelloWorld/controller/reducer.js:
--------------------------------------------------------------------------------
1 | import { COUNT_ADD } from '../constants';
2 |
3 | // ------------------------------------
4 | // Action Handlers
5 | // ------------------------------------
6 | const ACTION_HANDLERS = {
7 | [COUNT_ADD]: (state, action) => ({
8 | ...state,
9 | count: action.count,
10 | countDoubl: action.count % 2 === 0 ? action.count : state.countDoubl
11 | })
12 | };
13 |
14 | const initialState = {
15 | count: 5,
16 | countDoubl: 2
17 | };
18 |
19 | // ------------------------------------
20 | // Reducer
21 | // ------------------------------------
22 | const reducer = (state = initialState, action) => {
23 | const handler = ACTION_HANDLERS[action.type];
24 |
25 | // console.log(state, action)
26 | return handler ? handler(state, action) : state;
27 | };
28 |
29 | export default reducer;
30 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org
2 |
3 | # A special property that should be specified at the top of the file outside of
4 | # any sections. Set to true to stop .editor config file search on current file
5 | root = true
6 |
7 | [*]
8 | # Indentation style
9 | # Possible values - tab, space
10 | indent_style = space
11 |
12 | # Indentation size in single-spaced characters
13 | # Possible values - an integer, tab
14 | indent_size = 2
15 |
16 | # Line ending file format
17 | # Possible values - lf, crlf, cr
18 | end_of_line = lf
19 |
20 | # File character encoding
21 | # Possible values - latin1, utf-8, utf-16be, utf-16le
22 | charset = utf-8
23 |
24 | # Denotes whether to trim whitespace at the end of lines
25 | # Possible values - true, false
26 | trim_trailing_whitespace = true
27 |
28 | # Denotes whether file should end with a newline
29 | # Possible values - true, false
30 | insert_final_newline = true
31 |
--------------------------------------------------------------------------------
/src/controller/middleware/rootReducer.js:
--------------------------------------------------------------------------------
1 | import { combineReducers } from 'redux';
2 | import { connectRouter } from 'connected-react-router';
3 | import { createResponsiveStateReducer } from 'redux-responsive';
4 | import common from '../reducers';
5 | import history from '../history';
6 |
7 | const makeRootReducer = asyncReducers => {
8 | return combineReducers({
9 | ...asyncReducers,
10 | common,
11 | // routing
12 | router: connectRouter(history),
13 | browser: createResponsiveStateReducer({
14 | mobile: 600,
15 | tablet: 1000,
16 | desktop: 5000
17 | })
18 | });
19 | };
20 |
21 | export const injectReducer = (store, { key, reducer }) => {
22 | if (Object.hasOwnProperty.call(store.asyncReducers, key)) return;
23 | store.asyncReducers[key] = reducer;
24 |
25 | store.replaceReducer(makeRootReducer(store.asyncReducers));
26 | };
27 |
28 | export default makeRootReducer;
29 |
--------------------------------------------------------------------------------
/src/controller/store.js:
--------------------------------------------------------------------------------
1 | import { applyMiddleware, compose, createStore } from 'redux';
2 | import { routerMiddleware } from 'connected-react-router';
3 |
4 | import { logger } from './middleware';
5 | import makeRootReducer from './middleware/rootReducer';
6 | import initialState from './initialState';
7 | import history from './history';
8 |
9 | const rootStore = () => {
10 | const middleware = [routerMiddleware(history), logger];
11 | const enhancers = [];
12 |
13 | if (__DEV__ && window.__REDUX_DEVTOOLS_EXTENSION__) {
14 | enhancers.push(window.__REDUX_DEVTOOLS_EXTENSION__());
15 | }
16 |
17 | // ======================================================
18 | // Store Instantiation and HMR Setup
19 | // ======================================================
20 | const store = createStore(
21 | makeRootReducer(),
22 | initialState,
23 | compose(
24 | applyMiddleware(...middleware),
25 | ...enhancers
26 | )
27 | );
28 |
29 | store.asyncReducers = {};
30 |
31 | return store;
32 | };
33 |
34 | export default rootStore();
35 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 sviatoslav
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/typings.d.ts:
--------------------------------------------------------------------------------
1 | interface Window {
2 | __REDUX_DEVTOOLS_EXTENSION_COMPOSE__: any;
3 | __REDUX_DEVTOOLS_EXTENSION__: any;
4 | }
5 |
6 | declare const __DEV__: string;
7 | declare const __PROD__: string;
8 | declare const __TEST__: string;
9 |
10 | declare module '*.json' {
11 | interface IClassNames {
12 | [className: string]: string
13 | }
14 | const classNames: IClassNames;
15 | export = classNames;
16 | }
17 |
18 | declare module '*.css' {
19 | interface IClassNames {
20 | [className: string]: string
21 | }
22 | const classNames: IClassNames;
23 | export = classNames;
24 | }
25 |
26 | declare module '*.scss' {
27 | interface IClassNames {
28 | [className: string]: string
29 | }
30 | const classNames: IClassNames;
31 | export = classNames;
32 | }
33 |
34 | declare module '*.cssmodule.scss' {
35 | interface IClassNames {
36 | [className: string]: string
37 | }
38 | const classNames: IClassNames;
39 | export = classNames;
40 | }
41 |
42 | declare module '*.svg' {
43 | interface IClassNames {
44 | [className: string]: string
45 | }
46 | const classNames: IClassNames;
47 | export = classNames;
48 | }
49 |
--------------------------------------------------------------------------------
/src/components/Body.js:
--------------------------------------------------------------------------------
1 | import { PropTypes } from 'prop-types';
2 | import React, { Fragment, PureComponent } from 'react';
3 |
4 | class Body extends PureComponent {
5 | _handleClick = () => {
6 | const { onclick } = this.props;
7 |
8 | onclick();
9 | }
10 |
11 | render() {
12 | const { buttonClass, descriptionClass, title, description, count } = this.props;
13 |
14 | return (
15 |
16 |
20 | {description}
21 |
22 | );
23 | }
24 | }
25 |
26 | Body.propTypes = {
27 | buttonClass: PropTypes.string,
28 | descriptionClass: PropTypes.string,
29 | onclick: PropTypes.func,
30 | title: PropTypes.string,
31 | description: PropTypes.string,
32 | count: PropTypes.number
33 | };
34 |
35 | Body.defaultProps = {
36 | buttonClass: '',
37 | descriptionClass: '',
38 | onclick: () => {},
39 | title: '',
40 | description: '',
41 | count: 0
42 | };
43 |
44 | export default Body;
45 |
--------------------------------------------------------------------------------
/src/layout/index.js:
--------------------------------------------------------------------------------
1 | import { PropTypes } from 'prop-types';
2 | import React, { Component } from 'react';
3 | import { connect } from 'react-redux';
4 | import { withRouter } from 'react-router-dom';
5 | import { Header, Footer } from '../components';
6 | import styles from '../styles/index.scss';
7 |
8 | class AppLayout extends Component {
9 | render() {
10 | const { countDoubl, children } = this.props;
11 | console.log(this.props.state.router)
12 |
13 | return (
14 |
15 |
16 | {children}
17 |
18 |
19 | );
20 | }
21 | }
22 |
23 | AppLayout.propTypes = {
24 | children: PropTypes.node.isRequired,
25 | count: PropTypes.number,
26 | countDoubl: PropTypes.number,
27 | startAddCount: PropTypes.func
28 | };
29 |
30 | AppLayout.defaultProps = {
31 | count: 0,
32 | countDoubl: 0,
33 | startAddCount: () => {}
34 | };
35 |
36 | const mapStateToProps = state => ({
37 | state,
38 | count: state.count,
39 | countDoubl: state.countDoubl
40 | });
41 |
42 | export default withRouter(
43 | connect(
44 | mapStateToProps,
45 | null
46 | )(AppLayout)
47 | );
48 |
--------------------------------------------------------------------------------
/src/container/index.js:
--------------------------------------------------------------------------------
1 | import { PropTypes } from 'prop-types';
2 | import React, { Suspense } from 'react';
3 | import { Provider } from 'react-redux';
4 | import { HashRouter, Switch, Route } from 'react-router-dom';
5 | import { ConnectedRouter } from 'connected-react-router';
6 |
7 | import AppLayout from '../layout';
8 | import AsyncComponent from '../routes';
9 | import { LoadingPlaceholder } from '../components';
10 |
11 | const AppContainer = ({ store, history }) => {
12 | return (
13 |
14 |
15 |
16 |
17 | }>
18 |
19 | } />
20 | } />
21 |
22 |
23 |
24 |
25 |
26 |
27 | );
28 | };
29 |
30 | AppContainer.propTypes = {
31 | store: PropTypes.object.isRequired,
32 | history: PropTypes.object.isRequired
33 | };
34 |
35 | export default AppContainer;
36 |
--------------------------------------------------------------------------------
/server/compiler.js:
--------------------------------------------------------------------------------
1 | // import global vars for a whole app
2 | require('../globals');
3 |
4 | const debug = require('debug')('app:build:webpack-compiler');
5 | const webpack = require('webpack');
6 | const webpackConfig = require('../webpack.config.js');
7 |
8 | // -----------------------------
9 | // STARTING APP COMPILATION PROCESS
10 | // -----------------------------
11 | function webpackCompiler() {
12 | return new Promise((resolve, reject) => {
13 | const compiler = webpack(webpackConfig);
14 |
15 | compiler.run((err, stats) => {
16 | if (err) {
17 | debug('Webpack compiler encountered a fatal error.', err);
18 |
19 | return reject(err);
20 | }
21 |
22 | const jsonStats = stats.toJson();
23 |
24 | debug('Webpack compilation is completed.');
25 |
26 | resolve(jsonStats);
27 | });
28 | });
29 | }
30 |
31 | // -----------------------------
32 | // READING WEBPACK CONFIGURATION
33 | // -----------------------------
34 | const compile = () => {
35 | debug('Starting compiler.');
36 |
37 | return Promise.resolve()
38 | .then(() => webpackCompiler(webpackConfig))
39 | .then(() => {
40 | debug('Compilation completed successfully.');
41 | })
42 | .catch(err => {
43 | debug('Compiler encountered an error.', err);
44 |
45 | process.exit(1);
46 | });
47 | };
48 |
49 | compile();
50 |
--------------------------------------------------------------------------------
/src/routes/HelloWorld/index.js:
--------------------------------------------------------------------------------
1 | import { PropTypes } from 'prop-types';
2 | import React, { PureComponent } from 'react';
3 | import { connect } from 'react-redux';
4 | import { addCount } from './controller/action';
5 | import { Body } from '../../components';
6 | import styles from '../../styles/index.scss';
7 |
8 | class HelloWorld extends PureComponent {
9 | _addCount = () => {
10 | const { count, startAddCount } = this.props;
11 |
12 | startAddCount(count + 1);
13 | }
14 |
15 | render() {
16 | const { countDoubl } = this.props;
17 |
18 | return (
19 |
27 | );
28 | }
29 | }
30 |
31 | HelloWorld.propTypes = {
32 | count: PropTypes.number,
33 | countDoubl: PropTypes.number,
34 | startAddCount: PropTypes.func
35 | };
36 |
37 | HelloWorld.defaultProps = {
38 | count: 0,
39 | countDoubl: 0,
40 | startAddCount: () => {}
41 | };
42 |
43 | const mapStateToProps = state => ({
44 | count: state.HelloWorld.count,
45 | countDoubl: state.HelloWorld.countDoubl
46 | });
47 |
48 | const mapDispatchToProps = dispatch => ({
49 | startAddCount: value => dispatch(addCount(value))
50 | });
51 |
52 | export default connect(
53 | mapStateToProps,
54 | mapDispatchToProps
55 | )(HelloWorld);
56 |
--------------------------------------------------------------------------------
/src/routes/StartCoding/index.js:
--------------------------------------------------------------------------------
1 | import { PropTypes } from 'prop-types';
2 | import React, { PureComponent } from 'react';
3 | import { connect } from 'react-redux';
4 | import { addCount } from './controller/action';
5 | import { Body } from '../../components';
6 | import styles from '../../styles/index.scss';
7 |
8 | class StartCoding extends PureComponent {
9 | _addCount = () => {
10 | const { count, startAddCount } = this.props;
11 |
12 | startAddCount(count + 1);
13 | }
14 |
15 | render() {
16 | const { countDoubl } = this.props;
17 |
18 | return (
19 |
27 | );
28 | }
29 | }
30 |
31 | StartCoding.propTypes = {
32 | count: PropTypes.number,
33 | countDoubl: PropTypes.number,
34 | startAddCount: PropTypes.func
35 | };
36 |
37 | StartCoding.defaultProps = {
38 | count: 0,
39 | countDoubl: 0,
40 | startAddCount: () => {}
41 | };
42 |
43 | const mapStateToProps = state => ({
44 | count: state.StartCoding.count,
45 | countDoubl: state.StartCoding.countDoubl
46 | });
47 |
48 | const mapDispatchToProps = dispatch => ({
49 | startAddCount: value => dispatch(addCount(value))
50 | });
51 |
52 | export default connect(
53 | mapStateToProps,
54 | mapDispatchToProps
55 | )(StartCoding);
56 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import RedBox from 'redbox-react';
4 | import AppContainer from './container';
5 | import store from './controller/store';
6 | import history from './controller/history';
7 |
8 | const ENTRY_POINT = document.querySelector('#react-app-root');
9 |
10 | // creating starting endpoint for app.
11 | const render = () => {
12 | ReactDOM.render(, ENTRY_POINT);
13 | };
14 |
15 | // this will help us understand where the problem is located once app will fall.
16 | const renderError = error => {
17 | ReactDOM.render(, ENTRY_POINT);
18 | };
19 |
20 | // This code is excluded from production bundle
21 | if (__DEV__) {
22 | window.state = store;
23 | // ========================================================
24 | // DEVELOPMENT STAGE! HOT MODULE REPLACE ACTIVATION!
25 | // ========================================================
26 | const devRender = () => {
27 | if (module.hot) {
28 | module.hot.accept('./container/index.js', () => render());
29 | }
30 |
31 | render();
32 | };
33 |
34 | // Wrap render in try/catch
35 | try {
36 | devRender();
37 | } catch (error) {
38 | console.error(error);
39 | renderError(error);
40 | }
41 | } else {
42 | // ========================================================
43 | // PRODUCTION GO!
44 | // ========================================================
45 | render();
46 | }
47 |
--------------------------------------------------------------------------------
/server/server.js:
--------------------------------------------------------------------------------
1 | // import global vars for a whole app
2 | require('../globals');
3 |
4 | const path = require('path');
5 | const browserSync = require('browser-sync');
6 | const historyApiFallback = require('connect-history-api-fallback');
7 | const webpack = require('webpack');
8 | const webpackDevMiddleware = require('webpack-dev-middleware');
9 | const webpackHotMiddleware = require('webpack-hot-middleware');
10 | const webpackConfig = require('../webpack.config.js');
11 | const bundler = webpack(webpackConfig);
12 |
13 | // ========================================================
14 | // WEBPACK MIDDLEWARE CONFIGURATION
15 | // ========================================================
16 | const devMiddlewareOptions = {
17 | publicPath: webpackConfig.output.publicPath,
18 | hot: true,
19 | headers: { 'Access-Control-Allow-Origin': '*' }
20 | };
21 |
22 | // ========================================================
23 | // Server Configuration
24 | // ========================================================
25 | browserSync({
26 | open: false,
27 | ghostMode: {
28 | clicks: false,
29 | forms: false,
30 | scroll: true
31 | },
32 | server: {
33 | baseDir: path.resolve(__dirname, '../src'),
34 | middleware: [
35 | historyApiFallback(),
36 | webpackDevMiddleware(bundler, devMiddlewareOptions),
37 | webpackHotMiddleware(bundler)
38 | ]
39 | },
40 | files: [
41 | 'src/../*.tsx',
42 | 'src/../*.ts',
43 | 'src/../*.jsx',
44 | 'src/../*.js',
45 | 'src/../*.json',
46 | 'src/../*.scss',
47 | 'src/../*.html'
48 | ]
49 | });
50 |
--------------------------------------------------------------------------------
/src/styles/index.scss:
--------------------------------------------------------------------------------
1 | .appWrapper {
2 | display: flex;
3 | flex-direction: column;
4 | align-items: center;
5 | justify-content: center;
6 | width: 100%;
7 | height: auto;
8 | outline: none;
9 | }
10 |
11 | .extra {
12 | display: flex;
13 | align-items: center;
14 | justify-content: center;
15 | width: 100%;
16 | height: 25vh;
17 | font-size: 25px;
18 | text-align: center;
19 | }
20 |
21 | .appHeader {
22 | composes: extra;
23 | color: wheat;
24 | background: green;
25 | height: 15vh;
26 | font-size: 15px;
27 | position: relative;
28 |
29 | .buttonsContainer {
30 | position: absolute;
31 | left: 0;
32 | }
33 |
34 | a {
35 | margin: 5px;
36 | color: black;
37 | }
38 | }
39 |
40 | .helloWorld {
41 | composes: extra;
42 | background: linear-gradient(#e66465, #9198e5);
43 | color: white;
44 |
45 | span {
46 | &:first-of-type {
47 | cursor: pointer;
48 | user-select: none;
49 | background: #1ea247;
50 | border: 3px solid #45ca24;
51 | border-radius: 12px;
52 | padding: 8px;
53 | margin: 5px;
54 | box-shadow: 0 5px 15px #000;
55 | }
56 | }
57 | }
58 |
59 | .helloStart {
60 | composes: extra;
61 | background: linear-gradient(#9198e5, #e66465 );
62 | color: white;
63 | }
64 |
65 | .appFooter {
66 | composes: extra;
67 | background: yellow;
68 | height: 15vh;
69 | font-size: 15px;
70 | }
71 |
72 | .loadingPlaceholder {
73 | width: 100%;
74 | height: 50vh;
75 | display: flex;
76 | flex-direction: row;
77 | justify-content: center;
78 | align-items: center;
79 | top: 0;
80 | left: 0;
81 | background: black;
82 |
83 | span {
84 | font-size: 50px;
85 | color: white;
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "webpack4react17StarterKit",
3 | "version": "1.0.0",
4 | "description": "test stend to show how easy we can make code-splitting by in-box features in React 16.7 - Suspense and lazy.",
5 | "main": "index.js",
6 | "author": "Sviat Kuzhelev",
7 | "license": "MIT",
8 | "husky": {
9 | "hooks": {
10 | "pre-commit": "lint-staged"
11 | }
12 | },
13 | "lint-staged": {
14 | "*.json": [
15 | "jsonlint --formatter=verbose",
16 | "git add"
17 | ],
18 | "*.@(css|scss)": [
19 | "stylelint --fix --formatter=verbose",
20 | "git add"
21 | ],
22 | "*.cssmodule": [
23 | "stylelint --fix --syntax scss --formatter=verbose",
24 | "git add"
25 | ],
26 | "*.@(js|jsx)": [
27 | "prettier --write",
28 | "eslint --fix --quiet",
29 | "git add",
30 | "jest --bail --findRelatedTests"
31 | ],
32 | "*.@(ts|tsx)": [
33 | "prettier --write --parser typescript",
34 | "tslint --config tslint.json",
35 | "git add",
36 | "jest --bail --findRelatedTests"
37 | ]
38 | },
39 | "scripts": {
40 | "start:dev": "better-npm-run start:dev",
41 | "start:prod": "better-npm-run start:prod",
42 | "test": "better-npm-run test",
43 | "clean": "rimraf dist",
44 | "push": "npm run lint && git push",
45 | "compile": "better-npm-run compile",
46 | "lint": "prettier --single-quote --no-semi --print-width 120 --write '{src,tests}/**/*.js'",
47 | "eslint": "eslint --quiet ../../.eslintrc",
48 | "csslint": "stylelint **/*.scss --config ../../.stylelintrc"
49 | },
50 | "betterScripts": {
51 | "compile": {
52 | "command": "node server/compiler",
53 | "env": {
54 | "NODE_ENV": "production",
55 | "DEBUG": "app:*"
56 | }
57 | },
58 | "start:dev": {
59 | "command": "node server/server",
60 | "env": {
61 | "NODE_ENV": "development",
62 | "DEBUG": "app:*"
63 | }
64 | },
65 | "start:prod": {
66 | "command": "node server/server",
67 | "env": {
68 | "NODE_ENV": "production",
69 | "DEBUG": "app:*"
70 | }
71 | },
72 | "test": {
73 | "command": "node server/server",
74 | "env": {
75 | "NODE_ENV": "test",
76 | "DEBUG": "app:*"
77 | }
78 | }
79 | },
80 | "repository": {
81 | "type": "git"
82 | },
83 | "devDependencies": {
84 | "@types/classnames": "^2.2.6",
85 | "@types/enzyme": "^3.1.14",
86 | "@types/enzyme-adapter-react-16": "^1.0.3",
87 | "@types/jest": "^23.3.9",
88 | "@types/lodash": "^4.14.117",
89 | "@types/node": "^10.12.1",
90 | "@types/prop-types": "^15.5.6",
91 | "@types/react-dom": "^16.0.9",
92 | "@types/react-redux": "^6.0.9",
93 | "@types/webpack": "^4.4.17",
94 | "@types/webpack-dev-middleware": "^2.0.2",
95 | "@types/webpack-env": "^1.13.6",
96 | "@types/webpack-hot-middleware": "^2.16.4",
97 | "autoprefixer": "^9.3.1",
98 | "babel-eslint": "^10.0.1",
99 | "better-npm-run": "^0.1.1",
100 | "classnames": "^2.2.6",
101 | "css-loader": "^1.0.1",
102 | "cssnano": "^4.1.7",
103 | "enzyme": "^3.7.0",
104 | "enzyme-to-json": "^3.3.4",
105 | "eslint": "^5.8.0",
106 | "eslint-config-airbnb": "^17.1.0",
107 | "eslint-plugin-babel": "^5.0.0",
108 | "eslint-plugin-import": "^2.11.0",
109 | "eslint-plugin-jest": "^21.22.0",
110 | "eslint-plugin-jsx-a11y": "^6.1.1",
111 | "eslint-plugin-promise": "^3.4.0",
112 | "eslint-plugin-react": "^7.11.1",
113 | "eslint-plugin-react-hooks": "^0.0.0",
114 | "husky": "^1.1.2",
115 | "jsonlint": "^1.6.3",
116 | "lerna": "^2.11.0",
117 | "lint-staged": "^8.0.3",
118 | "node-sass": "^4.9.4",
119 | "postcss-cssnext": "^3.1.0",
120 | "postcss-import": "^12.0.1",
121 | "postcss-loader": "^3.0.0",
122 | "postcss-preset-env": "^6.3.0",
123 | "postcss-scss": "^2.0.0",
124 | "precss": "^3.1.2",
125 | "prettier": "^1.14.3",
126 | "redbox-react": "^1.6.0",
127 | "redux-responsive": "^4.3.8",
128 | "sass-loader": "^7.1.0",
129 | "style-loader": "^0.23.1",
130 | "stylelint": "^9.7.1",
131 | "stylelint-config-sass-guidelines": "^5.2.0",
132 | "stylelint-config-standard": "^18.2.0",
133 | "stylelint-no-unsupported-browser-features": "^3.0.1",
134 | "stylelint-order": "^1.0.0",
135 | "stylelint-scss": "^3.3.0",
136 | "tslint": "^5.11.0",
137 | "url-loader": "^1.1.2",
138 | "webpack-bundle-analyzer": "^3.0.3"
139 | },
140 | "dependencies": {
141 | "@babel/core": "^7.1.5",
142 | "@babel/plugin-proposal-class-properties": "^7.1.0",
143 | "@babel/plugin-syntax-dynamic-import": "^7.0.0",
144 | "@babel/plugin-transform-async-to-generator": "^7.1.0",
145 | "@babel/polyfill": "^7.0.0",
146 | "@babel/preset-env": "^7.1.0",
147 | "@babel/preset-react": "^7.0.0",
148 | "@babel/preset-stage-3": "^7.0.0",
149 | "@babel/preset-typescript": "^7.1.0",
150 | "babel": "^6.23.0",
151 | "babel-loader": "^8.0.4",
152 | "babel-plugin-transform-runtime": "^6.23.0",
153 | "babel-polyfill": "^6.26.0",
154 | "babel-preset-es2015": "^6.24.1",
155 | "babel-preset-stage-0": "^6.24.1",
156 | "browser-sync": "^2.26.3",
157 | "browser-sync-webpack-plugin": "^2.2.2",
158 | "clean-webpack-plugin": "^0.1.19",
159 | "connect-history-api-fallback": "^1.5.0",
160 | "connected-react-router": "^5.0.1",
161 | "debug": "^4.1.0",
162 | "history": "^4.7.2",
163 | "html-loader": "^0.5.5",
164 | "html-webpack-plugin": "^3.2.0",
165 | "mini-css-extract-plugin": "^0.4.1",
166 | "optimize-css-assets-webpack-plugin": "^5.0.1",
167 | "path": "^0.12.7",
168 | "prop-types": "^15.6.0",
169 | "react": "^16.7.0-alpha.0",
170 | "react-dom": "^16.7.0-alpha.0",
171 | "react-redux": "^5.1.1",
172 | "react-router": "^4.3.1",
173 | "react-router-dom": "^4.3.1",
174 | "redux": "^4.0.1",
175 | "redux-logger": "^3.0.6",
176 | "regenerator-runtime": "^0.12.1",
177 | "uglifyjs-webpack-plugin": "^1.2.7",
178 | "webpack": "^4.23.1",
179 | "webpack-cli": "^3.1.2",
180 | "webpack-dev-middleware": "^3.4.0",
181 | "webpack-dev-server": "^3.1.10",
182 | "webpack-hot-middleware": "^2.24.3"
183 | }
184 | }
185 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 |
2 | // import global vars for a whole app
3 | require('./globals');
4 |
5 | const path = require('path');
6 | const webpack = require('webpack');
7 | const HtmlWebpackPlugin = require('html-webpack-plugin');
8 | const MiniCssExtractPlugin = require('mini-css-extract-plugin');
9 | const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
10 | const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
11 | const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
12 | const debug = require('debug')('app:webpack:config');
13 |
14 | // ------------------------------------
15 | // RULES INJECTION!
16 | // ------------------------------------
17 | const rules = [
18 | // JAVASCRIPT/JSON
19 | {
20 | test: /\.(js|jsx|ts|tsx)?$/,
21 | use: ['babel-loader']
22 | },
23 | {
24 | type: 'javascript/auto',
25 | test: /\.json$/,
26 | loader: 'json-loader'
27 | },
28 | // STYLES
29 | {
30 | test: /.scss$/,
31 | use: [
32 | __PROD__ ? MiniCssExtractPlugin.loader : 'style-loader',
33 | 'css-loader?modules&importLoaders=1&localIdentName=[local]___[hash:base64:5]',
34 | { loader: 'postcss-loader' },
35 | 'sass-loader'
36 | ]
37 | },
38 | // FILE/IMAGES
39 | {
40 | test: /\.woff(\?.*)?$/,
41 | loader: 'url-loader?prefix=fonts/&name=[path][name].[ext]&limit=10000&mimetype=application/font-woff'
42 | },
43 | {
44 | test: /\.woff2(\?.*)?$/,
45 | loader: 'url-loader?prefix=fonts/&name=[path][name].[ext]&limit=10000&mimetype=application/font-woff2'
46 | },
47 | {
48 | test: /\.otf(\?.*)?$/,
49 | loader: 'file-loader?prefix=fonts/&name=[path][name].[ext]&limit=10000&mimetype=font/opentype'
50 | },
51 | {
52 | test: /\.ttf(\?.*)?$/,
53 | loader: 'url-loader?prefix=fonts/&name=[path][name].[ext]&limit=10000&mimetype=application/octet-stream'
54 | },
55 | {
56 | test: /\.eot(\?.*)?$/,
57 | loader: 'file-loader?prefix=fonts/&name=[path][name].[ext]'
58 | },
59 | {
60 | test: /\.svg(\?.*)?$/,
61 | loader: 'url-loader?prefix=fonts/&name=[path][name].[ext]&limit=10000&mimetype=image/svg+xml'
62 | },
63 | {
64 | test: /\.(png|jpg)$/,
65 | loader: 'url-loader?limit=8192'
66 | }
67 | ];
68 |
69 | // ------------------------------------
70 | // BUNDLES OPTIMIZATION
71 | // ------------------------------------
72 | const optimization = {
73 | optimization: {
74 | splitChunks: {
75 | chunks: 'all',
76 | minChunks: 2
77 | },
78 | minimizer: [
79 | new UglifyJsPlugin({
80 | uglifyOptions: {
81 | compress: {
82 | unused: true,
83 | dead_code: true,
84 | warnings: false
85 | }
86 | },
87 | sourceMap: true
88 | }),
89 | new OptimizeCSSAssetsPlugin({})
90 | ]
91 | },
92 | performance: {
93 | hints: false
94 | }
95 | };
96 |
97 | // ------------------------------------
98 | // STAGE PLUGINS INJECTION! [DEVELOPMENT, PRODUCTION, TESTING]
99 | // ------------------------------------
100 | const stagePlugins = {
101 | test: [
102 | new BundleAnalyzerPlugin()
103 | ],
104 | development: [
105 | new HtmlWebpackPlugin({
106 | template: path.resolve('./src/index.html'),
107 | filename: 'index.html',
108 | inject: 'body',
109 | minify: false,
110 | chunksSortMode: 'auto'
111 | }),
112 | new webpack.HotModuleReplacementPlugin(),
113 | new webpack.NoEmitOnErrorsPlugin()
114 | ],
115 | production: [
116 | new MiniCssExtractPlugin({
117 | filename: '[name].[hash].css',
118 | chunkFilename: '[name].[hash].css'
119 | }),
120 | new HtmlWebpackPlugin({
121 | template: path.resolve('./src/index.html'),
122 | filename: 'index.html',
123 | inject: 'body',
124 | minify: {
125 | collapseWhitespace: true
126 | },
127 | chunksSortMode: 'auto'
128 | }),
129 | new webpack.ProvidePlugin({
130 | fetch: 'exports-loader?self.fetch!whatwg-fetch'
131 | })
132 | ]
133 | };
134 |
135 | // ------------------------------------
136 | // STAGE CONFIGURATION INJECTION! [DEVELOPMENT, PRODUCTION]
137 | // ------------------------------------
138 | const stageConfig = {
139 | development: {
140 | devtool: '',
141 | stats: {
142 | chunks: false,
143 | children: false,
144 | chunkModules: false,
145 | colors: true
146 | }
147 | },
148 | production: {
149 | devtool: 'source-map',
150 | stats: {
151 | chunks: true,
152 | chunkModules: true,
153 | colors: true
154 | }
155 | }
156 | };
157 |
158 | const createConfig = () => {
159 | debug('Creating configuration.');
160 | debug(`Enabling devtools for "${__NODE_ENV__} Mode!"`);
161 |
162 | const webpackConfig = {
163 | mode: __DEV__ ? 'development' : 'production',
164 | name: 'client',
165 | target: 'web',
166 | devtool: stageConfig[__NODE_ENV__].devtool,
167 | stats: stageConfig[__NODE_ENV__].stats,
168 | module: {
169 | rules: [
170 | ...rules
171 | ]
172 | },
173 | ...optimization,
174 | resolve: {
175 | modules: ['node_modules'],
176 | extensions: ['.ts', '.tsx', '.js', '.jsx', '.json']
177 | }
178 | };
179 |
180 | // ------------------------------------
181 | // Entry Points
182 | // ------------------------------------
183 | webpackConfig.entry = {
184 | app: ['babel-polyfill', path.resolve(__dirname, 'src/index.js')].concat('webpack-hot-middleware/client?path=/__webpack_hmr')
185 | };
186 |
187 | // ------------------------------------
188 | // Bundle externals
189 | // ------------------------------------
190 | webpackConfig.externals = {
191 | react: 'React',
192 | 'react-dom': 'ReactDOM'
193 | };
194 |
195 | // ------------------------------------
196 | // Bundle Output
197 | // ------------------------------------
198 | webpackConfig.output = {
199 | filename: '[name].[hash].js',
200 | chunkFilename: '[name].[hash].js',
201 | path: path.resolve(__dirname, 'dist'),
202 | publicPath: '/'
203 | };
204 |
205 | // ------------------------------------
206 | // Plugins
207 | // ------------------------------------
208 | debug(`Enable plugins for "${__NODE_ENV__} Mode!"`);
209 | webpackConfig.plugins = [
210 | new webpack.DefinePlugin({
211 | __DEV__,
212 | __PROD__,
213 | __TEST__
214 | }),
215 | ...stagePlugins[__NODE_ENV__]
216 | ];
217 |
218 | // ------------------------------------
219 | // Finishing the Webpack configuration!
220 | // ------------------------------------
221 | debug(`Webpack Bundles is Ready for "${__NODE_ENV__} Mode!"`);
222 | return webpackConfig;
223 | };
224 |
225 | module.exports = createConfig();
226 |
--------------------------------------------------------------------------------
/.stylelintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "stylelint-config-standard",
3 | "plugins": [
4 | "stylelint-no-unsupported-browser-features",
5 | "stylelint-order"
6 | ],
7 | "ignoreFiles": ["**/*.js","**/*.jsx","**/*.ts","**/*.tsx","**/*.html"],
8 | "rules": {
9 | "declaration-block-no-redundant-longhand-properties": [
10 | true,
11 | {
12 | "ignoreShorthands": ["flex-flow"]
13 | }
14 | ],
15 | "function-comma-space-after": "always",
16 | "declaration-block-no-duplicate-properties": null,
17 | "comment-empty-line-before": [
18 | "always"
19 | ],
20 | "at-rule-no-unknown": [true, {
21 | "ignoreAtRules": ["function", "if", "each", "include", "mixin"]
22 | }],
23 | "at-rule-empty-line-before": [
24 | "always",
25 | {
26 | "except": [
27 | "after-same-name"
28 | ]
29 | }
30 | ],
31 | "number-leading-zero": "never",
32 | "indentation": [
33 | 2, {
34 | "indentInsideParens": "once-at-root-twice-in-block",
35 | "severity": "error"
36 | }
37 | ],
38 | "plugin/no-unsupported-browser-features": [
39 | true,
40 | {
41 | "severity": "warning",
42 | "ignore": [
43 | "css-boxshadow",
44 | "pointer-events",
45 | "border-radius",
46 | "border-image",
47 | "css-gradients",
48 | "css-textshadow",
49 | "transforms2d",
50 | "css-animation",
51 | "css-transitions",
52 | "css-transform",
53 | "transition",
54 | "transform",
55 | "css-image-set",
56 | "flexbox",
57 | "viewport-units",
58 | "calc",
59 | "intrinsic-width"
60 | ]
61 | }
62 | ],
63 | "selector-pseudo-class-no-unknown": [
64 | true,
65 | {
66 | "ignorePseudoClasses": ["global", "local"]
67 | }
68 | ],
69 | "selector-pseudo-class-case": null,
70 | "property-no-unknown": [
71 | true,
72 | {
73 | "ignoreProperties": ["composes", "r"]
74 | }
75 | ],
76 | "unit-no-unknown": [
77 | true,
78 | {
79 | "ignoreUnits": ["x"]
80 | }
81 | ],
82 | "order/order": [
83 | [
84 | "custom-properties",
85 | "at-variables",
86 | "declarations",
87 | "at-rules",
88 | "rules",
89 | "less-mixins"
90 | ],
91 | {
92 | "severity": "warning"
93 | }
94 | ],
95 | "order/properties-order": [
96 | [
97 | {
98 | "emptyLineBefore": "never",
99 | "properties": [
100 | "content"
101 | ]
102 | },
103 | {
104 | "emptyLineBefore": "never",
105 | "properties": [
106 | "position",
107 | "top",
108 | "right",
109 | "bottom",
110 | "left",
111 | "z-index"
112 | ]
113 | },
114 | {
115 | "emptyLineBefore": "never",
116 | "properties": [
117 | "box-sizing",
118 | "display",
119 | "flex",
120 | "flex-basis",
121 | "flex-direction",
122 | "flex-flow",
123 | "flex-grow",
124 | "flex-shrink",
125 | "flex-wrap",
126 | "align-content",
127 | "align-items",
128 | "align-self",
129 | "justify-content",
130 | "order",
131 | "margin",
132 | "margin-top",
133 | "margin-right",
134 | "margin-bottom",
135 | "margin-left",
136 | "padding",
137 | "padding-top",
138 | "padding-right",
139 | "padding-bottom",
140 | "padding-left",
141 | "min-width",
142 | "min-height",
143 | "max-width",
144 | "max-height",
145 | "width",
146 | "height",
147 | "float",
148 | "clear",
149 | "clip",
150 | "visibility",
151 | "overflow",
152 | "border",
153 | "border-top",
154 | "border-right",
155 | "border-bottom",
156 | "border-left",
157 | "border-width",
158 | "border-top-width",
159 | "border-right-width",
160 | "border-bottom-width",
161 | "border-left-width",
162 | "border-style",
163 | "border-top-style",
164 | "border-right-style",
165 | "border-bottom-style",
166 | "border-left-style",
167 | "border-radius",
168 | "border-top-left-radius",
169 | "border-top-right-radius",
170 | "border-bottom-right-radius",
171 | "border-bottom-left-radius",
172 | "border-color",
173 | "border-top-color",
174 | "border-right-color",
175 | "border-bottom-color",
176 | "border-left-color",
177 | "box-shadow"
178 | ]
179 | },
180 | {
181 | "emptyLineBefore": "never",
182 | "properties": [
183 | "background",
184 | "background-attachment",
185 | "background-clip",
186 | "background-color",
187 | "background-image",
188 | "background-repeat",
189 | "background-position",
190 | "background-size"
191 | ]
192 | },
193 | {
194 | "emptyLineBefore": "never",
195 | "properties": [
196 | "color",
197 | "font",
198 | "font-family",
199 | "font-size",
200 | "font-smoothing",
201 | "font-style",
202 | "font-variant",
203 | "font-weight",
204 | "letter-spacing",
205 | "line-height",
206 | "list-style",
207 | "text-align",
208 | "text-decoration",
209 | "text-indent",
210 | "text-overflow",
211 | "text-rendering",
212 | "text-shadow",
213 | "text-transform",
214 | "text-wrap",
215 | "vertical-align",
216 | "white-space",
217 | "word-spacing"
218 | ]
219 | }
220 | ],
221 | {
222 | "severity": "warning"
223 | }
224 | ]
225 | }
226 | }
227 |
--------------------------------------------------------------------------------
/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "defaultSeverity": "error",
3 | "extends": [
4 | "tslint-config-airbnb",
5 | "tslint-eslint-rules",
6 | "tslint-react"
7 | ],
8 | "jsRules": {},
9 | "rulesDirectory": [],
10 | "rules": {
11 | "arrow-parens": false,
12 | "whitespace": [
13 | false,
14 | "check-branch",
15 | "check-decl",
16 | "check-operator",
17 | "check-separator",
18 | "check-type"
19 | ],
20 | "arrow-return-shorthand": [false],
21 | "semicolon": [true, "never"],
22 | "block-spacing": [
23 | true,
24 | "never"
25 | ],
26 | "comment-format": [true, "check-space"],
27 | "function-name": [false],
28 | "import-blacklist": [true, "rxjs"],
29 | "interface-over-type-literal": false,
30 | "interface-name": false,
31 | "naming-convention": [true,
32 | {"type": "default", "format": "camelCase", "leadingUnderscore": "allow", "trailingUnderscore": "forbid"},
33 | {"type": "variable", "format": ["camelCase","UPPER_CASE","PascalCase"]},
34 | {"type": "variable", "modifiers": ["global", "const"], "format": ["camelCase","UPPER_CASE","PascalCase"]},
35 | {"type": "variable", "modifiers": ["export", "const"], "format": ["camelCase","UPPER_CASE"]},
36 | {"type": "functionVariable", "modifiers": ["export", "const"], "leadingUnderscore": "forbid", "format": "camelCase"},
37 | {"type": "parameter", "modifiers": "unused", "leadingUnderscore": "allow"},
38 | {"type": "member", "modifiers": "private", "leadingUnderscore": "require"},
39 | {"type": "member", "modifiers": "protected", "leadingUnderscore": "require"},
40 | {"type": "method", "filter": "^toJSON$", "format": null},
41 | {"type": "property", "modifiers": ["public", "static", "const"], "format": "UPPER_CASE"},
42 | {"type": "type", "format": "PascalCase"},
43 | {"type": "typeAlias", "format": "PascalCase", "prefix": "T"},
44 | {"type": "class", "modifiers": "abstract"},
45 | {"type": "interface", "format": "PascalCase", "prefix": "I"},
46 | {"type": "genericTypeParameter", "format": "PascalCase", "prefix": "T"},
47 | {"type": "enumMember", "format": "PascalCase"}
48 | ],
49 | "max-line-length": [true, 120],
50 | "member-access": false,
51 | "member-ordering": [true, { "order": "fields-first" }],
52 | "newline-before-return": false,
53 | "no-any": false,
54 | "no-empty-interface": false,
55 | "no-import-side-effect": [true],
56 | "no-inferrable-types": [true, "ignore-params", "ignore-properties"],
57 | "no-invalid-this": [true, "check-function-in-method"],
58 | "no-null-keyword": false,
59 | "no-require-imports": false,
60 | "no-submodule-imports": [false],
61 | "no-this-assignment": [true, { "allow-destructuring": true }],
62 | "no-trailing-whitespace": true,
63 | "no-var-requires": false,
64 | "object-literal-sort-keys": false,
65 | "object-literal-shorthand": false,
66 | "one-variable-per-declaration": [false],
67 | "only-arrow-functions": [true, "allow-declarations"],
68 | "ordered-imports": [false],
69 | "prefer-method-signature": false,
70 | "prefer-template": [true, "allow-single-concat"],
71 | "no-unused-variable": true,
72 | "no-restricted-globals": [2, "find"],
73 | "no-cond-assign": [1, "always"],
74 | "trailing-comma": [true, {
75 | "singleline": "never",
76 | "multiline": {
77 | "objects": "never",
78 | "arrays": "never",
79 | "functions": "never",
80 | "typeLiterals": "ignore"
81 | }
82 | }],
83 | "newline-per-chained-call": [false],
84 | "triple-equals": [true, "allow-null-check"],
85 | "type-literal-delimiter": false,
86 | "typedef": [true,"parameter", "property-declaration"],
87 | "variable-name": [true, "ban-keywords", "check-format", "allow-pascal-case", "allow-leading-underscore"],
88 | "jsx-no-lambda": false,
89 | "ter-arrow-parens": [false],
90 | "ter-indent": [
91 | false,
92 | 2,
93 | {
94 | "SwitchCase": 4
95 | }
96 | ],
97 | "quotemark": [true, "single", "jsx-single"],
98 | "import-name": [false],
99 | "no-restricted-imports": [
100 | 1,
101 | "lodash"
102 | ],
103 | "new-parens": true,
104 | "no-plusplus": [1, { "allowForLoopAfterthoughts": true }],
105 | "prefer-promise-reject-errors": [1, { "allowEmptyReject": false }],
106 | "one-var": [1, "never"],
107 | "max-len": [2, { "code": 120, "ignoreStrings": true }],
108 | "dot-location": [2, "property"],
109 | "operator-linebreak": [
110 | 2,
111 | "after",
112 | {
113 | "overrides": {
114 | ">": "before",
115 | ">=": "before",
116 | "<": "before",
117 | "<=": "before",
118 | "||": "before",
119 | "&&": "before",
120 | "+": "before",
121 | "-": "before"
122 | }
123 | }
124 | ],
125 | "max-statements": [2, 15],
126 | "max-depth": [1, 2],
127 | "complexity": [2, 10],
128 | "max-params": [1, 3],
129 | "max-nested-callbacks": [2, 3],
130 | "prefer-const": true,
131 | "no-param-reassign": [
132 | 1,
133 | {
134 | "props": false
135 | }
136 | ],
137 | "no-console": false,
138 | "comma-dangle": [2, "never"],
139 | "func-style": [
140 | 2,
141 | "declaration",
142 | {
143 | "allowArrowFunctions": true
144 | }
145 | ],
146 | "newline-after-var": [2, "always"],
147 | "new-cap": [
148 | 2,
149 | {
150 | "capIsNewExceptions": ["Nothing", "T", "F"],
151 | "newIsCap": false
152 | }
153 | ],
154 | "no-unused-expressions": [
155 | 2,
156 | {
157 | "allowShortCircuit": true,
158 | "allowTernary": true
159 | }
160 | ],
161 | "no-underscore-dangle": [
162 | 2,
163 | {
164 | "allow": ["_exception", "__html"]
165 | }
166 | ],
167 | "jsx-quotes": [2, "prefer-single"],
168 | "react/jsx-indent": [4, "spaces"],
169 | "react/prefer-stateless-function": [
170 | 1,
171 | {
172 | "ignorePureComponents": true
173 | }
174 | ],
175 | "react/require-optimization": [
176 | 1,
177 | { "allowDecorators": ["pureRender", "connect"] }
178 | ],
179 | "react/forbid-prop-types": [
180 | 2,
181 | {
182 | "forbid": ["any"]
183 | }
184 | ],
185 | "quote-props": [1, "consistent-as-needed"],
186 | "react/display-name": [
187 | 1,
188 | {
189 | "ignoreTranspilerName": false
190 | }
191 | ],
192 | "react/jsx-indent-props": [1, 2],
193 | "react/no-multi-comp": [
194 | 1,
195 | {
196 | "ignoreStateless": true
197 | }
198 | ],
199 | "react/jsx-handler-names": [
200 | 1,
201 | {
202 | "eventHandlerPrefix": "handle",
203 | "eventHandlerPropPrefix": "on"
204 | }
205 | ],
206 | "react/jsx-max-props-per-line": [1, { "maximum": 2 }],
207 | "react/sort-comp": [
208 | 2,
209 | {
210 | "order": [
211 | "static-methods",
212 | "mixins",
213 | "displayName",
214 | "actions",
215 | "contextTypes",
216 | "childContextTypes",
217 | "propTypes",
218 | "defaultProps",
219 | "pure",
220 | "statics",
221 | "state",
222 | "constructor",
223 | "getDefaultProps",
224 | "getInitialState",
225 | "getChildContext",
226 | "getStoresState",
227 | "componentWillMount",
228 | "componentDidMount",
229 | "componentWillReceiveProps",
230 | "shouldComponentUpdate",
231 | "componentWillUpdate",
232 | "componentDidUpdate",
233 | "componentWillUnmount",
234 | "/^component.+$/",
235 | "/^get.+$/",
236 | "/^on.+$/",
237 | "/^handle.+$/",
238 | "everything-else",
239 | "/^render.+$/",
240 | "render"
241 | ]
242 | }
243 | ],
244 | "import/no-unresolved": [
245 | 2,
246 | {
247 | "commonjs": true,
248 | "amd": false
249 | }
250 | ],
251 | "import/extensions": [
252 | 1,
253 | "always",
254 | {
255 | "js": "never",
256 | "jsx": "always"
257 | }
258 | ],
259 | "no-multiple-empty-lines": [
260 | 2,
261 | {
262 | "max": 1
263 | }
264 | ]
265 | }
266 | }
267 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["airbnb", "plugin:import/react"],
3 | "parser": "babel-eslint",
4 | "plugins": [
5 | "react",
6 | "react-hooks",
7 | "import",
8 | "jest"
9 | ],
10 | "env": {
11 | "browser": true,
12 | "node": true,
13 | "jest/globals": true
14 | },
15 | "settings": {
16 | "import/parser": "babel-eslint",
17 | "import/ignore": [
18 | "node_modules"
19 | ],
20 | "import/resolver": {
21 | "webpack": {
22 | "config": "./config/webpackConfigFactory.js"
23 | },
24 | "node": {
25 | "paths": [
26 | "./"
27 | ],
28 | "extensions": [".js",".jsx",".ts",".tsx"]
29 | }
30 | },
31 | "react": {
32 | "pragma": "React",
33 | "version": "16.3"
34 | }
35 | },
36 | "globals": {
37 | "jest": true,
38 | "react_disableWarnings": true,
39 | "react_enableWarnings": true,
40 | "__NODE_ENV__": false,
41 | "__PORT__": false,
42 | "__DEV__": false,
43 | "__TEST__": false,
44 | "__PROD__": false,
45 | "__COVERAGE__": false
46 | },
47 | "rules": {
48 | "react-hooks/rules-of-hooks": "error",
49 | "indent": [
50 | 1,
51 | 2,
52 | {
53 | "SwitchCase": 1
54 | }
55 | ],
56 | "import/extensions": [1, "always", {
57 | "js": "never",
58 | "jsx": "never",
59 | "json": "never",
60 | "ts": "never",
61 | "tsx": "never",
62 | ".tsx": "never"
63 | }],
64 | "import/no-named-as-default": 0,
65 | "linebreak-style": [1, "unix"],
66 | "no-restricted-imports": [1, "lodash"],
67 | "no-restricted-globals": [2, "find"],
68 | "no-var": 0,
69 | "no-shadow": 1,
70 | "vars-on-top": 0,
71 | "consistent-return": 1,
72 | "no-unused-vars": ["error", { "vars": "all", "args": "all", "ignoreRestSiblings": false, "argsIgnorePattern": "^nextProps|^nextState" }],
73 | "no-cond-assign": [1, "always"],
74 | "default-case": 1,
75 | "no-use-before-define": 1,
76 | "one-var-declaration-per-line": 1,
77 | "no-confusing-arrow": 1,
78 | "arrow-body-style": 0,
79 | "prefer-arrow-callback": 1,
80 | "no-case-declarations": 1,
81 | "newline-per-chained-call": 1,
82 | "no-restricted-syntax": 1,
83 | "guard-for-in": 1,
84 | "no-mixed-operators": 0,
85 | "no-continue": 1,
86 | "func-name-matching": 1,
87 | "prefer-template": 1,
88 | "no-useless-escape": 1,
89 | "new-parens": 1,
90 | "class-methods-use-this": 1,
91 | "no-return-assign": 1,
92 | "no-plusplus": [1, { "allowForLoopAfterthoughts": true }],
93 | "no-restricted-properties": 1,
94 | "prefer-promise-reject-errors": [1, {"allowEmptyReject": false}],
95 | "one-var": [
96 | 1,
97 | "never"
98 | ],
99 | "object-curly-newline": ["error", { "multiline": true, "consistent": true }],
100 | "max-len": [2, { "code": 120, "ignoreStrings": true }],
101 | "quotes": ["error", "single", { "avoidEscape": true }],
102 | "dot-location": [
103 | 2,
104 | "property"
105 | ],
106 | "operator-linebreak": [
107 | 2,
108 | "after",
109 | {
110 | "overrides": {
111 | ">": "before",
112 | ">=": "before",
113 | "<": "before",
114 | "<=": "before",
115 | "||": "before",
116 | "&&": "before",
117 | "+": "before",
118 | "-": "before"
119 | }
120 | }
121 | ],
122 | "max-statements": [
123 | 2,
124 | 15
125 | ],
126 | "max-depth": [
127 | 1,
128 | 2
129 | ],
130 | "complexity": [
131 | 2,
132 | 10
133 | ],
134 | "max-params": [
135 | 1,
136 | 3
137 | ],
138 | "max-nested-callbacks": [
139 | 2,
140 | 3
141 | ],
142 | "space-before-function-paren": [
143 | 2,
144 | "never"
145 | ],
146 | "semi": ["error", "always"],
147 | "prefer-const": 1,
148 | "no-param-reassign": [
149 | 1,
150 | {
151 | "props": false
152 | }
153 | ],
154 | "dot-notation": "off",
155 | "allowAfterThis": true,
156 | "no-console": "off",
157 | "curly": 0,
158 | "comma-dangle": [
159 | 2,
160 | "never"
161 | ],
162 | "func-style": [
163 | 2,
164 | "declaration",
165 | {
166 | "allowArrowFunctions": true
167 | }
168 | ],
169 | "newline-after-var": [
170 | 2,
171 | "always"
172 | ],
173 | "new-cap": [
174 | 2,
175 | {
176 | "capIsNewExceptions": [
177 | "When",
178 | "Then",
179 | "Given",
180 | "Nothing",
181 | "T",
182 | "F"
183 | ],
184 | "newIsCap": false,
185 | "capIsNew": false
186 | }
187 | ],
188 | "no-unused-expressions": [
189 | 2,
190 | {
191 | "allowShortCircuit": true,
192 | "allowTernary": true
193 | }
194 | ],
195 | "no-underscore-dangle": [
196 | 0,
197 | {
198 | "allowAfterThis": true,
199 | "allow": [
200 | "__REDUX_DEVTOOLS_EXTENSION__",
201 | "__REDUX_DEVTOOLS_EXTENSION_COMPOSE__",
202 | "__DEV__",
203 | "__INITIAL_STATE__",
204 | "_exception",
205 | "__html"
206 | ]
207 | }
208 | ],
209 | "arrow-parens": [
210 | 2,
211 | "as-needed",
212 | {
213 | "requireForBlockBody": false
214 | }
215 | ],
216 | "jsx-quotes": [
217 | 2,
218 | "prefer-single"
219 | ],
220 | "react/jsx-indent": [
221 | 1,
222 | 2
223 | ],
224 | "jsx-a11y/img-has-alt": 0,
225 | "jsx-a11y/aria-role": 1,
226 | "jsx-a11y/label-has-for": 0,
227 | "jsx-a11y/href-no-hash": 0,
228 | "jsx-a11y/html-has-lang": 1,
229 | "jsx-a11y/no-static-element-interactions": 1,
230 | "jsx-a11y/anchor-has-content": 1,
231 | "jsx-a11y/no-noninteractive-element-interactions": 1,
232 | "jsx-a11y/alt-text": 1,
233 | "jsx-a11y/iframe-has-title": 1,
234 | "jsx-a11y/no-autofocus": 1,
235 | "jsx-a11y/media-has-caption": 1,
236 | "jsx-a11y/no-noninteractive-tabindex": 1,
237 | "jsx-a11y/no-noninteractive-element-to-interactive-role": 1,
238 | "jsx-a11y/interactive-supports-focus": 1,
239 | "react/no-array-index-key": 1,
240 | "react/no-will-update-set-state": 1,
241 | "react/require-default-props": 1,
242 | "react/style-prop-object": 0,
243 | "react/jsx-first-prop-new-line": 1,
244 | "react/jsx-one-expression-per-line": 0,
245 | "react/prefer-stateless-function": [
246 | 1,
247 | {
248 | "ignorePureComponents": true
249 | }
250 | ],
251 | "react/jsx-no-bind": 2,
252 | "react/no-direct-mutation-state": 2,
253 | "react/jsx-key": 2,
254 | "react/no-find-dom-node": 1,
255 | "react/require-optimization": [1, {"allowDecorators": ["pureRender", "connect"]}],
256 | "react/jsx-filename-extension": 0,
257 | "react/jsx-no-target-blank": 2,
258 | "react/no-children-prop": 1,
259 | "react/forbid-prop-types": [
260 | 2,
261 | {
262 | "forbid": ["any"]
263 | }
264 | ],
265 | "quote-props": [
266 | 1,
267 | "as-needed"
268 | ],
269 | "react/prop-types": 2,
270 | "react/display-name": [
271 | 1,
272 | {
273 | "ignoreTranspilerName": false
274 | }
275 | ],
276 | "react/jsx-indent-props": [
277 | 1,
278 | 2
279 | ],
280 | "react/no-multi-comp": [
281 | 1,
282 | {
283 | "ignoreStateless": true
284 | }
285 | ],
286 | "react/jsx-handler-names": [
287 | 1,
288 | {
289 | "eventHandlerPrefix": "_handle",
290 | "eventHandlerPropPrefix": "on"
291 | }
292 | ],
293 | "no-else-return": [
294 | "error",
295 | {
296 | "allowElseIf": true
297 | }
298 | ],
299 | "react/jsx-max-props-per-line": [1, { "maximum": 2 }],
300 | "react/jsx-wrap-multilines": 0,
301 | "react/no-unused-prop-types": 1,
302 | "react/sort-comp": [
303 | 2,
304 | {
305 | "order": [
306 | "static-methods",
307 | "mixins",
308 | "displayName",
309 | "actions",
310 | "contextTypes",
311 | "childContextTypes",
312 | "propTypes",
313 | "defaultProps",
314 | "pure",
315 | "statics",
316 | "state",
317 | "constructor",
318 | "getDefaultProps",
319 | "getInitialState",
320 | "getChildContext",
321 | "getStoresState",
322 | "componentWillMount",
323 | "componentDidMount",
324 | "componentWillReceiveProps",
325 | "shouldComponentUpdate",
326 | "componentWillUpdate",
327 | "componentDidUpdate",
328 | "componentWillUnmount",
329 | "/^component.+$/",
330 | "/^get.+$/",
331 | "/^on.+$/",
332 | "/^handle.+$/",
333 | "everything-else",
334 | "/^render.+$/",
335 | "render"
336 | ]
337 | }
338 | ],
339 | "import/no-unresolved": [
340 | 2,
341 | {
342 | "commonjs": true,
343 | "amd": false
344 | }
345 | ],
346 | "import/no-commonjs": [0, { "allowPrimitiveModules": true }],
347 | "import/named": 2,
348 | "import/namespace": 2,
349 | "import/default": 2,
350 | "import/prefer-default-export": 1,
351 | "import/newline-after-import": 0,
352 | "import/unambiguous": 0,
353 | "import/no-webpack-loader-syntax": 1,
354 | "import/first": 1,
355 | "import/no-dynamic-require": 1,
356 | "import/no-deprecated": 1,
357 | "import/no-extraneous-dependencies": 0,
358 | "jest/no-disabled-tests": "warn",
359 | "jest/no-focused-tests": "error",
360 | "jest/no-identical-title": "error",
361 | "jest/valid-expect": "error",
362 | "no-multiple-empty-lines": [2, {
363 | "max": 1
364 | }]
365 | }
366 | }
367 |
--------------------------------------------------------------------------------