├── .nvmrc
├── .npmrc
├── .eslintignore
├── public
├── robots.txt
├── favicon.ico
├── favicons
│ ├── favicon-128.png
│ ├── mstile-70x70.png
│ ├── favicon-16x16.png
│ ├── favicon-196x196.png
│ ├── favicon-32x32.png
│ ├── favicon-96x96.png
│ ├── mstile-144x144.png
│ ├── mstile-150x150.png
│ ├── mstile-310x150.png
│ ├── mstile-310x310.png
│ ├── android-chrome-192x192.png
│ ├── android-chrome-512x512.png
│ ├── apple-touch-icon-57x57.png
│ ├── apple-touch-icon-60x60.png
│ ├── apple-touch-icon-72x72.png
│ ├── apple-touch-icon-76x76.png
│ ├── apple-touch-icon-114x114.png
│ ├── apple-touch-icon-120x120.png
│ ├── apple-touch-icon-144x144.png
│ ├── apple-touch-icon-152x152.png
│ ├── apple-touch-icon-180x180.png
│ └── safari-pinned-tab.svg
├── browserconfig.xml
└── manifest.json
├── internal
├── jest
│ ├── assetMock.js
│ └── styleMock.js
├── scripts
│ ├── deploy.js
│ ├── clean.js
│ ├── build.js
│ ├── preinstall.js
│ └── analyze.js
├── .eslintrc
├── docs
│ ├── ADDING_AN_API_BUNDLE.md
│ ├── DEPLOY_TO_NOW.md
│ ├── PKG_SCRIPTS.md
│ ├── FEATURE_BRANCHES.md
│ ├── FAQ.md
│ ├── PROJECT_OVERVIEW.md
│ └── PROJECT_CONFIG.md
├── webpack
│ ├── withServiceWorker
│ │ ├── offlinePageTemplate.js
│ │ └── index.js
│ └── configFactory.js
├── utils.js
└── development
│ ├── index.js
│ ├── listenerManager.js
│ ├── hotClientServer.js
│ ├── hotNodeServer.js
│ ├── hotDevelopment.js
│ └── createVendorDLL.js
├── .modernizrrc
├── shared
├── utils
│ ├── logic
│ │ ├── index.js
│ │ ├── ifElse.js
│ │ └── __tests__
│ │ │ └── ifElse.test.js
│ ├── arrays
│ │ ├── index.js
│ │ ├── removeNil.js
│ │ └── __tests__
│ │ │ └── removeNil.test.js
│ └── objects
│ │ ├── index.js
│ │ ├── __tests__
│ │ ├── mergeDeep.test.js
│ │ └── filterWithRules.test.js
│ │ ├── mergeDeep.js
│ │ └── filterWithRules.js
├── components
│ ├── DemoApp
│ │ ├── Header
│ │ │ ├── Logo
│ │ │ │ ├── logo.png
│ │ │ │ └── index.js
│ │ │ ├── Menu
│ │ │ │ ├── __tests__
│ │ │ │ │ ├── Menu.test.js
│ │ │ │ │ └── __snapshots__
│ │ │ │ │ │ └── Menu.test.js.snap
│ │ │ │ └── index.js
│ │ │ └── index.js
│ │ ├── Error404
│ │ │ ├── __tests__
│ │ │ │ ├── __snapshots__
│ │ │ │ │ └── Error404.test.js.snap
│ │ │ │ └── Error404.test.js
│ │ │ └── index.js
│ │ ├── AsyncCounterRoute
│ │ │ ├── index.js
│ │ │ └── CounterRoute.js
│ │ ├── AsyncAboutRoute
│ │ │ ├── index.js
│ │ │ ├── __tests__
│ │ │ │ ├── AboutRoute.test.js
│ │ │ │ └── __snapshots__
│ │ │ │ │ └── AboutRoute.test.js.snap
│ │ │ └── AboutRoute.js
│ │ ├── AsyncHomeRoute
│ │ │ ├── index.js
│ │ │ ├── __tests__
│ │ │ │ ├── HomeRoute.test.js
│ │ │ │ └── __snapshots__
│ │ │ │ │ └── HomeRoute.test.js.snap
│ │ │ └── HomeRoute.js
│ │ ├── globals.css
│ │ └── index.js
│ └── HTML
│ │ └── index.js
└── README.md
├── server
├── middleware
│ ├── clientBundle.js
│ ├── serviceWorker.js
│ ├── errorHandlers.js
│ ├── offlinePage.js
│ ├── reactApplication
│ │ ├── getClientBundleEntryAssets.js
│ │ ├── index.js
│ │ └── ServerHTML.js
│ └── security.js
└── index.js
├── client
├── components
│ └── ReactHotLoader.js
├── polyfills
│ └── index.js
├── registerServiceWorker.js
└── index.js
├── .babelrc
├── .editorconfig
├── .gitignore
├── .eslintrc
├── .env_example
├── LICENSE
├── config
├── components
│ └── ClientConfig.js
├── utils
│ └── envVars.js
├── index.js
└── values.js
├── package.json
├── .all-contributorsrc
└── README.md
/.nvmrc:
--------------------------------------------------------------------------------
1 | v6.11.1
2 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | save-exact = true
2 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | build/
3 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | User-agent: *
2 | Allow: /
3 |
--------------------------------------------------------------------------------
/internal/jest/assetMock.js:
--------------------------------------------------------------------------------
1 | module.exports = '/asset/mock';
2 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ctrlplusb/react-universally/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/.modernizrrc:
--------------------------------------------------------------------------------
1 | {
2 | "minify": true,
3 | "options": [],
4 | "feature-detects": [
5 | "elem/picture"
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/public/favicons/favicon-128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ctrlplusb/react-universally/HEAD/public/favicons/favicon-128.png
--------------------------------------------------------------------------------
/public/favicons/mstile-70x70.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ctrlplusb/react-universally/HEAD/public/favicons/mstile-70x70.png
--------------------------------------------------------------------------------
/public/favicons/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ctrlplusb/react-universally/HEAD/public/favicons/favicon-16x16.png
--------------------------------------------------------------------------------
/public/favicons/favicon-196x196.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ctrlplusb/react-universally/HEAD/public/favicons/favicon-196x196.png
--------------------------------------------------------------------------------
/public/favicons/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ctrlplusb/react-universally/HEAD/public/favicons/favicon-32x32.png
--------------------------------------------------------------------------------
/public/favicons/favicon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ctrlplusb/react-universally/HEAD/public/favicons/favicon-96x96.png
--------------------------------------------------------------------------------
/public/favicons/mstile-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ctrlplusb/react-universally/HEAD/public/favicons/mstile-144x144.png
--------------------------------------------------------------------------------
/public/favicons/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ctrlplusb/react-universally/HEAD/public/favicons/mstile-150x150.png
--------------------------------------------------------------------------------
/public/favicons/mstile-310x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ctrlplusb/react-universally/HEAD/public/favicons/mstile-310x150.png
--------------------------------------------------------------------------------
/public/favicons/mstile-310x310.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ctrlplusb/react-universally/HEAD/public/favicons/mstile-310x310.png
--------------------------------------------------------------------------------
/public/favicons/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ctrlplusb/react-universally/HEAD/public/favicons/android-chrome-192x192.png
--------------------------------------------------------------------------------
/public/favicons/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ctrlplusb/react-universally/HEAD/public/favicons/android-chrome-512x512.png
--------------------------------------------------------------------------------
/public/favicons/apple-touch-icon-57x57.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ctrlplusb/react-universally/HEAD/public/favicons/apple-touch-icon-57x57.png
--------------------------------------------------------------------------------
/public/favicons/apple-touch-icon-60x60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ctrlplusb/react-universally/HEAD/public/favicons/apple-touch-icon-60x60.png
--------------------------------------------------------------------------------
/public/favicons/apple-touch-icon-72x72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ctrlplusb/react-universally/HEAD/public/favicons/apple-touch-icon-72x72.png
--------------------------------------------------------------------------------
/public/favicons/apple-touch-icon-76x76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ctrlplusb/react-universally/HEAD/public/favicons/apple-touch-icon-76x76.png
--------------------------------------------------------------------------------
/public/favicons/apple-touch-icon-114x114.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ctrlplusb/react-universally/HEAD/public/favicons/apple-touch-icon-114x114.png
--------------------------------------------------------------------------------
/public/favicons/apple-touch-icon-120x120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ctrlplusb/react-universally/HEAD/public/favicons/apple-touch-icon-120x120.png
--------------------------------------------------------------------------------
/public/favicons/apple-touch-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ctrlplusb/react-universally/HEAD/public/favicons/apple-touch-icon-144x144.png
--------------------------------------------------------------------------------
/public/favicons/apple-touch-icon-152x152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ctrlplusb/react-universally/HEAD/public/favicons/apple-touch-icon-152x152.png
--------------------------------------------------------------------------------
/public/favicons/apple-touch-icon-180x180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ctrlplusb/react-universally/HEAD/public/favicons/apple-touch-icon-180x180.png
--------------------------------------------------------------------------------
/shared/utils/logic/index.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/prefer-default-export */
2 |
3 | import ifElse from './ifElse';
4 |
5 | export { ifElse };
6 |
--------------------------------------------------------------------------------
/internal/jest/styleMock.js:
--------------------------------------------------------------------------------
1 | // internal/test/styleMock.js
2 | // Return an object to emulate css modules (if you are using them)
3 | module.exports = {};
4 |
--------------------------------------------------------------------------------
/shared/components/DemoApp/Header/Logo/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ctrlplusb/react-universally/HEAD/shared/components/DemoApp/Header/Logo/logo.png
--------------------------------------------------------------------------------
/shared/utils/arrays/index.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/prefer-default-export */
2 |
3 | import removeNil from './removeNil';
4 |
5 | export { removeNil };
6 |
--------------------------------------------------------------------------------
/shared/utils/objects/index.js:
--------------------------------------------------------------------------------
1 | import filterWithRules from './filterWithRules';
2 | import mergeDeep from './mergeDeep';
3 |
4 | export { filterWithRules, mergeDeep };
5 |
--------------------------------------------------------------------------------
/internal/scripts/deploy.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Deploys to now.
3 | * @see https://zeit.co/now
4 | */
5 |
6 | import { exec } from '../utils';
7 | const cmd = 'now';
8 | exec(cmd);
9 |
--------------------------------------------------------------------------------
/shared/README.md:
--------------------------------------------------------------------------------
1 | # src/shared
2 |
3 | This directory contains code that is shared between our bundles and should be considered safe to execute on either a `node` or `web` target (i.e. "Universal" code).
4 |
--------------------------------------------------------------------------------
/shared/components/DemoApp/Error404/__tests__/__snapshots__/Error404.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`
Produced with ❤️
12 | 13 |14 | View our contributors list on our 15 | {' '} 16 | GitHub 17 | {' '} 18 | page. 19 |
20 |17 | This starter kit contains all the build tooling and configuration you need to kick off your next universal React project, whilst containing a minimal project set up allowing you to make your own architecture decisions (Redux/Mobx etc). 18 |
19 |20 | Produced with ❤️ 21 |
22 |23 | View our contributors list on our 24 | 25 | 28 | GitHub 29 | 30 | 31 | page. 32 |
33 |16 | This starter kit contains all the build tooling and configuration you 17 | need to kick off your next universal React project, whilst containing a 18 | minimal project set up allowing you to make your own architecture 19 | decisions (Redux/Mobx etc). 20 |
21 |} />, 18 | ); 19 | return `${html}`; 20 | }; 21 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "React Universally", 3 | "short_name": "Rct-Unvrslly", 4 | "description": "A starter kit giving you the minimum requirements for a production ready universal react application.", 5 | "lang": "en", 6 | "start_url": "./", 7 | "icons": [ 8 | { 9 | "src": "\/android-chrome-512x512.png", 10 | "sizes": "512x512", 11 | "type": "image\/png" 12 | }, 13 | { 14 | "src": "\/android-chrome-192x192.png", 15 | "sizes": "192x192", 16 | "type": "image\/png" 17 | }, 18 | { 19 | "src": "\/apple-touch-icon.png", 20 | "sizes": "180x180", 21 | "type": "image\/png" 22 | }, 23 | { 24 | "src": "\/favicon-32x32.png", 25 | "sizes": "32x32", 26 | "type": "image\/png" 27 | }, 28 | { 29 | "src": "\/favicon-16x16.png", 30 | "sizes": "16x16", 31 | "type": "image\/png" 32 | } 33 | ], 34 | "theme_color": "#2b2b2b", 35 | "background_color": "#ffffff", 36 | "display": "standalone" 37 | } 38 | -------------------------------------------------------------------------------- /shared/utils/logic/ifElse.js: -------------------------------------------------------------------------------- 1 | const execIfFunc = x => (typeof x === 'function' ? x() : x); 2 | 3 | /** 4 | * This is a higher order function that accepts a boolean condition and will 5 | * return a function allowing you to provide if/else values that should be 6 | * resolved based on the boolean condition. 7 | * 8 | * @param {Boolean|() => Boolean} condition: 9 | * The condition to test against. This can be a function for lazy resolution. 10 | * 11 | * @return {(X|() => X, Y|() => Y) => X|Y} 12 | * A function where the first paramater is the "if" and the second paramater 13 | * is the "else". Each of these allows lazy resolving by providing a function. 14 | * 15 | * @example 16 | * const ifDev = ifElse(process.env.NODE_ENV === 'development'); 17 | * ifDev('foo', () => 'lazy resolved'); // => 'foo' 18 | */ 19 | export default function ifElse(condition) { 20 | return (then, or) => (execIfFunc(condition) ? execIfFunc(then) : execIfFunc(or)); 21 | } 22 | -------------------------------------------------------------------------------- /shared/utils/objects/__tests__/mergeDeep.test.js: -------------------------------------------------------------------------------- 1 | import { mergeDeep } from '../'; 2 | 3 | describe('mergeDeep', () => { 4 | test('merges deeply two objects together', () => { 5 | const object1 = { a: 1, b: 2, c: { a: 1, b: 2 } }; 6 | const object2 = { a: 1, c: { c: 3 } }; 7 | expect(mergeDeep(object1, object2)).toEqual({ 8 | a: 1, 9 | b: 2, 10 | c: { 11 | a: 1, 12 | b: 2, 13 | c: 3, 14 | }, 15 | }); 16 | }); 17 | 18 | test('the object to the right takes the priority', () => { 19 | const object1 = { a: 1, b: 2 }; 20 | const object2 = { a: 1, b: 3 }; 21 | expect(mergeDeep(object1, object2)).toEqual({ 22 | a: 1, 23 | b: 3, 24 | }); 25 | }); 26 | 27 | test('returns an empty object if no args are given', () => { 28 | expect(mergeDeep()).toEqual({}); 29 | }); 30 | 31 | test('returns the only object given as arg if no other args are given', () => { 32 | expect(mergeDeep({ a: 1 })).toEqual({ a: 1 }); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /shared/utils/objects/mergeDeep.js: -------------------------------------------------------------------------------- 1 | import removeNil from '../arrays/removeNil'; 2 | 3 | /** 4 | * Deeply merges a given set of objects together. 5 | * 6 | * Objects to the right take priority. 7 | * 8 | * @param {...Object} args - The objects to merge. 9 | * 10 | * @return {Object} - The merged object. 11 | */ 12 | export default function mergeDeep(...args) { 13 | const filtered = removeNil(args); 14 | if (filtered.length < 1) { 15 | return {}; 16 | } 17 | if (filtered.length === 1) { 18 | return args[0]; 19 | } 20 | return filtered.reduce( 21 | (acc, cur) => { 22 | Object.keys(cur).forEach((key) => { 23 | if (typeof acc[key] === 'object' && typeof cur[key] === 'object') { 24 | // eslint-disable-next-line no-param-reassign 25 | acc[key] = mergeDeep(acc[key], cur[key]); 26 | } else { 27 | // eslint-disable-next-line no-param-reassign 28 | acc[key] = cur[key]; 29 | } 30 | }); 31 | return acc; 32 | }, 33 | {}, 34 | ); 35 | } 36 | -------------------------------------------------------------------------------- /shared/components/DemoApp/AsyncCounterRoute/CounterRoute.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable react/no-unescaped-entities */ 2 | import React, { Component } from 'react'; 3 | 4 | class CounterRoute extends Component { 5 | constructor(props) { 6 | super(props); 7 | this.incrementCounter = this.incrementCounter.bind(this); 8 | this.state = { counter: 0 }; 9 | } 10 | 11 | incrementCounter() { 12 | this.setState({ counter: this.state.counter + 1 }); 13 | } 14 | 15 | render() { 16 | return ( 17 |
20 | 21 | This is a small demo component that contains state. It's useful for 22 | testing the hot reloading experience of an asyncComponent. 23 | 24 |
25 |26 | Current value: {this.state.counter} 27 |
28 |29 | 30 |
31 |32 | ); 33 | } 34 | } 35 | 36 | export default CounterRoute; 37 | -------------------------------------------------------------------------------- /shared/components/HTML/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable react/no-danger */ 2 | /* eslint-disable jsx-a11y/html-has-lang */ 3 | 4 | import React from 'react'; 5 | import PropTypes from 'prop-types'; 6 | 7 | /** 8 | * The is the HTML shell for our React Application. 9 | */ 10 | function HTML(props) { 11 | const { htmlAttributes, headerElements, bodyElements, appBodyString } = props; 12 | 13 | return ( 14 | 15 |
16 | {headerElements} 17 | 18 |