├── .flowconfig
├── .gitignore
├── .foreverignore
├── src
├── screens
│ ├── main.css
│ ├── results
│ │ ├── index.js
│ │ └── Container.js
│ ├── app
│ │ ├── loading
│ │ │ ├── index.js
│ │ │ ├── View.js
│ │ │ ├── main.css
│ │ │ ├── Container.js
│ │ │ └── __tests__
│ │ │ │ └── Container.test.js
│ │ ├── actions.js
│ │ ├── index.js
│ │ ├── reducer.js
│ │ ├── Container.js
│ │ └── __tests__
│ │ │ └── Container.test.js
│ ├── index.js
│ ├── reducers.js
│ └── home
│ │ └── index.js
├── components
│ └── property-card
│ │ ├── index.js
│ │ ├── main.css
│ │ └── View.js
├── shared
│ ├── polyfills.js
│ ├── fetchData.js
│ └── routes.js
├── server
│ ├── ignoreExtensions.js
│ ├── pages
│ │ ├── index.js
│ │ ├── error.js
│ │ └── default.js
│ ├── mockAPI.js
│ ├── index.js
│ ├── mockData.json
│ └── middleware.js
├── app.js
├── types
│ └── Property.js
└── client
│ └── index.js
├── __mocks__
├── fileMock.js
└── styleMock.js
├── .babelrc
├── config
└── webpack.config.js
├── README.md
├── package.json
└── .eslintrc.js
/.flowconfig:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | node_modules
3 | public
--------------------------------------------------------------------------------
/.foreverignore:
--------------------------------------------------------------------------------
1 | .idea/*
2 | node_modules
3 | public
4 | src/client/*
--------------------------------------------------------------------------------
/src/screens/main.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: #f0f0f0;
3 | }
4 |
--------------------------------------------------------------------------------
/src/screens/results/index.js:
--------------------------------------------------------------------------------
1 | export { default } from './Container';
--------------------------------------------------------------------------------
/__mocks__/fileMock.js:
--------------------------------------------------------------------------------
1 | // __mocks__/fileMock.js
2 |
3 | module.exports = {};
--------------------------------------------------------------------------------
/__mocks__/styleMock.js:
--------------------------------------------------------------------------------
1 | // __mocks__/styleMock.js
2 |
3 | module.exports = {};
--------------------------------------------------------------------------------
/src/components/property-card/index.js:
--------------------------------------------------------------------------------
1 | // @flow
2 |
3 | export { default } from './View';
--------------------------------------------------------------------------------
/src/screens/app/loading/index.js:
--------------------------------------------------------------------------------
1 | // @flow
2 |
3 | export { default } from './Container';
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "env",
4 | "react",
5 | "stage-2"
6 | ]
7 | }
--------------------------------------------------------------------------------
/src/shared/polyfills.js:
--------------------------------------------------------------------------------
1 | require('es6-promise').polyfill();
2 | require('isomorphic-fetch');
--------------------------------------------------------------------------------
/src/server/ignoreExtensions.js:
--------------------------------------------------------------------------------
1 | const noop = () => null;
2 |
3 | require.extensions['.css'] = noop;
4 |
--------------------------------------------------------------------------------
/src/server/pages/index.js:
--------------------------------------------------------------------------------
1 | export { default } from './default';
2 | export { default as error } from './error';
--------------------------------------------------------------------------------
/src/screens/app/actions.js:
--------------------------------------------------------------------------------
1 | export const DATA_LOADED = 'DATA_LOADED';
2 | export const DATA_FETCHING = 'DATA_FETCHING';
--------------------------------------------------------------------------------
/src/screens/app/index.js:
--------------------------------------------------------------------------------
1 | export { default } from './Container';
2 | export { default as reducer } from './reducer';
--------------------------------------------------------------------------------
/src/app.js:
--------------------------------------------------------------------------------
1 | require('./shared/polyfills');
2 | require('./server/ignoreExtensions');
3 | require('babel-register');
4 | require('./server');
--------------------------------------------------------------------------------
/src/types/Property.js:
--------------------------------------------------------------------------------
1 | // @flow
2 |
3 | export type Property = {
4 | image: string,
5 | address: string,
6 | type: string,
7 | }
--------------------------------------------------------------------------------
/src/screens/app/loading/View.js:
--------------------------------------------------------------------------------
1 | import './main.css'
2 | import React from 'react';
3 |
4 | export default () =>
Loading...
;
5 |
--------------------------------------------------------------------------------
/src/screens/index.js:
--------------------------------------------------------------------------------
1 | import './main.css';
2 | export { default as App } from './app';
3 | export { default as Home } from './home';
4 | export { default as Results } from './results';
--------------------------------------------------------------------------------
/src/server/mockAPI.js:
--------------------------------------------------------------------------------
1 | import mockData from './mockData.json'
2 |
3 | export default (_, response) => {
4 | response.setHeader('Content-Type', 'application/json');
5 | response.send(mockData);
6 | };
--------------------------------------------------------------------------------
/src/screens/reducers.js:
--------------------------------------------------------------------------------
1 | /*
2 | http://redux.js.org/docs/recipes/reducers/UsingCombineReducers.html
3 | */
4 | import { combineReducers } from 'redux'
5 | import { reducer as apiData } from './app';
6 |
7 | export default combineReducers({ apiData });
8 |
--------------------------------------------------------------------------------
/src/shared/fetchData.js:
--------------------------------------------------------------------------------
1 | const emptyPromise = () => Promise.resolve();
2 |
3 | export default ({ routes }) => {
4 | const matchedRoute = routes[routes.length - 1];
5 | const fetchData = matchedRoute.fetchData || emptyPromise;
6 |
7 | return fetchData();
8 | }
--------------------------------------------------------------------------------
/src/server/pages/error.js:
--------------------------------------------------------------------------------
1 | export default (app) => `
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | ${app}
10 |
11 |
12 | `;
--------------------------------------------------------------------------------
/src/components/property-card/main.css:
--------------------------------------------------------------------------------
1 | .property-card {
2 | overflow: hidden;
3 | width:400px;
4 | margin-bottom: 10px;
5 | border-radius: 4px;
6 | font-family: Helvetica;
7 | background:#fff;
8 | border-bottom: solid 2px #ccc;
9 | }
10 |
11 | .property-card__content {
12 | text-align:center;
13 | padding: 5px;
14 | }
15 |
--------------------------------------------------------------------------------
/src/shared/routes.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Route, IndexRoute } from 'react-router';
3 | import { App, Home, Results } from '../screens';
4 |
5 | export default (
6 |
7 |
8 |
9 |
10 | )
11 |
--------------------------------------------------------------------------------
/src/screens/app/loading/main.css:
--------------------------------------------------------------------------------
1 | .loader {
2 | position: fixed;
3 | background: rgba(51, 63, 72, 0.95);
4 | width:75px;
5 | height: 75px;
6 | line-height: 75px;
7 | margin: -37px 0 0 -37px;
8 | border-radius:50%;
9 | top:50%;
10 | left:50%;
11 | color: #fff;
12 | text-align: center;
13 | opacity: 1;
14 | z-index: 999;
15 | visibility: visible;
16 | }
17 |
--------------------------------------------------------------------------------
/src/screens/home/index.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Link } from 'react-router';
3 |
4 | export default class Home extends Component {
5 | render () {
6 | return (
7 |
8 |
Welcome to the homepage
9 |
Go get some Results
10 |
11 | );
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/screens/app/loading/Container.js:
--------------------------------------------------------------------------------
1 | // @flow
2 |
3 | import React from 'react';
4 | import { connect } from 'react-redux';
5 | import View from './View';
6 |
7 | export const Container = ({fetchingData}: {fetchingData: boolean}) => {
8 | return fetchingData ? : null;
9 | };
10 |
11 | const mapStateToProps = ({apiData}) => {
12 | return { fetchingData: apiData.fetchingData }
13 | };
14 |
15 | export default connect(mapStateToProps)(Container);
16 |
--------------------------------------------------------------------------------
/src/screens/app/reducer.js:
--------------------------------------------------------------------------------
1 | import { DATA_LOADED, DATA_FETCHING } from './actions';
2 |
3 | export default (state = {}, action) => {
4 | switch (action.type) {
5 | case DATA_FETCHING: {
6 | return { ...state, fetchingData: true };
7 | }
8 |
9 | case DATA_LOADED: {
10 | const { data } = action;
11 |
12 | return { ...state, data, fetchingData: false };
13 | }
14 |
15 | default: {
16 | return state;
17 | }
18 | }
19 | };
20 |
--------------------------------------------------------------------------------
/src/server/pages/default.js:
--------------------------------------------------------------------------------
1 | export default (app, data) => `
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | ${app}
10 |
13 |
14 |
15 |
16 | `;
--------------------------------------------------------------------------------
/src/components/property-card/View.js:
--------------------------------------------------------------------------------
1 | // @flow
2 |
3 | import React from 'react';
4 | import './main.css';
5 | import type { Property } from '../../types/Property';
6 |
7 | export default ({image, address, type}: Property) => (
8 |
9 |
10 |
11 |
{type}
12 |
{address}
13 |
14 |
15 | )
--------------------------------------------------------------------------------
/src/screens/app/loading/__tests__/Container.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { shallow } from 'enzyme';
3 | import { Container } from '../Container';
4 | import View from '../View';
5 |
6 | describe("Loader", () => {
7 | const test = shallow(
8 |
9 | );
10 |
11 | it("renders a loader when fetchingData", () => {
12 | expect(test.contains( )).toBeTruthy();
13 | });
14 |
15 | it("renders null when not fetchingData", () => {
16 | test.setProps({fetchingData: false});
17 | expect(test.type()).toBe(null);
18 | });
19 | });
20 |
--------------------------------------------------------------------------------
/src/server/index.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 |
3 | import express from 'express';
4 | import path from 'path';
5 | import middleware from './middleware';
6 | import mockAPI from './mockAPI';
7 |
8 | const app = express();
9 |
10 | app.set('host', process.env.HOST || "0.0.0.0");
11 | app.set('port', process.env.PORT || 3001);
12 |
13 | app.use('/public', express.static(path.join(__dirname, '../../public')));
14 | app.get('/api', mockAPI);
15 | app.use('/', middleware);
16 |
17 | app.listen(app.get('port'), app.get('host'), () => {
18 | console.log(`server listening on http://${app.get('host')}:${app.get('port')}`);
19 | });
20 |
--------------------------------------------------------------------------------
/src/server/mockData.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "image": "https://i2.au.reastatic.net/400x300/d735c9ef4a3fffe6c212a8008a89f97e1e465a64461489cd6cdadb855ad7ee0d/main.jpg",
4 | "address": "123 Fake street",
5 | "type": "house"
6 | },
7 | {
8 | "image": "https://i2.au.reastatic.net/400x300/78505655419944e4c58c753435a6f6b6ec8934641bc724570a07733db1a48067/main.jpg",
9 | "address": "123 Smith street",
10 | "type": "house"
11 | },
12 | {
13 | "image": "https://i2.au.reastatic.net/400x300/be36162503aca7ddc483b2ff184853a416b4c38673def09b420ab9eeb21f8fc8/main.jpg",
14 | "address": "12 George street",
15 | "type": "apartment"
16 | }
17 | ]
--------------------------------------------------------------------------------
/config/webpack.config.js:
--------------------------------------------------------------------------------
1 | const ExtractTextPlugin = require('extract-text-webpack-plugin');
2 | module.exports = {
3 | devtool: "#inline-source-map",
4 | "entry": "./src/client",
5 | module: {
6 | loaders: [
7 | {
8 | test: /\.js$/,
9 | loader: 'babel-loader'
10 | },
11 | {
12 | test: /\.json$/,
13 | loader: 'json-loader'
14 | },
15 | {
16 | test:/\.css$/,
17 | loader: ExtractTextPlugin.extract('style-loader','css-loader')
18 | }
19 | ]
20 | },
21 | plugins: [
22 | new ExtractTextPlugin('styles.css')
23 | ],
24 | "output": {
25 | path: './public',
26 | filename: 'bundle.js'
27 | }
28 | };
--------------------------------------------------------------------------------
/src/screens/app/Container.js:
--------------------------------------------------------------------------------
1 | // @flow
2 |
3 | import React, { Component } from 'react';
4 | import { connect } from 'react-redux';
5 | import Loader from './loading';
6 |
7 | type props = {
8 | apiData: {
9 | data: any,
10 | fetchingData: string
11 | }
12 | }
13 |
14 | export class App extends Component {
15 | shouldComponentUpdate (nextProps: props) {
16 | return !nextProps.apiData.fetchingData;
17 | }
18 |
19 | render () {
20 | return (
21 |
22 |
23 | { React.cloneElement(this.props.children, { data: this.props.apiData.data }) }
24 |
25 | );
26 | }
27 | }
28 |
29 | /*
30 | Connecting to the Redux store:
31 | http://redux.js.org/docs/basics/UsageWithReact.html#implementing-container-components
32 | */
33 |
34 | const mapStateToProps = ({ apiData }) => ({ apiData });
35 |
36 | export default connect(mapStateToProps)(App);
37 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # app-with-server-rendering
2 | A basic application that demonstrates server side rendering.
3 | Each individual commit has purposefully been crafted to explain the new code that's added and its purpose
4 | within the application.
5 |
6 | ## Requirements
7 | - [Node js (7.1)](https://nodejs.org/en/download/)
8 | - [NPM](https://www.npmjs.com/package/npm)
9 |
10 | ## Optional Requirements
11 | - [NVM](https://github.com/creationix/nvm) Node version manager
12 | - [Yarn package manager](https://yarnpkg.com/) An alternative to NPM
13 |
14 | NVM is a version manager for node which is a good option if you don't have node installed use NVM:
15 | > https://github.com/creationix/nvm/blob/master/README.markdown
16 |
17 | For a smoother experience with package management it is ideal to use `yarn`over NPM
18 | `npm install -g yarn`
19 |
20 | ## Prior to starting the application
21 | `npm install` or `yarn`
22 |
23 | ## Run the application
24 | `npm run start` or `yarn start`
25 |
26 | ## Develop the application
27 | `npm run dev` or `yarn dev`
28 | This will restart the server and recompile the client side assets whenever a file has been changed
29 | within the project
30 |
31 | ## Linting and Testing
32 | `npm run lint` or `yarn lint`
33 |
--------------------------------------------------------------------------------
/src/screens/results/Container.js:
--------------------------------------------------------------------------------
1 | // @flow
2 |
3 | import React, { Component } from 'react';
4 | import PropertyCard from '../../components/property-card';
5 | import { Link } from 'react-router';
6 | import type { Property } from '../../types/Property';
7 | import type { Fetch } from 'isomorphic-fetch';
8 |
9 | export default class Results extends Component {
10 | props: {
11 | data: Array
12 | }
13 |
14 | static fetchData (): Fetch {
15 | return new Promise((resolve) => {
16 | // Wait 1 second before making a request to simulate a poor connection.
17 | setTimeout(() => {
18 | fetch('http://localhost:3001/api')
19 | .then(response => response.json())
20 | .then(properties => resolve(properties))
21 | }, 1000);
22 | });
23 | }
24 |
25 | renderProperties () {
26 | return this.props.data.map((property: Property, key) => )
27 | }
28 |
29 | render () {
30 | return (
31 |
32 | Back to Home page
33 | { this.renderProperties() }
34 |
35 | );
36 | }
37 | }
38 |
39 |
--------------------------------------------------------------------------------
/src/screens/app/__tests__/Container.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { shallow } from 'enzyme';
3 | import { App } from '../Container';
4 | import Loader from '../loading';
5 |
6 | describe("App", () => {
7 | // In the context of an App screen it has a child of a sub-route (screen) this could be any component, lets just create one
8 | const Screen = ({ data }) => (
9 | {data}
10 | );
11 | // Lets simulate some API data
12 | const apiData = { data: 'Some API Data' };
13 | // Shallow Mount the component to a test variable so we may apply assertions on it ( we shallow mount as we don't care about the
14 | // Output of the child components
15 | const test = shallow(
16 |
17 |
18 |
19 | );
20 |
21 | it("renders the apps children with API data", () => {
22 | expect(test.contains([
23 | ,
24 |
25 | ])).toBe(true);
26 | });
27 |
28 | it("won't re-render fetchingData is true", () => {
29 | const newProps = {
30 | apiData: {
31 | fetchingData: true,
32 | data: 'Change me'
33 | }
34 | };
35 |
36 | // Calling setProps will assign the Component with the next set of props and trigger a re-render.
37 | test.setProps(newProps);
38 | expect(test.contains([ ])).toBe(true);
39 | });
40 | });
41 |
--------------------------------------------------------------------------------
/src/client/index.js:
--------------------------------------------------------------------------------
1 | import '../shared/polyfills';
2 | import {browserHistory, Router, match} from 'react-router';
3 | import React from 'react';
4 | import reactDOM from 'react-dom';
5 | import routes from '../shared/routes';
6 | import {Provider} from 'react-redux';
7 | import {createStore} from 'redux';
8 | import reducers from '../screens/reducers';
9 | import fetchData from '../shared/fetchData';
10 | import {DATA_LOADED, DATA_FETCHING} from '../screens/app/actions';
11 |
12 | export default (() => {
13 | // Create a store from hydrated data that was populated by the server.
14 | const store = createStore(reducers, {apiData: {data: window.__hydrationData__}});
15 | // Create an instance of our application
16 | const application = (
17 |
18 |
19 |
20 | );
21 |
22 | // Render the application into the DOM
23 | reactDOM.render(application, document.getElementById("wrapper"));
24 |
25 | // Listen to URL changes in the browser
26 | browserHistory.listen(location => {
27 | // Match the URL we listened to, to one of our routes
28 | match({location, routes}, (error, redirectLocation, routingState) => {
29 | // Dispatch an action to our store that we are fetching data, we block re-rendering within the app screen
30 | // Until the next set of data comes back because as soon as this callback finishes react router will render the
31 | // Next matched route, we stop this behaviour until the asynchronous route has finished fetching data.
32 | store.dispatch({type: DATA_FETCHING});
33 |
34 | // After we have the active route we execute the fetchData method via the fetchData Module
35 | fetchData(routingState).then(data => {
36 |
37 | // Dispatch the data to our store so the screens can now render.
38 | store.dispatch({type: DATA_LOADED, data});
39 | });
40 | });
41 | });
42 | })();
43 |
--------------------------------------------------------------------------------
/src/server/middleware.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOMServer from 'react-dom/server';
3 | import { RouterContext, match } from 'react-router';
4 | import { Provider } from 'react-redux';
5 | import { createStore } from 'redux';
6 | import reducers from '../screens/reducers';
7 | import routes from '../shared/routes';
8 | import fetchData from '../shared/fetchData';
9 |
10 | import page, { error as errorPage } from './pages';
11 |
12 | export default (request, response) => {
13 | // Match the URL to a route
14 | match({location: request.url, routes}, (_, redirect, routingState) => {
15 |
16 | // Handle a URL that matches a redirect
17 | if (redirect) {
18 | response.redirect(redirect.pathname + redirect.search);
19 | }
20 |
21 | // Handle any route we don't have a screen for
22 | if (!routingState) {
23 | return response.status(404).send(errorPage(` 404 `));
24 | }
25 |
26 | // After we have the active route we execute the fetchData method via the fetchData Module
27 | fetchData(routingState).then(data => {
28 |
29 | // Render the application to a string
30 | const applicationString = ReactDOMServer.renderToString(
31 | // Set the initial state of the store to the data that came back from the API
32 |
33 |
34 |
35 | );
36 |
37 | // Place the application within the page template
38 | const pageResponse = page(applicationString, data);
39 |
40 | // Return the response to the browser.
41 | return response.status(200).send(pageResponse);
42 |
43 | })
44 | .catch(error => {
45 |
46 | /* eslint-disable no-console */
47 | console.log(error);
48 |
49 | // If there is a run time error that bubbles up from fetchData, catch it and return a 500
50 | return response.status(500).send(errorPage(` 500 `));
51 | });
52 | });
53 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "app-with-server-rendering",
3 | "version": "0.0.1",
4 | "description": "A basic application that demonstrates serverside rendering",
5 | "repository": "git@github.com:azaharakis/app-with-server-rendering.git",
6 | "author": "Alexander Zaharakis ",
7 | "license": "MIT",
8 | "scripts": {
9 | "build": "webpack --config=./config/webpack.config.js",
10 | "start": "npm run build && node ./src/app.js",
11 | "watch": "webpack --watch --config=./config/webpack.config.js",
12 | "dev": "concurrently 'npm run watch' 'forever --watch ./src/app.js'",
13 | "lint": "eslint ./src",
14 | "flow": "flow; test $? -eq 0 -o $? -eq 2",
15 | "unit": "jest test",
16 | "unit-watch": "jest test --watch",
17 | "test": "npm run lint && npm run flow && npm run unit"
18 | },
19 | "dependencies": {
20 | "babel-preset-env": "^1.1.4",
21 | "babel-preset-react": "^6.16.0",
22 | "babel-preset-stage-2": "^6.18.0",
23 | "babel-register": "^6.18.0",
24 | "es6-promise": "^4.0.5",
25 | "express": "^4.14.0",
26 | "isomorphic-fetch": "^2.2.1",
27 | "react": "^15.4.1",
28 | "react-dom": "^15.4.1",
29 | "react-redux": "^5.0.1",
30 | "react-router": "^3.0.0",
31 | "redux": "^3.6.0"
32 | },
33 | "devDependencies": {
34 | "babel-core": "^6.21.0",
35 | "babel-eslint": "^7.1.1",
36 | "babel-jest": "^18.0.0",
37 | "babel-loader": "^6.2.10",
38 | "concurrently": "^3.1.0",
39 | "css-loader": "^0.26.1",
40 | "enzyme": "^2.7.0",
41 | "eslint": "^3.12.2",
42 | "eslint-plugin-flowtype": "^2.29.2",
43 | "eslint-plugin-react": "^6.8.0",
44 | "extract-text-webpack-plugin": "^1.0.1",
45 | "flow-bin": "^0.37.4",
46 | "forever": "^0.15.3",
47 | "jest": "^18.1.0",
48 | "json-loader": "^0.5.4",
49 | "react-addons-test-utils": "^15.4.1",
50 | "style-loader": "^0.13.1",
51 | "webpack": "^1.14.0"
52 | },
53 | "jest": {
54 | "moduleNameMapper": {
55 | "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "/__mocks__/fileMock.js",
56 | "\\.(css)$": "/__mocks__/styleMock.js"
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "env": {
3 | "browser": true,
4 | "commonjs": true,
5 | "es6": true,
6 | "node": true,
7 | "jest": true
8 | },
9 | "extends": [
10 | "eslint:recommended",
11 | "plugin:flowtype/recommended"
12 | ],
13 | "parserOptions": {
14 | "ecmaFeatures": {
15 | "experimentalObjectRestSpread": true,
16 | "jsx": true
17 | },
18 | "sourceType": "module"
19 | },
20 | "plugins": [
21 | "react",
22 | "flowtype"
23 | ],
24 | "rules": {
25 | "react/jsx-uses-react": "error",
26 | "react/jsx-uses-vars": "error",
27 | "accessor-pairs": "error",
28 | "array-bracket-spacing": "error",
29 | "array-callback-return": "error",
30 | "arrow-spacing": [
31 | "error",
32 | {
33 | "after": true,
34 | "before": true
35 | }
36 | ],
37 | "block-scoped-var": "error",
38 | "block-spacing": "error",
39 | "brace-style": "error",
40 | "callback-return": "error",
41 | "camelcase": "error",
42 | "capitalized-comments": "error",
43 | "comma-dangle": "error",
44 | "comma-spacing": [
45 | "error",
46 | {
47 | "after": true,
48 | "before": false
49 | }
50 | ],
51 | "comma-style": "error",
52 | "complexity": "error",
53 | "computed-property-spacing": "error",
54 | "consistent-this": "error",
55 | "curly": "error",
56 | "default-case": "error",
57 | "dot-notation": [
58 | "error",
59 | {
60 | "allowKeywords": true
61 | }
62 | ],
63 | "eol-last": "off",
64 | "eqeqeq": "error",
65 | "func-call-spacing": "error",
66 | "func-name-matching": "error",
67 | "func-names": "error",
68 | "func-style": "error",
69 | "generator-star-spacing": "error",
70 | "global-require": "error",
71 | "guard-for-in": "error",
72 | "handle-callback-err": "error",
73 | "id-blacklist": "error",
74 | "id-match": "error",
75 | "indent": [
76 | "error",
77 | 4,
78 | {
79 | "SwitchCase":1
80 | }
81 | ],
82 | "init-declarations": "error",
83 | "jsx-quotes": "error",
84 | "key-spacing": "error",
85 | "keyword-spacing": "error",
86 | "line-comment-position": "error",
87 | "linebreak-style": [
88 | "error",
89 | "unix"
90 | ],
91 | "lines-around-comment": "error",
92 | "lines-around-directive": "error",
93 | "max-depth": "error",
94 | "max-len": "off",
95 | "max-lines": "error",
96 | "max-nested-callbacks": "error",
97 | "max-params": "error",
98 | "max-statements": "error",
99 | "max-statements-per-line": "error",
100 | "new-cap": "error",
101 | "new-parens": "error",
102 | "newline-after-var": [
103 | "error",
104 | "always"
105 | ],
106 | "newline-before-return": "error",
107 | "newline-per-chained-call": "error",
108 | "no-alert": "error",
109 | "no-array-constructor": "error",
110 | "no-await-in-loop": "error",
111 | "no-bitwise": "error",
112 | "no-caller": "error",
113 | "no-catch-shadow": "error",
114 | "no-confusing-arrow": "error",
115 | "no-continue": "error",
116 | "no-div-regex": "error",
117 | "no-duplicate-imports": "error",
118 | "no-else-return": "error",
119 | "no-empty-function": "error",
120 | "no-eq-null": "error",
121 | "no-eval": "error",
122 | "no-extend-native": "error",
123 | "no-extra-bind": "error",
124 | "no-extra-label": "error",
125 | "no-floating-decimal": "error",
126 | "no-implicit-coercion": "error",
127 | "no-implicit-globals": "error",
128 | "no-implied-eval": "error",
129 | "no-inline-comments": "error",
130 | "no-invalid-this": "error",
131 | "no-iterator": "error",
132 | "no-label-var": "error",
133 | "no-labels": "error",
134 | "no-lone-blocks": "error",
135 | "no-lonely-if": "error",
136 | "no-loop-func": "error",
137 | "no-magic-numbers": "off",
138 | "no-mixed-operators": "error",
139 | "no-mixed-requires": "error",
140 | "no-multi-spaces": "error",
141 | "no-multi-str": "error",
142 | "no-multiple-empty-lines": "error",
143 | "no-native-reassign": "error",
144 | "no-negated-condition": "error",
145 | "no-negated-in-lhs": "error",
146 | "no-nested-ternary": "error",
147 | "no-new": "error",
148 | "no-new-func": "error",
149 | "no-new-object": "error",
150 | "no-new-require": "error",
151 | "no-new-wrappers": "error",
152 | "no-octal-escape": "error",
153 | "no-param-reassign": "error",
154 | "no-path-concat": "error",
155 | "no-plusplus": "error",
156 | "no-process-env": "off",
157 | "no-process-exit": "error",
158 | "no-proto": "error",
159 | "no-prototype-builtins": "error",
160 | "no-restricted-globals": "error",
161 | "no-restricted-imports": "error",
162 | "no-restricted-modules": "error",
163 | "no-restricted-properties": "error",
164 | "no-restricted-syntax": "error",
165 | "no-return-assign": "error",
166 | "no-return-await": "error",
167 | "no-script-url": "error",
168 | "no-self-compare": "error",
169 | "no-sequences": "error",
170 | "no-shadow": "error",
171 | "no-shadow-restricted-names": "error",
172 | "no-spaced-func": "error",
173 | "no-sync": "error",
174 | "no-tabs": "error",
175 | "no-template-curly-in-string": "error",
176 | "no-throw-literal": "error",
177 | "no-trailing-spaces": "error",
178 | "no-undef-init": "error",
179 | "no-undefined": "error",
180 | "no-unmodified-loop-condition": "error",
181 | "no-unneeded-ternary": "error",
182 | "no-unused-expressions": "error",
183 | "no-use-before-define": "error",
184 | "no-useless-call": "error",
185 | "no-useless-computed-key": "error",
186 | "no-useless-concat": "error",
187 | "no-useless-constructor": "error",
188 | "no-useless-escape": "error",
189 | "no-useless-rename": "error",
190 | "no-useless-return": "error",
191 | "no-var": "error",
192 | "no-void": "error",
193 | "no-warning-comments": "error",
194 | "no-whitespace-before-property": "error",
195 | "no-with": "error",
196 | "object-curly-newline": "error",
197 | "object-shorthand": "error",
198 | "one-var": "off",
199 | "one-var-declaration-per-line": "error",
200 | "operator-assignment": "error",
201 | "operator-linebreak": "error",
202 | "padded-blocks": "off",
203 | "prefer-arrow-callback": "error",
204 | "prefer-const": "error",
205 | "prefer-numeric-literals": "error",
206 | "prefer-reflect": "error",
207 | "prefer-rest-params": "error",
208 | "prefer-spread": "error",
209 | "prefer-template": "error",
210 | "quotes": "off",
211 | "radix": "error",
212 | "require-await": "error",
213 | "require-jsdoc": "error",
214 | "rest-spread-spacing": "error",
215 | "semi": "off",
216 | "semi-spacing": "error",
217 | "sort-imports": "off",
218 | "sort-vars": "error",
219 | "space-before-blocks": "error",
220 | "space-before-function-paren": "error",
221 | "space-in-parens": [
222 | "error",
223 | "never"
224 | ],
225 | "space-infix-ops": "error",
226 | "space-unary-ops": "error",
227 | "spaced-comment": "error",
228 | "strict": "error",
229 | "symbol-description": "error",
230 | "template-curly-spacing": [
231 | "error",
232 | "never"
233 | ],
234 | "unicode-bom": [
235 | "error",
236 | "never"
237 | ],
238 | "valid-jsdoc": "error",
239 | "vars-on-top": "error",
240 | "wrap-iife": "error",
241 | "wrap-regex": "error",
242 | "yield-star-spacing": "error",
243 | "yoda": "error"
244 | },
245 | };
--------------------------------------------------------------------------------