From 487f19bd3c793df0841827d12aa2d718f63f654d Mon Sep 17 00:00:00 2001
From: Konstantin Tarkus
Date: Mon, 24 Apr 2017 21:26:00 +0300
Subject: [PATCH 1/6] Initialize a new HTTP client for each web request
---
LICENSE.txt | 2 +-
docs/data-fetching.md | 4 +-
docs/getting-started.md | 4 +-
docs/recipes/how-to-implement-routing.md | 24 +--
package.json | 44 ++---
src/{core => }/DOMUtils.js | 0
src/client.js | 18 +-
src/components/App.js | 2 +
src/components/Html.js | 23 ++-
src/components/Link/Link.js | 2 +-
src/config.js | 73 ++++---
src/core/fetch/fetch.client.js | 15 --
src/core/fetch/fetch.server.js | 33 ----
src/core/fetch/package.json | 6 -
src/createFetch.js | 34 ++++
src/data/queries/news.js | 6 +-
src/data/sequelize.js | 4 +-
src/{core => }/devUtils.js | 0
src/{core => }/history.js | 0
src/{core => }/passport.js | 8 +-
src/{core => }/router.js | 2 +-
src/routes/home/index.js | 9 +-
src/server.js | 30 +--
yarn.lock | 236 +++++++++++------------
24 files changed, 282 insertions(+), 297 deletions(-)
rename src/{core => }/DOMUtils.js (100%)
delete mode 100644 src/core/fetch/fetch.client.js
delete mode 100644 src/core/fetch/fetch.server.js
delete mode 100644 src/core/fetch/package.json
create mode 100644 src/createFetch.js
rename src/{core => }/devUtils.js (100%)
rename src/{core => }/history.js (100%)
rename src/{core => }/passport.js (95%)
rename src/{core => }/router.js (91%)
diff --git a/LICENSE.txt b/LICENSE.txt
index 3e95f03c6..2e4e7b16b 100644
--- a/LICENSE.txt
+++ b/LICENSE.txt
@@ -1,6 +1,6 @@
The MIT License
-Copyright (c) 2014-present Konstantin Tarkus, KriaSoft LLC.
+Copyright (c) 2014-present Konstantin Tarkus, Kriasoft LLC.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/docs/data-fetching.md b/docs/data-fetching.md
index b7a3ffc6d..af24768d6 100644
--- a/docs/data-fetching.md
+++ b/docs/data-fetching.md
@@ -4,10 +4,8 @@ There is isomorphic `core/fetch` module that can be used the same way in both
client-side and server-side code as follows:
```jsx
-import fetch from '../core/fetch';
-
export const path = '/products';
-export const action = async () => {
+export const action = async ({ fetch }) => {
const response = await fetch('/graphql?query={products{id,name}}');
const data = await response.json();
return ;
diff --git a/docs/getting-started.md b/docs/getting-started.md
index 171db6912..c288d12b5 100644
--- a/docs/getting-started.md
+++ b/docs/getting-started.md
@@ -18,12 +18,12 @@ Before you start, take a moment to see how the project structure looks like:
├── /public/ # Static files which are copied into the /build/public folder
├── /src/ # The source code of the application
│ ├── /components/ # React components
-│ ├── /core/ # Core framework and utility functions
│ ├── /data/ # GraphQL server schema and data models
│ ├── /routes/ # Page/screen components along with the routing information
│ ├── /client.js # Client-side startup script
│ ├── /config.js # Global application settings
-│ └── /server.js # Server-side startup script
+│ ├── /server.js # Server-side startup script
+│ └── ... # Other core framework modules
├── /test/ # Unit and end-to-end tests
├── /tools/ # Build automation scripts and utilities
│ ├── /lib/ # Library for utility snippets
diff --git a/docs/recipes/how-to-implement-routing.md b/docs/recipes/how-to-implement-routing.md
index 496523caa..6493b9ca9 100644
--- a/docs/recipes/how-to-implement-routing.md
+++ b/docs/recipes/how-to-implement-routing.md
@@ -4,7 +4,7 @@ Let's see how a custom routing solution under 100 lines of code may look like.
First, you will need to implement the **list of application routes** in which each route can be
represented as an object with properties of `path` (a parametrized URL path string), `action`
-(a function), and optionally `children` (a list of sub-routes, each of which is a route object).
+(a function), and optionally `children` (a list of sub-routes, each of which is a route object).
The `action` function returns anything - a string, a React component, etc. For example:
#### `src/routes/index.js`
@@ -42,7 +42,7 @@ return `{ id: '123' }` while calling `matchURI('/tasks/:id', '/foo')` must retur
Fortunately, there is a great library called [`path-to-regexp`](https://github.com/pillarjs/path-to-regexp)
that makes this task very easy. Here is how a URL matcher function may look like:
-#### `src/core/router.js`
+#### `src/router.js`
```js
import toRegExp from 'path-to-regexp';
@@ -67,7 +67,7 @@ action method returns anything other than `null` or `undefined` return that to t
Otherwise, it should continue iterating over the remaining routes. If none of the routes match to the
provided URL string, it should throw an exception (Not found). Here is how this function may look like:
-#### `src/core/router.js`
+#### `src/router.js`
```js
import toRegExp from 'path-to-regexp';
@@ -93,12 +93,12 @@ export default { resolve };
That's it! Here is a usage example:
```js
-import router from './core/router';
+import router from './router';
import routes from './routes';
router.resolve(routes, { pathname: '/tasks' }).then(result => {
console.log(result);
- // => { title: 'To-do', component: }
+ // => { title: 'To-do', component: }
});
```
@@ -108,10 +108,10 @@ npm module to handles this task for you. It is the same library used in React Ro
wrapper over [HTML5 History API](https://developer.mozilla.org/docs/Web/API/History_API) that
handles all the tricky browser compatibility issues related to client-side navigation.
-First, create `src/core/history.js` file that will initialize a new instance of the `history` module
+First, create `src/history.js` file that will initialize a new instance of the `history` module
and export is as a singleton:
-#### `src/core/history.js`
+#### `src/history.js`
```js
import createHistory from 'history/lib/createBrowserHistory';
@@ -125,8 +125,8 @@ Then plug it in, in your client-side bootstrap code as follows:
```js
import ReactDOM from 'react-dom';
-import history from './core/history';
-import router from './core/router';
+import history from './history';
+import router from './router';
import routes from './routes';
const container = document.getElementById('root');
@@ -157,7 +157,7 @@ In order to trigger client-side navigation without causing full-page refresh, yo
```js
import React from 'react';
-import history from '../core/history';
+import history from '../history';
class App extends React.Component {
transition = event => {
@@ -181,9 +181,9 @@ class App extends React.Component {
Though, it is a common practice to extract that transitioning functionality into a stand-alone
(`Link`) component that can be used as follows:
-
+
```html
-View Task #123
+View Task #123
```
### Routing in React Starter Kit
diff --git a/package.json b/package.json
index 2ee257935..200e580b2 100644
--- a/package.json
+++ b/package.json
@@ -21,36 +21,36 @@
"core-js": "^2.4.1",
"express": "^4.15.2",
"express-graphql": "^0.6.4",
- "express-jwt": "^5.1.0",
+ "express-jwt": "^5.3.0",
"fastclick": "^1.0.6",
- "graphql": "^0.9.2",
+ "graphql": "^0.9.3",
"history": "^4.6.1",
- "isomorphic-style-loader": "^1.1.0",
+ "isomorphic-fetch": "^2.2.1",
+ "isomorphic-style-loader": "^2.0.0",
"jsonwebtoken": "^7.3.0",
- "node-fetch": "^1.6.3",
"normalize.css": "^6.0.0",
"passport": "^0.3.2",
"passport-facebook": "^2.1.1",
"pretty-error": "^2.1.0",
- "prop-types": "^15.5.6",
- "query-string": "^4.3.2",
- "react": "^15.5.3",
- "react-dom": "^15.5.3",
+ "prop-types": "^15.5.8",
+ "query-string": "^4.3.4",
+ "react": "^15.5.4",
+ "react-dom": "^15.5.4",
"sequelize": "^3.30.4",
+ "serialize-javascript": "^1.3.0",
"source-map-support": "^0.4.14",
"sqlite3": "^3.1.8",
- "universal-router": "^3.0.0",
- "whatwg-fetch": "^2.0.3"
+ "universal-router": "^3.1.0"
},
"devDependencies": {
"assets-webpack-plugin": "^3.5.1",
"autoprefixer": "^6.7.7",
"babel-cli": "^6.24.1",
"babel-core": "^6.24.1",
- "babel-eslint": "^7.2.1",
- "babel-loader": "^6.4.1",
+ "babel-eslint": "^7.2.3",
+ "babel-loader": "^7.0.0",
"babel-plugin-rewire": "^1.1.0",
- "babel-preset-env": "^1.3.3",
+ "babel-preset-env": "^1.4.0",
"babel-preset-react": "^6.24.1",
"babel-preset-react-optimize": "^1.0.1",
"babel-preset-stage-2": "^6.24.1",
@@ -62,7 +62,7 @@
"chokidar": "^1.6.1",
"css-loader": "^0.28.0",
"editorconfig-tools": "^0.1.1",
- "enzyme": "^2.8.0",
+ "enzyme": "^2.8.2",
"eslint": "^3.19.0",
"eslint-config-airbnb": "^14.1.0",
"eslint-loader": "^1.7.1",
@@ -77,21 +77,21 @@
"lint-staged": "^3.4.0",
"markdown-it": "^8.3.1",
"mkdirp": "^0.5.1",
- "mocha": "^3.2.0",
+ "mocha": "^3.3.0",
"pixrem": "^3.0.2",
"pleeease-filters": "^3.0.1",
- "postcss": "^5.2.16",
+ "postcss": "^5.2.17",
"postcss-calc": "^5.3.1",
"postcss-color-function": "^3.0.0",
"postcss-custom-media": "^5.0.1",
"postcss-custom-properties": "^5.0.2",
"postcss-custom-selectors": "^3.0.0",
- "postcss-flexbugs-fixes": "^2.1.0",
+ "postcss-flexbugs-fixes": "^2.1.1",
"postcss-global-import": "^1.0.0",
"postcss-import": "^9.1.0",
"postcss-loader": "^1.3.3",
"postcss-media-minmax": "^2.1.2",
- "postcss-nested": "^1.0.0",
+ "postcss-nested": "^1.0.1",
"postcss-nesting": "^2.3.1",
"postcss-pseudoelements": "^4.0.0",
"postcss-selector-matches": "^2.0.5",
@@ -108,11 +108,11 @@
"stylelint": "^7.10.1",
"stylelint-config-standard": "^16.0.0",
"url-loader": "^0.5.8",
- "webpack": "^2.3.3",
- "webpack-bundle-analyzer": "^2.3.1",
- "webpack-dev-middleware": "^1.10.1",
+ "webpack": "^2.4.1",
+ "webpack-bundle-analyzer": "^2.4.0",
+ "webpack-dev-middleware": "^1.10.2",
"webpack-hot-middleware": "^2.18.0",
- "write-file-webpack-plugin": "^4.0.0"
+ "write-file-webpack-plugin": "^4.0.2"
},
"babel": {
"presets": [
diff --git a/src/core/DOMUtils.js b/src/DOMUtils.js
similarity index 100%
rename from src/core/DOMUtils.js
rename to src/DOMUtils.js
diff --git a/src/client.js b/src/client.js
index 36ffb1561..f43bd258b 100644
--- a/src/client.js
+++ b/src/client.js
@@ -12,10 +12,11 @@ import ReactDOM from 'react-dom';
import FastClick from 'fastclick';
import queryString from 'query-string';
import { createPath } from 'history/PathUtils';
-import history from './core/history';
import App from './components/App';
-import { updateMeta } from './core/DOMUtils';
-import { ErrorReporter, deepForceUpdate } from './core/devUtils';
+import createFetch from './createFetch';
+import history from './history';
+import { updateMeta } from './DOMUtils';
+import { ErrorReporter, deepForceUpdate } from './devUtils';
/* eslint-disable global-require */
@@ -29,6 +30,10 @@ const context = {
const removeCss = styles.map(x => x._insertCss());
return () => { removeCss.forEach(f => f()); };
},
+ // Universal HTTP client
+ fetch: createFetch({
+ baseUrl: window.App.apiUrl,
+ }),
};
// Switch off the native scroll restoration behavior and handle it manually
@@ -87,7 +92,7 @@ FastClick.attach(document.body);
const container = document.getElementById('app');
let appInstance;
let currentLocation = history.location;
-let router = require('./core/router').default;
+let router = require('./router').default;
// Re-render the app when window.location changes
async function onLocationChange(location, action) {
@@ -109,6 +114,7 @@ async function onLocationChange(location, action) {
const route = await router.resolve({
path: location.pathname,
query: queryString.parse(location.search),
+ fetch: context.fetch,
});
// Prevent multiple page renders during the routing process
@@ -161,8 +167,8 @@ if (__DEV__) {
// Enable Hot Module Replacement (HMR)
if (module.hot) {
- module.hot.accept('./core/router', () => {
- router = require('./core/router').default;
+ module.hot.accept('./router', () => {
+ router = require('./router').default;
if (appInstance) {
try {
diff --git a/src/components/App.js b/src/components/App.js
index b4fa46ade..1dc8443b0 100644
--- a/src/components/App.js
+++ b/src/components/App.js
@@ -14,6 +14,8 @@ const ContextType = {
// Enables critical path CSS rendering
// https://github.com/kriasoft/isomorphic-style-loader
insertCss: PropTypes.func.isRequired,
+ // Universal HTTP client
+ fetch: PropTypes.func.isRequired,
};
/**
diff --git a/src/components/Html.js b/src/components/Html.js
index 03f8e632a..2592f8872 100644
--- a/src/components/Html.js
+++ b/src/components/Html.js
@@ -9,7 +9,10 @@
import React from 'react';
import PropTypes from 'prop-types';
-import { analytics } from '../config';
+import serialize from 'serialize-javascript';
+import config from '../config';
+
+/* eslint-disable react/no-danger */
class Html extends React.Component {
static propTypes = {
@@ -20,6 +23,7 @@ class Html extends React.Component {
cssText: PropTypes.string.isRequired,
}).isRequired),
scripts: PropTypes.arrayOf(PropTypes.string.isRequired),
+ app: PropTypes.object,
children: PropTypes.string.isRequired,
};
@@ -29,7 +33,7 @@ class Html extends React.Component {
};
render() {
- const { title, description, styles, scripts, children } = this.props;
+ const { title, description, styles, scripts, app, children } = this.props;
return (
@@ -43,27 +47,22 @@ class Html extends React.Component {
,
)}
-
+
+
{scripts.map(script => )}
- {analytics.google.trackingId &&
+ {config.analytics.googleTrackingId &&
}
- {analytics.google.trackingId &&
+ {config.analytics.googleTrackingId &&
}
diff --git a/src/components/Link/Link.js b/src/components/Link/Link.js
index b1914c1db..31d215417 100644
--- a/src/components/Link/Link.js
+++ b/src/components/Link/Link.js
@@ -9,7 +9,7 @@
import React from 'react';
import PropTypes from 'prop-types';
-import history from '../../core/history';
+import history from '../../history';
function isLeftClickEvent(event) {
return event.button === 0;
diff --git a/src/config.js b/src/config.js
index 04f217fab..bcaba07a6 100644
--- a/src/config.js
+++ b/src/config.js
@@ -9,40 +9,53 @@
/* eslint-disable max-len */
-export const port = process.env.PORT || 3000;
-export const host = process.env.WEBSITE_HOSTNAME || `localhost:${port}`;
-
-export const databaseUrl = process.env.DATABASE_URL || 'sqlite:database.sqlite';
-
-export const analytics = {
-
- // https://analytics.google.com/
- google: {
- trackingId: process.env.GOOGLE_TRACKING_ID, // UA-XXXXX-X
+if (process.env.BROWSER) {
+ throw new Error('Do not import `config.js` from inside the client-side code.');
+}
+
+module.exports = {
+ // Node.js app
+ port: process.env.PORT || 3000,
+
+ // API Gateway
+ api: {
+ // API URL to be used in the client-side code
+ clientUrl: typeof process.env.API_CLIENT_URL === 'undefined' ?
+ '' : process.env.API_CLIENT_URL,
+ // API URL to be used in the server-side code
+ serverUrl: typeof process.env.API_SERVER_URL === 'undefined' ?
+ `http://localhost:${process.env.PORT || 3000}` : process.env.API_SERVER_URL,
},
-};
-
-export const auth = {
+ // Database
+ databaseUrl: process.env.DATABASE_URL || 'sqlite:database.sqlite',
- jwt: { secret: process.env.JWT_SECRET || 'React Starter Kit' },
-
- // https://developers.facebook.com/
- facebook: {
- id: process.env.FACEBOOK_APP_ID || '186244551745631',
- secret: process.env.FACEBOOK_APP_SECRET || 'a970ae3240ab4b9b8aae0f9f0661c6fc',
- },
-
- // https://cloud.google.com/console/project
- google: {
- id: process.env.GOOGLE_CLIENT_ID || '251410730550-ahcg0ou5mgfhl8hlui1urru7jn5s12km.apps.googleusercontent.com',
- secret: process.env.GOOGLE_CLIENT_SECRET || 'Y8yR9yZAhm9jQ8FKAL8QIEcd',
+ // Web analytics
+ analytics: {
+ // https://analytics.google.com/
+ googleTrackingId: process.env.GOOGLE_TRACKING_ID, // UA-XXXXX-X
},
- // https://apps.twitter.com/
- twitter: {
- key: process.env.TWITTER_CONSUMER_KEY || 'Ie20AZvLJI2lQD5Dsgxgjauns',
- secret: process.env.TWITTER_CONSUMER_SECRET || 'KTZ6cxoKnEakQCeSpZlaUCJWGAlTEBJj0y2EMkUBujA7zWSvaQ',
+ // Authentication
+ auth: {
+ jwt: { secret: process.env.JWT_SECRET || 'React Starter Kit' },
+
+ // https://developers.facebook.com/
+ facebook: {
+ id: process.env.FACEBOOK_APP_ID || '186244551745631',
+ secret: process.env.FACEBOOK_APP_SECRET || 'a970ae3240ab4b9b8aae0f9f0661c6fc',
+ },
+
+ // https://cloud.google.com/console/project
+ google: {
+ id: process.env.GOOGLE_CLIENT_ID || '251410730550-ahcg0ou5mgfhl8hlui1urru7jn5s12km.apps.googleusercontent.com',
+ secret: process.env.GOOGLE_CLIENT_SECRET || 'Y8yR9yZAhm9jQ8FKAL8QIEcd',
+ },
+
+ // https://apps.twitter.com/
+ twitter: {
+ key: process.env.TWITTER_CONSUMER_KEY || 'Ie20AZvLJI2lQD5Dsgxgjauns',
+ secret: process.env.TWITTER_CONSUMER_SECRET || 'KTZ6cxoKnEakQCeSpZlaUCJWGAlTEBJj0y2EMkUBujA7zWSvaQ',
+ },
},
-
};
diff --git a/src/core/fetch/fetch.client.js b/src/core/fetch/fetch.client.js
deleted file mode 100644
index 5201119f5..000000000
--- a/src/core/fetch/fetch.client.js
+++ /dev/null
@@ -1,15 +0,0 @@
-/**
- * React Starter Kit (https://www.reactstarterkit.com/)
- *
- * Copyright © 2014-present Kriasoft, LLC. All rights reserved.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE.txt file in the root directory of this source tree.
- */
-
-import 'whatwg-fetch';
-
-export default self.fetch.bind(self);
-export const Headers = self.Headers;
-export const Request = self.Request;
-export const Response = self.Response;
diff --git a/src/core/fetch/fetch.server.js b/src/core/fetch/fetch.server.js
deleted file mode 100644
index 991f9ed81..000000000
--- a/src/core/fetch/fetch.server.js
+++ /dev/null
@@ -1,33 +0,0 @@
-/**
- * React Starter Kit (https://www.reactstarterkit.com/)
- *
- * Copyright © 2014-present Kriasoft, LLC. All rights reserved.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE.txt file in the root directory of this source tree.
- */
-
-import Promise from 'bluebird';
-import fetch, { Request, Headers, Response } from 'node-fetch';
-import { host } from '../../config';
-
-fetch.Promise = Promise;
-Response.Promise = Promise;
-
-function localUrl(url) {
- if (url.startsWith('//')) {
- return `https:${url}`;
- }
-
- if (url.startsWith('http')) {
- return url;
- }
-
- return `http://${host}${url}`;
-}
-
-function localFetch(url, options) {
- return fetch(localUrl(url), options);
-}
-
-export { localFetch as default, Request, Headers, Response };
diff --git a/src/core/fetch/package.json b/src/core/fetch/package.json
deleted file mode 100644
index 0fa7625d6..000000000
--- a/src/core/fetch/package.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "private": true,
- "name": "fetch",
- "main": "./fetch.server.js",
- "browser": "./fetch.client.js"
-}
diff --git a/src/createFetch.js b/src/createFetch.js
new file mode 100644
index 000000000..9af4bcee1
--- /dev/null
+++ b/src/createFetch.js
@@ -0,0 +1,34 @@
+/**
+ * React Starter Kit (https://www.reactstarterkit.com/)
+ *
+ * Copyright © 2014-present Kriasoft, LLC. All rights reserved.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE.txt file in the root directory of this source tree.
+ */
+
+import isoFetch from 'isomorphic-fetch';
+
+type FetchOptions = {
+ baseUrl: string,
+ cookie?: string,
+};
+
+function createFetch({ baseUrl, cookie }: FetchOptions) {
+ return function fetch(url, options) {
+ const { headers, ...other } = options || {};
+ return url.startsWith('/') ? isoFetch(`${baseUrl}${url}`, {
+ method: 'POST',
+ headers: {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ ...(typeof cookie === 'undefined' ? null : { cookie }),
+ ...headers,
+ },
+ credentials: 'include',
+ ...other,
+ }) : isoFetch(url, options);
+ };
+}
+
+export default createFetch;
diff --git a/src/data/queries/news.js b/src/data/queries/news.js
index 2880058d4..775a42886 100644
--- a/src/data/queries/news.js
+++ b/src/data/queries/news.js
@@ -8,7 +8,7 @@
*/
import { GraphQLList as List } from 'graphql';
-import fetch from '../../core/fetch';
+import fetch from 'isomorphic-fetch';
import NewsItemType from '../types/NewsItemType';
// React.js News Feed (RSS)
@@ -35,10 +35,12 @@ const news = {
items = data.items;
}
+ lastFetchTask = null;
return items;
})
- .finally(() => {
+ .catch((err) => {
lastFetchTask = null;
+ throw err;
});
if (items.length) {
diff --git a/src/data/sequelize.js b/src/data/sequelize.js
index b0e593943..7954b8bc8 100644
--- a/src/data/sequelize.js
+++ b/src/data/sequelize.js
@@ -8,9 +8,9 @@
*/
import Sequelize from 'sequelize';
-import { databaseUrl } from '../config';
+import config from '../config';
-const sequelize = new Sequelize(databaseUrl, {
+const sequelize = new Sequelize(config.databaseUrl, {
define: {
freezeTableName: true,
},
diff --git a/src/core/devUtils.js b/src/devUtils.js
similarity index 100%
rename from src/core/devUtils.js
rename to src/devUtils.js
diff --git a/src/core/history.js b/src/history.js
similarity index 100%
rename from src/core/history.js
rename to src/history.js
diff --git a/src/core/passport.js b/src/passport.js
similarity index 95%
rename from src/core/passport.js
rename to src/passport.js
index 6772810ec..6bcd351e4 100644
--- a/src/core/passport.js
+++ b/src/passport.js
@@ -15,15 +15,15 @@
import passport from 'passport';
import { Strategy as FacebookStrategy } from 'passport-facebook';
-import { User, UserLogin, UserClaim, UserProfile } from '../data/models';
-import { auth as config } from '../config';
+import { User, UserLogin, UserClaim, UserProfile } from './data/models';
+import config from './config';
/**
* Sign in with Facebook.
*/
passport.use(new FacebookStrategy({
- clientID: config.facebook.id,
- clientSecret: config.facebook.secret,
+ clientID: config.auth.facebook.id,
+ clientSecret: config.auth.facebook.secret,
callbackURL: '/login/facebook/return',
profileFields: ['name', 'email', 'link', 'locale', 'timezone'],
passReqToCallback: true,
diff --git a/src/core/router.js b/src/router.js
similarity index 91%
rename from src/core/router.js
rename to src/router.js
index 21f78fefd..b7322790a 100644
--- a/src/core/router.js
+++ b/src/router.js
@@ -8,6 +8,6 @@
*/
import Router from 'universal-router';
-import routes from '../routes';
+import routes from './routes';
export default new Router(routes);
diff --git a/src/routes/home/index.js b/src/routes/home/index.js
index ea9fa02c4..19a98cf51 100644
--- a/src/routes/home/index.js
+++ b/src/routes/home/index.js
@@ -9,24 +9,17 @@
import React from 'react';
import Home from './Home';
-import fetch from '../../core/fetch';
import Layout from '../../components/Layout';
export default {
path: '/',
- async action() {
+ async action({ fetch }) {
const resp = await fetch('/graphql', {
- method: 'post',
- headers: {
- Accept: 'application/json',
- 'Content-Type': 'application/json',
- },
body: JSON.stringify({
query: '{news{title,link,content}}',
}),
- credentials: 'include',
});
const { data } = await resp.json();
if (!data || !data.news) throw new Error('Failed to load the news feed.');
diff --git a/src/server.js b/src/server.js
index 135f22374..0151ef886 100644
--- a/src/server.js
+++ b/src/server.js
@@ -21,12 +21,13 @@ import App from './components/App';
import Html from './components/Html';
import { ErrorPageWithoutStyle } from './routes/error/ErrorPage';
import errorPageStyle from './routes/error/ErrorPage.css';
-import passport from './core/passport';
-import router from './core/router';
+import createFetch from './createFetch';
+import passport from './passport';
+import router from './router';
import models from './data/models';
import schema from './data/schema';
import assets from './assets.json'; // eslint-disable-line import/no-unresolved
-import { port, auth } from './config';
+import config from './config';
const app = express();
@@ -49,7 +50,7 @@ app.use(bodyParser.json());
// Authentication
// -----------------------------------------------------------------------------
app.use(expressJwt({
- secret: auth.jwt.secret,
+ secret: config.auth.jwt.secret,
credentialsRequired: false,
getToken: req => req.cookies.id_token,
}));
@@ -65,7 +66,7 @@ app.get('/login/facebook/return',
passport.authenticate('facebook', { failureRedirect: '/login', session: false }),
(req, res) => {
const expiresIn = 60 * 60 * 24 * 180; // 180 days
- const token = jwt.sign(req.user, auth.jwt.secret, { expiresIn });
+ const token = jwt.sign(req.user, config.auth.jwt.secret, { expiresIn });
res.cookie('id_token', token, { maxAge: 1000 * expiresIn, httpOnly: true });
res.redirect('/');
},
@@ -97,11 +98,17 @@ app.get('*', async (req, res, next) => {
// eslint-disable-next-line no-underscore-dangle
styles.forEach(style => css.add(style._getCss()));
},
+ // Universal HTTP client
+ fetch: createFetch({
+ baseUrl: config.api.serverUrl,
+ cookie: req.cookie,
+ }),
};
const route = await router.resolve({
path: req.path,
query: req.query,
+ fetch: context.fetch,
});
if (route.redirect) {
@@ -121,10 +128,12 @@ app.get('*', async (req, res, next) => {
if (assets[route.chunk]) {
data.scripts.push(assets[route.chunk].js);
}
+ data.app = {
+ apiUrl: config.api.clientUrl,
+ };
const html = ReactDOM.renderToStaticMarkup();
- res.status(route.status || 200);
- res.send(`${html}`);
+ res.status(route.status || 200).send(`${html}`);
} catch (err) {
next(err);
}
@@ -148,15 +157,14 @@ app.use((err, req, res, next) => { // eslint-disable-line no-unused-vars
{ReactDOM.renderToString()}
,
);
- res.status(err.status || 500);
- res.send(`${html}`);
+ res.status(err.status || 500).send(`${html}`);
});
//
// Launch the server
// -----------------------------------------------------------------------------
models.sync().catch(err => console.error(err.stack)).then(() => {
- app.listen(port, () => {
- console.info(`The server is running at http://localhost:${port}/`);
+ app.listen(config.port, () => {
+ console.info(`The server is running at http://localhost:${config.port}/`);
});
});
diff --git a/yarn.lock b/yarn.lock
index 58ef2ba5d..9117c1f62 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -59,8 +59,8 @@ ajv-keywords@^1.0.0, ajv-keywords@^1.1.1:
resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c"
ajv@^4.7.0, ajv@^4.9.1:
- version "4.11.6"
- resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.6.tgz#947e93049790942b2a2d60a8289b28924d39f987"
+ version "4.11.7"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.7.tgz#8655a5d86d0824985cc471a1d913fb6729a0ec48"
dependencies:
co "^4.6.0"
json-stable-stringify "^1.0.1"
@@ -117,11 +117,11 @@ aproba@^1.0.3:
resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.1.1.tgz#95d3600f07710aa0e9298c726ad5ecf2eacbabab"
are-we-there-yet@~1.1.2:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.2.tgz#80e470e95a084794fe1899262c5667c6e88de1b3"
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d"
dependencies:
delegates "^1.0.0"
- readable-stream "^2.0.0 || ^1.1.13"
+ readable-stream "^2.0.6"
argparse@^0.1.15:
version "0.1.16"
@@ -149,8 +149,8 @@ arr-diff@^2.0.0:
arr-flatten "^1.0.1"
arr-flatten@^1.0.1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.2.tgz#1ec1e63439c54f67d6f72bb4299c3d4f73b2d996"
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.3.tgz#a274ed85ac08849b6bd7847c4580745dc51adfb1"
array-differ@^1.0.0:
version "1.0.0"
@@ -335,14 +335,14 @@ babel-core@^6.24.1:
slash "^1.0.0"
source-map "^0.5.0"
-babel-eslint@^7.2.1:
- version "7.2.2"
- resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-7.2.2.tgz#0da2cbe6554fd0fb069f19674f2db2f9c59270ff"
+babel-eslint@^7.2.3:
+ version "7.2.3"
+ resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-7.2.3.tgz#b2fe2d80126470f5c19442dc757253a897710827"
dependencies:
babel-code-frame "^6.22.0"
babel-traverse "^6.23.1"
babel-types "^6.23.0"
- babylon "^6.16.1"
+ babylon "^6.17.0"
babel-generator@^6.24.1:
version "6.24.1"
@@ -487,14 +487,13 @@ babel-helpers@^6.24.1:
babel-runtime "^6.22.0"
babel-template "^6.24.1"
-babel-loader@^6.4.1:
- version "6.4.1"
- resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-6.4.1.tgz#0b34112d5b0748a8dcdbf51acf6f9bd42d50b8ca"
+babel-loader@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-7.0.0.tgz#2e43a66bee1fff4470533d0402c8a4532fafbaf7"
dependencies:
find-cache-dir "^0.1.1"
- loader-utils "^0.2.16"
+ loader-utils "^1.0.2"
mkdirp "^0.5.1"
- object-assign "^4.0.1"
babel-messages@^6.23.0:
version "6.23.0"
@@ -848,7 +847,7 @@ babel-polyfill@^6.23.0:
core-js "^2.4.0"
regenerator-runtime "^0.10.0"
-babel-preset-env@^1.3.3:
+babel-preset-env@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.4.0.tgz#c8e02a3bcc7792f23cded68e0355b9d4c28f0f7a"
dependencies:
@@ -939,7 +938,7 @@ babel-register@^6.24.1:
mkdirp "^0.5.1"
source-map-support "^0.4.2"
-babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.22.0:
+babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.23.0:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.23.0.tgz#0a9489f144de70efb3ce4300accdb329e2fc543b"
dependencies:
@@ -979,9 +978,9 @@ babel-types@^6.19.0, babel-types@^6.23.0, babel-types@^6.24.1:
lodash "^4.2.0"
to-fast-properties "^1.0.1"
-babylon@^6.11.0, babylon@^6.15.0, babylon@^6.16.1:
- version "6.16.1"
- resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.16.1.tgz#30c5a22f481978a9e7f8cdfdf496b11d94b404d3"
+babylon@^6.11.0, babylon@^6.15.0, babylon@^6.17.0:
+ version "6.17.0"
+ resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.17.0.tgz#37da948878488b9c4e3c4038893fa3314b3fc932"
backo2@1.0.2:
version "1.0.2"
@@ -1314,8 +1313,8 @@ caniuse-api@^1.5.2:
lodash.uniq "^4.5.0"
caniuse-db@^1.0.30000187, caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639:
- version "1.0.30000655"
- resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000655.tgz#e40b6287adc938848d6708ef83d65b5f54ac1874"
+ version "1.0.30000659"
+ resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000659.tgz#6775220394d464c8efa4a25cafd2ed9b0c60b11c"
caseless@~0.11.0:
version "0.11.0"
@@ -1913,17 +1912,23 @@ debug@2.3.3:
dependencies:
ms "0.7.2"
+debug@2.6.0:
+ version "2.6.0"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.0.tgz#bc596bcabe7617f11d9fa15361eded5608b8499b"
+ dependencies:
+ ms "0.7.2"
+
debug@2.6.1, debug@^2.1.1, debug@^2.2.0, debug@^2.6.0:
version "2.6.1"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.1.tgz#79855090ba2c4e3115cc7d8769491d58f0491351"
dependencies:
ms "0.7.2"
-debug@2.6.3:
- version "2.6.3"
- resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.3.tgz#0f7eb8c30965ec08c72accfa0130c8b79984141d"
+debug@2.6.4:
+ version "2.6.4"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.4.tgz#7586a9b3c39741c0282ae33445c4e8ac74734fe0"
dependencies:
- ms "0.7.2"
+ ms "0.7.3"
debug@~0.7.4:
version "0.7.4"
@@ -2007,11 +2012,7 @@ dev-ip@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/dev-ip/-/dev-ip-1.0.1.tgz#a76a3ed1855be7a012bb8ac16cb80f3c00dc28f0"
-diff@1.4.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/diff/-/diff-1.4.0.tgz#7f28d2eb9ee7b15a97efd89ce63dcfdaa3ccbabf"
-
-diff@^3.1.0:
+diff@3.2.0, diff@^3.1.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9"
@@ -2187,8 +2188,8 @@ ejs@^2.5.6:
resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.5.6.tgz#479636bfa3fe3b1debd52087f0acb204b4f19c88"
electron-to-chromium@^1.2.7:
- version "1.3.3"
- resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.3.tgz#651eb63fe89f39db70ffc8dbd5d9b66958bc6a0e"
+ version "1.3.8"
+ resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.8.tgz#b2c8a2c79bb89fbbfd3724d9555e15095b5f5fb6"
elegant-spinner@^1.0.1:
version "1.0.1"
@@ -2280,7 +2281,7 @@ entities@^1.1.1, entities@~1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0"
-enzyme@^2.8.0:
+enzyme@^2.8.2:
version "2.8.2"
resolved "https://registry.yarnpkg.com/enzyme/-/enzyme-2.8.2.tgz#6c8bcb05012abc4aa4bc3213fb23780b9b5b1714"
dependencies:
@@ -2519,8 +2520,8 @@ eslint@^3.19.0:
user-home "^2.0.0"
espree@^3.4.0:
- version "3.4.1"
- resolved "https://registry.yarnpkg.com/espree/-/espree-3.4.1.tgz#28a83ab4aaed71ed8fe0f5efe61b76a05c13c4d2"
+ version "3.4.2"
+ resolved "https://registry.yarnpkg.com/espree/-/espree-3.4.2.tgz#38dbdedbedc95b8961a1fbf04734a8f6a9c8c592"
dependencies:
acorn "^5.0.1"
acorn-jsx "^3.0.0"
@@ -2630,13 +2631,13 @@ express-graphql@^0.6.4:
http-errors "^1.3.0"
raw-body "^2.1.0"
-express-jwt@^5.1.0:
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/express-jwt/-/express-jwt-5.1.0.tgz#a1c5e3381bc78d2de4d3c51133421c69e004d581"
+express-jwt@^5.3.0:
+ version "5.3.0"
+ resolved "https://registry.yarnpkg.com/express-jwt/-/express-jwt-5.3.0.tgz#3d90cd65802e6336252f19e6a3df3e149e0c5ea0"
dependencies:
async "^1.5.0"
express-unless "^0.3.0"
- jsonwebtoken "~6.2.0"
+ jsonwebtoken "^7.3.0"
lodash.set "^4.0.0"
express-unless@^0.3.0:
@@ -2772,10 +2773,10 @@ finalhandler@0.5.0:
unpipe "~1.0.0"
finalhandler@~1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.0.1.tgz#bcd15d1689c0e5ed729b6f7f541a6df984117db8"
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.0.2.tgz#d0e36f9dbc557f2de14423df6261889e9d60c93a"
dependencies:
- debug "2.6.3"
+ debug "2.6.4"
encodeurl "~1.0.1"
escape-html "~1.0.3"
on-finished "~2.3.0"
@@ -2930,8 +2931,8 @@ gather-stream@^1.0.0:
resolved "https://registry.yarnpkg.com/gather-stream/-/gather-stream-1.0.0.tgz#b33994af457a8115700d410f317733cbe7a0904b"
gauge@~2.7.1:
- version "2.7.3"
- resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.3.tgz#1c23855f962f17b3ad3d0dc7443f304542edfe09"
+ version "2.7.4"
+ resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
dependencies:
aproba "^1.0.3"
console-control-strings "^1.0.0"
@@ -2991,18 +2992,7 @@ glob-parent@^2.0.0:
dependencies:
is-glob "^2.0.0"
-glob@7.0.5:
- version "7.0.5"
- resolved "https://registry.yarnpkg.com/glob/-/glob-7.0.5.tgz#b4202a69099bbb4d292a7c1b95b6682b67ebdc95"
- dependencies:
- fs.realpath "^1.0.0"
- inflight "^1.0.4"
- inherits "2"
- minimatch "^3.0.2"
- once "^1.3.0"
- path-is-absolute "^1.0.0"
-
-glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1:
+glob@7.1.1, glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1:
version "7.1.1"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8"
dependencies:
@@ -3014,8 +3004,8 @@ glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1:
path-is-absolute "^1.0.0"
global@^4.3.0:
- version "4.3.1"
- resolved "https://registry.yarnpkg.com/global/-/global-4.3.1.tgz#5f757908c7cbabce54f386ae440e11e26b7916df"
+ version "4.3.2"
+ resolved "https://registry.yarnpkg.com/global/-/global-4.3.2.tgz#e76989268a6c74c38908b1305b10fc0e394e9d0f"
dependencies:
min-document "^2.19.0"
process "~0.5.1"
@@ -3069,7 +3059,7 @@ graceful-fs@^4.1.2, graceful-fs@^4.1.4, graceful-fs@^4.1.6, graceful-fs@^4.1.9:
version "1.0.1"
resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725"
-graphql@^0.9.2:
+graphql@^0.9.3:
version "0.9.3"
resolved "https://registry.yarnpkg.com/graphql/-/graphql-0.9.3.tgz#71fc0fa331bffb9c20678485861cfb370803118e"
dependencies:
@@ -3198,8 +3188,8 @@ html-comment-regex@^1.1.0:
resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.1.tgz#668b93776eaae55ebde8f3ad464b307a4963625e"
html-entities@^1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.0.tgz#41948caf85ce82fed36e4e6a0ed371a6664379e2"
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f"
html-tags@^1.1.1:
version "1.1.1"
@@ -3345,8 +3335,8 @@ inquirer@^0.12.0:
through "^2.3.6"
interpret@^1.0.0:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.2.tgz#f4f623f0bb7122f15f5717c8e254b8161b5c5b2d"
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.3.tgz#cbc35c62eeee73f19ab7b10a801511401afc0f90"
invariant@^2.2.0, invariant@^2.2.1, invariant@^2.2.2:
version "2.2.2"
@@ -3568,20 +3558,21 @@ isobject@^2.0.0:
dependencies:
isarray "1.0.0"
-isomorphic-fetch@^2.1.1:
+isomorphic-fetch@^2.1.1, isomorphic-fetch@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9"
dependencies:
node-fetch "^1.0.1"
whatwg-fetch ">=0.10.0"
-isomorphic-style-loader@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/isomorphic-style-loader/-/isomorphic-style-loader-1.1.0.tgz#677d0040b10db2d84a1403a1622b9f6e5a264c75"
+isomorphic-style-loader@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/isomorphic-style-loader/-/isomorphic-style-loader-2.0.0.tgz#d4d41a5f88a045dcdb3c5b61a464912bc6c0d3dc"
dependencies:
- babel-runtime "^6.11.6"
+ babel-runtime "^6.23.0"
hoist-non-react-statics "^1.2.0"
- loader-utils "^0.2.16"
+ loader-utils "^1.1.0"
+ prop-types "^15.5.8"
isstream@~0.1.2:
version "0.1.2"
@@ -3597,7 +3588,7 @@ jodid25519@^1.0.0:
dependencies:
jsbn "~0.1.0"
-joi@^6.10.1, joi@~6.10.1:
+joi@^6.10.1:
version "6.10.1"
resolved "https://registry.yarnpkg.com/joi/-/joi-6.10.1.tgz#4d50c318079122000fe5f16af1ff8e1917b77e06"
dependencies:
@@ -3703,15 +3694,6 @@ jsonwebtoken@^7.3.0:
ms "^0.7.1"
xtend "^4.0.1"
-jsonwebtoken@~6.2.0:
- version "6.2.0"
- resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-6.2.0.tgz#8233154c6cd9fd8760ad0f5a563f539dd391f2f9"
- dependencies:
- joi "~6.10.1"
- jws "^3.0.0"
- ms "^0.7.1"
- xtend "^4.0.1"
-
jsprim@^1.2.2:
version "1.4.0"
resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.0.tgz#a3b87e40298d8c380552d8cc7628a0bb95a22918"
@@ -3722,10 +3704,8 @@ jsprim@^1.2.2:
verror "1.3.6"
jsx-ast-utils@^1.0.0, jsx-ast-utils@^1.3.4:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-1.4.0.tgz#5afe38868f56bc8cc7aeaef0100ba8c75bd12591"
- dependencies:
- object-assign "^4.1.0"
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz#3867213e8dd79bf1e8f2300c0cfc1efb182c0df1"
jwa@^1.1.4:
version "1.1.5"
@@ -3736,7 +3716,7 @@ jwa@^1.1.4:
ecdsa-sig-formatter "1.0.9"
safe-buffer "^5.0.1"
-jws@^3.0.0, jws@^3.1.4:
+jws@^3.1.4:
version "3.1.4"
resolved "https://registry.yarnpkg.com/jws/-/jws-3.1.4.tgz#f9e8b9338e8a847277d6444b1464f61880e050a2"
dependencies:
@@ -3886,7 +3866,7 @@ loader-utils@^0.2.16:
json5 "^0.5.0"
object-assign "^4.0.1"
-loader-utils@^1.0.2:
+loader-utils@^1.0.2, loader-utils@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.1.0.tgz#c98aef488bcceda2ffb5e2de646d6a754429f5cd"
dependencies:
@@ -4322,16 +4302,16 @@ mkdirp@0.5.1, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkd
dependencies:
minimist "0.0.8"
-mocha@^3.2.0:
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/mocha/-/mocha-3.2.0.tgz#7dc4f45e5088075171a68896814e6ae9eb7a85e3"
+mocha@^3.3.0:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/mocha/-/mocha-3.3.0.tgz#d29b7428d3f52c82e2e65df1ecb7064e1aabbfb5"
dependencies:
browser-stdout "1.3.0"
commander "2.9.0"
- debug "2.2.0"
- diff "1.4.0"
+ debug "2.6.0"
+ diff "3.2.0"
escape-string-regexp "1.0.5"
- glob "7.0.5"
+ glob "7.1.1"
growl "1.9.2"
json3 "3.3.2"
lodash.create "3.1.1"
@@ -4356,7 +4336,7 @@ ms@0.7.2:
version "0.7.2"
resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765"
-ms@^0.7.1:
+ms@0.7.3, ms@^0.7.1:
version "0.7.3"
resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.3.tgz#708155a5e44e33f5fd0fc53e81d0d40a91be1fff"
@@ -4393,7 +4373,7 @@ negotiator@0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9"
-node-fetch@^1.0.1, node-fetch@^1.6.3:
+node-fetch@^1.0.1:
version "1.6.3"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.6.3.tgz#dc234edd6489982d58e8f0db4f695029abcd8c04"
dependencies:
@@ -4460,8 +4440,8 @@ nopt@^4.0.1:
osenv "^0.1.4"
normalize-package-data@^2.3.2, normalize-package-data@^2.3.4:
- version "2.3.6"
- resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.3.6.tgz#498fa420c96401f787402ba21e600def9f981fff"
+ version "2.3.8"
+ resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.3.8.tgz#d819eda2a9dedbd1ffa563ea4071d936782295bb"
dependencies:
hosted-git-info "^2.1.4"
is-builtin-module "^1.0.0"
@@ -5002,7 +4982,7 @@ postcss-filter-plugins@^2.0.0:
postcss "^5.0.4"
uniqid "^4.0.0"
-postcss-flexbugs-fixes@^2.1.0:
+postcss-flexbugs-fixes@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-2.1.1.tgz#5fa40080ba216d398e41228be2765282f2060d8d"
dependencies:
@@ -5162,7 +5142,7 @@ postcss-modules-values@^1.1.0:
icss-replace-symbols "^1.0.2"
postcss "^5.0.14"
-postcss-nested@^1.0.0:
+postcss-nested@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-1.0.1.tgz#91f28f4e6e23d567241ac154558a0cfab4cc0d8f"
dependencies:
@@ -5377,7 +5357,7 @@ promise@^7.1.1:
dependencies:
asap "~2.0.3"
-prop-types@^15.5.4, prop-types@^15.5.6, prop-types@^15.5.7, prop-types@~15.5.7:
+prop-types@^15.5.4, prop-types@^15.5.7, prop-types@^15.5.8, prop-types@~15.5.7:
version "15.5.8"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.5.8.tgz#6b7b2e141083be38c8595aa51fc55775c7199394"
dependencies:
@@ -5436,9 +5416,9 @@ qs@~6.3.0:
version "6.3.2"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.2.tgz#e75bd5f6e268122a2a0e0bda630b2550c166502c"
-query-string@^4.1.0, query-string@^4.3.2:
- version "4.3.2"
- resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.2.tgz#ec0fd765f58a50031a3968c2431386f8947a5cdd"
+query-string@^4.1.0, query-string@^4.3.4:
+ version "4.3.4"
+ resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.4.tgz#bbb693b9ca915c232515b228b1a02b609043dbeb"
dependencies:
object-assign "^4.1.0"
strict-uri-encode "^1.0.0"
@@ -5498,7 +5478,7 @@ react-deep-force-update@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/react-deep-force-update/-/react-deep-force-update-2.0.1.tgz#4f7f6c12c3e7de42f345992a3c518236fa1ecad3"
-react-dom@^15.5.3:
+react-dom@^15.5.4:
version "15.5.4"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-15.5.4.tgz#ba0c28786fd52ed7e4f2135fe0288d462aef93da"
dependencies:
@@ -5524,7 +5504,7 @@ react-proxy@^3.0.0-alpha.0:
dependencies:
lodash "^4.6.1"
-react@^15.5.3:
+react@^15.5.4:
version "15.5.4"
resolved "https://registry.yarnpkg.com/react/-/react-15.5.4.tgz#fa83eb01506ab237cdc1c8c3b1cea8de012bf047"
dependencies:
@@ -5578,7 +5558,7 @@ readable-stream@^1.0.33, readable-stream@~1.1.9:
isarray "0.0.1"
string_decoder "~0.10.x"
-"readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.1.4, readable-stream@^2.2.2, readable-stream@^2.2.6:
+readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.2.2, readable-stream@^2.2.6:
version "2.2.9"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.9.tgz#cf78ec6f4a6d1eb43d26488cac97f042e74b7fc8"
dependencies:
@@ -5807,12 +5787,12 @@ resolve-from@^2.0.0:
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57"
resolve-pathname@^2.0.0:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-2.0.2.tgz#e55c016eb2e9df1de98e85002282bfb38c630436"
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-2.1.0.tgz#e8358801b86b83b17560d4e3c382d7aef2100944"
resolve@^1.1.6, resolve@^1.1.7:
- version "1.3.2"
- resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.3.2.tgz#1f0442c9e0cbb8136e87b9305f932f46c7f28235"
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.3.3.tgz#655907c3469a8680dc2de3a275a8fdd69691f0e5"
dependencies:
path-parse "^1.0.5"
@@ -5955,6 +5935,10 @@ sequelize@^3.30.4:
validator "^5.2.0"
wkx "0.2.0"
+serialize-javascript@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.3.0.tgz#86a4f3752f5c7e47295449b0bbb63d64ba533f05"
+
serve-index@1.8.0:
version "1.8.0"
resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.8.0.tgz#7c5d96c13fb131101f93c1c5774f8516a1e78d3b"
@@ -6619,8 +6603,8 @@ type-detect@^1.0.0:
resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-1.0.0.tgz#762217cc06db258ec48908a1298e8b95121e8ea2"
type-detect@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.0.tgz#62053883542a321f2f7b25746dc696478b18ff6b"
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.3.tgz#0e3f2670b44099b0b46c284d136a7ef49c74c2ea"
type-is@~1.6.14:
version "1.6.15"
@@ -6688,9 +6672,9 @@ uniqs@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02"
-universal-router@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/universal-router/-/universal-router-3.0.0.tgz#f65f22ec284e4e44fb33f6c6070c8ca5fc7f46a3"
+universal-router@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/universal-router/-/universal-router-3.1.0.tgz#644c3b9d7c64a3cde12dce01df6702fdd7179941"
dependencies:
path-to-regexp "^1.7.0"
@@ -6753,8 +6737,8 @@ uuid@^3.0.0:
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1"
v8flags@^2.0.10:
- version "2.0.12"
- resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.0.12.tgz#73235d9f7176f8e8833fb286795445f7938d84e5"
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.1.1.tgz#aab1a1fa30d45f88dd321148875ac02c0b55e5b4"
dependencies:
user-home "^1.1.1"
@@ -6770,8 +6754,8 @@ validator@^5.2.0:
resolved "https://registry.yarnpkg.com/validator/-/validator-5.7.0.tgz#7a87a58146b695ac486071141c0c49d67da05e5c"
value-equal@^0.2.0:
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-0.2.0.tgz#4f41c60a3fc011139a2ec3d3340a8998ae8b69c0"
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-0.2.1.tgz#c220a304361fce6994dbbedaa3c7e1a1b895871d"
vary@~1.1.0:
version "1.1.1"
@@ -6811,7 +6795,7 @@ watchpack@^1.3.1:
chokidar "^1.4.3"
graceful-fs "^4.1.2"
-webpack-bundle-analyzer@^2.3.1:
+webpack-bundle-analyzer@^2.4.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-2.4.0.tgz#e406b016e7452bc864793848c79308782accba8e"
dependencies:
@@ -6826,9 +6810,9 @@ webpack-bundle-analyzer@^2.3.1:
mkdirp "^0.5.1"
opener "^1.4.3"
-webpack-dev-middleware@^1.10.1:
- version "1.10.1"
- resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-1.10.1.tgz#c6b4cf428139cf1aefbe06a0c00fdb4f8da2f893"
+webpack-dev-middleware@^1.10.2:
+ version "1.10.2"
+ resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-1.10.2.tgz#2e252ce1dfb020dbda1ccb37df26f30ab014dbd1"
dependencies:
memory-fs "~0.4.1"
mime "^1.3.4"
@@ -6851,7 +6835,7 @@ webpack-sources@^0.2.3:
source-list-map "^1.1.1"
source-map "~0.5.3"
-webpack@^2.3.3:
+webpack@^2.4.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/webpack/-/webpack-2.4.1.tgz#15a91dbe34966d8a4b99c7d656efd92a2e5a6f6a"
dependencies:
@@ -6885,7 +6869,7 @@ weinre@^2.0.0-pre-I0Z7U9OV:
nopt "3.0.x"
underscore "1.7.x"
-whatwg-fetch@>=0.10.0, whatwg-fetch@^2.0.3:
+whatwg-fetch@>=0.10.0:
version "2.0.3"
resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84"
@@ -6952,7 +6936,7 @@ write-file-stdout@0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/write-file-stdout/-/write-file-stdout-0.0.2.tgz#c252d7c7c5b1b402897630e3453c7bfe690d9ca1"
-write-file-webpack-plugin@^4.0.0:
+write-file-webpack-plugin@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/write-file-webpack-plugin/-/write-file-webpack-plugin-4.0.2.tgz#70c89a4d99a105e1aed778b21b5f75e7af4da58b"
dependencies:
From 0b1e1e408430e048c381d1c806c7ad99bdb1336d Mon Sep 17 00:00:00 2001
From: Konstantin Tarkus
Date: Mon, 24 Apr 2017 21:44:41 +0300
Subject: [PATCH 2/6] Fix ESLint warning in Html.js
---
src/components/Html.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/components/Html.js b/src/components/Html.js
index 2592f8872..5eeee0a45 100644
--- a/src/components/Html.js
+++ b/src/components/Html.js
@@ -23,7 +23,7 @@ class Html extends React.Component {
cssText: PropTypes.string.isRequired,
}).isRequired),
scripts: PropTypes.arrayOf(PropTypes.string.isRequired),
- app: PropTypes.object,
+ app: PropTypes.object, // eslint-disable-line
children: PropTypes.string.isRequired,
};
From 6c1b54cee54d4f2f03bc2347ea7d24e868ccbcde Mon Sep 17 00:00:00 2001
From: Konstantin Tarkus
Date: Tue, 25 Apr 2017 11:58:06 +0300
Subject: [PATCH 3/6] Make createFetch more readable
---
src/createFetch.js | 45 ++++++++++++++++++++++++++++++---------------
yarn.lock | 18 ++++++++++++------
2 files changed, 42 insertions(+), 21 deletions(-)
diff --git a/src/createFetch.js b/src/createFetch.js
index 9af4bcee1..b5bc3b531 100644
--- a/src/createFetch.js
+++ b/src/createFetch.js
@@ -7,28 +7,43 @@
* LICENSE.txt file in the root directory of this source tree.
*/
-import isoFetch from 'isomorphic-fetch';
+/* @flow */
-type FetchOptions = {
+import fetch from 'isomorphic-fetch';
+
+type Options = {
baseUrl: string,
cookie?: string,
};
-function createFetch({ baseUrl, cookie }: FetchOptions) {
- return function fetch(url, options) {
- const { headers, ...other } = options || {};
- return url.startsWith('/') ? isoFetch(`${baseUrl}${url}`, {
- method: 'POST',
+/**
+ * Creates a wrapper function around the HTML5 Fetch API that provides
+ * default arguments to fetch(...) and is intended to reduce the amount
+ * of boilerplate code in the application.
+ * https://developer.mozilla.org/docs/Web/API/Fetch_API/Using_Fetch
+ */
+function createFetch({ baseUrl, cookie }: Options) {
+ // NOTE: Tweak the default options to suite your application needs
+ const defaults = {
+ method: 'POST', // handy with GraphQL backends
+ mode: baseUrl ? 'cors' : 'same-origin',
+ credentials: baseUrl ? 'include' : 'same-origin',
+ headers: {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ ...(cookie ? { Cookie: cookie } : null),
+ },
+ };
+
+ return (url, options) => ((url.startsWith('/graphql') || url.startsWith('/api')) ?
+ fetch(`${baseUrl}${url}`, {
+ ...defaults,
+ ...options,
headers: {
- Accept: 'application/json',
- 'Content-Type': 'application/json',
- ...(typeof cookie === 'undefined' ? null : { cookie }),
- ...headers,
+ ...defaults.headers,
+ ...(options && options.headers),
},
- credentials: 'include',
- ...other,
- }) : isoFetch(url, options);
- };
+ }) : fetch(url, options));
}
export default createFetch;
diff --git a/yarn.lock b/yarn.lock
index 9117c1f62..d3d72c5c6 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2,6 +2,10 @@
# yarn lockfile v1
+"@types/geojson@^1.0.0":
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-1.0.2.tgz#b02d10ab028e2928ac592a051aaa4981a1941d03"
+
JSONStream@^0.8.4:
version "0.8.4"
resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-0.8.4.tgz#91657dfe6ff857483066132b4618b62e8f4887bd"
@@ -1313,8 +1317,8 @@ caniuse-api@^1.5.2:
lodash.uniq "^4.5.0"
caniuse-db@^1.0.30000187, caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639:
- version "1.0.30000659"
- resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000659.tgz#6775220394d464c8efa4a25cafd2ed9b0c60b11c"
+ version "1.0.30000660"
+ resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000660.tgz#d2d57b309dc5a11bb5b46018f51855f7a41efee5"
caseless@~0.11.0:
version "0.11.0"
@@ -3685,8 +3689,8 @@ jsonpointer@^4.0.0:
resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9"
jsonwebtoken@^7.3.0:
- version "7.3.0"
- resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-7.3.0.tgz#85118d6a70e3fccdf14389f4e7a1c3f9c8a9fbba"
+ version "7.4.0"
+ resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-7.4.0.tgz#515bf2bba070ec615bad97fd2e945027eb476946"
dependencies:
joi "^6.10.1"
jws "^3.1.4"
@@ -6495,8 +6499,10 @@ terraformer-wkt-parser@^1.1.0:
terraformer "~1.0.5"
terraformer@~1.0.5:
- version "1.0.7"
- resolved "https://registry.yarnpkg.com/terraformer/-/terraformer-1.0.7.tgz#d8a19a56fbf25966ea062d21f515b93589702d69"
+ version "1.0.8"
+ resolved "https://registry.yarnpkg.com/terraformer/-/terraformer-1.0.8.tgz#51e0ad89746fcf2161dc6f65aa70e42377c8b593"
+ dependencies:
+ "@types/geojson" "^1.0.0"
text-encoding@0.6.4:
version "0.6.4"
From e0222a3fa34cfc64d4e50315f8b44524a5fb47ef Mon Sep 17 00:00:00 2001
From: Konstantin Tarkus
Date: Tue, 25 Apr 2017 12:32:13 +0300
Subject: [PATCH 4/6] Update docs/data-fetching.md
---
docs/data-fetching.md | 76 ++++++++++++++++++++++++++++++-------------
1 file changed, 53 insertions(+), 23 deletions(-)
diff --git a/docs/data-fetching.md b/docs/data-fetching.md
index af24768d6..71fa32d55 100644
--- a/docs/data-fetching.md
+++ b/docs/data-fetching.md
@@ -1,30 +1,60 @@
-## Data Fetching with WHATWG Fetch
-
-There is isomorphic `core/fetch` module that can be used the same way in both
-client-side and server-side code as follows:
-
-```jsx
-export const path = '/products';
-export const action = async ({ fetch }) => {
- const response = await fetch('/graphql?query={products{id,name}}');
- const data = await response.json();
- return ;
-};
+## Data Fetching
+
+At a bare minimum you may want to use [HTML5 Fetch API][fetch] as an HTTP client utility for
+making Ajax request to the [data API server][nodeapi]. This API is supported natively in all the
+major browsers except for IE (note, that Edge browser does support Fetch).
+
+**React Starter Kit** is pre-configured with [`whatwg-fetch`][wfetch] polyfill for the browser
+environment and [`node-fetch`][nfetch] module for the server-side environment (see
+[`src/createFetch.js`](../src/createFetch.js)), allowing you to use the `fetch(url, options)`
+method universally in both the client-side and server-side code bases.
+
+In order to avoid the the amount of boilerplate code needed when using the raw `fetch(..)`
+function, a simple wrapper was created that provides a base URL of the data API server, credentials
+(cookies), CORS etc. For example, in a browser environment the base URL of the data API server
+might be an empty string, so when you make an Ajax request to the `/graphql` endpoint it's being
+sent to the same origin, and when the same code is executed on the server, during server-side
+rendering, it fetches data from the `http://api:8080/graphql` endpoint (`node-fetch` doesn't
+support relative URLs for obvious reasons).
+
+Because of these subtle differences of how the `fetch` method works internally, it makes total
+sense to pass it as a `context` variable to your React application, so it can be used from either
+routing level or from inside your React components as follows:
+
+#### Route Example
+
+```js
+{
+ path: '/posts/:id',
+ async action({ params, fetch }) {
+ const resp = await fetch(`/api/posts/${params.id}`, { method: 'GET' });
+ const data = await resp.json();
+ return { title: data.title, component: };
+ }
+}
```
-When this code executes on the client, the Ajax request will be sent via
-GitHub's [fetch](https://github.com/github/fetch) library (`whatwg-fetch`),
-that itself uses XHMLHttpRequest behind the scene unless `fetch` is supported
-natively by the user's browser.
+#### React Component
+
+```js
+class Post extends React.Component {
+ static context = { fetch: PropTypes.func.isRequired };
+ handleDelete = (event) => {
+ event.preventDefault();
+ const id = event.target.dataset['id'];
+ this.context.fetch(`/api/posts/${id}`, { method: 'DELETE' }).then(...);
+ };
+ render() { ... }
+}
+```
-Whenever the same code executes on the server, it uses
-[node-fetch](https://github.com/bitinn/node-fetch) module behind the scene that
-itself sends an HTTP request via Node.js `http` module. It also converts
-relative URLs to absolute (see `./core/fetch/fetch.server.js`).
+#### Related articles
-Both `whatwg-fetch` and `node-fetch` modules have almost identical API. If
-you're new to this API, the following article may give you a good introduction:
+* [That's so fetch!](https://jakearchibald.com/2015/thats-so-fetch/) by [Jake Archibald](https://twitter.com/jaffathecake)
-https://jakearchibald.com/2015/thats-so-fetch/
+[fetch]: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
+[wfetch]: https://github.com/github/fetchno
+[nfetch]: https://github.com/bitinn/node-fetch
+[nodeapi]: https://github.com/kriasoft/nodejs-api-starter
From 19b555e8528e3727df6187c6067ae7f2517c1d3c Mon Sep 17 00:00:00 2001
From: Konstantin Tarkus
Date: Tue, 25 Apr 2017 12:49:11 +0300
Subject: [PATCH 5/6] Code style fixes
---
src/config.js | 3 +--
src/server.js | 6 ++++--
2 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/src/config.js b/src/config.js
index bcaba07a6..847113c34 100644
--- a/src/config.js
+++ b/src/config.js
@@ -20,8 +20,7 @@ module.exports = {
// API Gateway
api: {
// API URL to be used in the client-side code
- clientUrl: typeof process.env.API_CLIENT_URL === 'undefined' ?
- '' : process.env.API_CLIENT_URL,
+ clientUrl: typeof process.env.API_CLIENT_URL || '',
// API URL to be used in the server-side code
serverUrl: typeof process.env.API_SERVER_URL === 'undefined' ?
`http://localhost:${process.env.PORT || 3000}` : process.env.API_SERVER_URL,
diff --git a/src/server.js b/src/server.js
index 0151ef886..cc14a2727 100644
--- a/src/server.js
+++ b/src/server.js
@@ -133,7 +133,8 @@ app.get('*', async (req, res, next) => {
};
const html = ReactDOM.renderToStaticMarkup();
- res.status(route.status || 200).send(`${html}`);
+ res.status(route.status || 200);
+ res.send(`${html}`);
} catch (err) {
next(err);
}
@@ -157,7 +158,8 @@ app.use((err, req, res, next) => { // eslint-disable-line no-unused-vars
{ReactDOM.renderToString()}
,
);
- res.status(err.status || 500).send(`${html}`);
+ res.status(err.status || 500);
+ res.send(`${html}`);
});
//
From 0dcd16eaa51a766680d1fcb59e855132f0f6cfc4 Mon Sep 17 00:00:00 2001
From: Konstantin Tarkus
Date: Tue, 25 Apr 2017 12:51:54 +0300
Subject: [PATCH 6/6] Code style fixes
---
src/config.js | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/src/config.js b/src/config.js
index 847113c34..8fdece989 100644
--- a/src/config.js
+++ b/src/config.js
@@ -20,10 +20,9 @@ module.exports = {
// API Gateway
api: {
// API URL to be used in the client-side code
- clientUrl: typeof process.env.API_CLIENT_URL || '',
+ clientUrl: process.env.API_CLIENT_URL || '',
// API URL to be used in the server-side code
- serverUrl: typeof process.env.API_SERVER_URL === 'undefined' ?
- `http://localhost:${process.env.PORT || 3000}` : process.env.API_SERVER_URL,
+ serverUrl: process.env.API_SERVER_URL || `http://localhost:${process.env.PORT || 3000}`,
},
// Database