Skip to content

Commit 78a079a

Browse files
committed
2.9.1
2.9.1 - 2017-10-17 ----------------------------------------------- ## Config * Adds `.addBeforeMiddleware()`, for adding Koa middleware that runs before Apollo/Redux instantiation * Adds `.disableTiming()` to optionally remove the `Response-Time` header / timing middleware ## Server * Renames `ctx.apollo` to `ctx.apollo.client`. Now, setting `ctx.apollo.options` in before middleware will merge those settings into Apollo client creation * Adds logic to check for the presence of `ctx.apollo.client` and `ctx.store` before using default Apollo/Redux init. This allows overrides in before middleware for completely custom instantiation
1 parent edbd88b commit 78a079a

File tree

7 files changed

+79
-33
lines changed

7 files changed

+79
-33
lines changed

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
2.9.1 - 2017-10-17
2+
-----------------------------------------------
3+
4+
## Config
5+
* Adds `.addBeforeMiddleware()`, for adding Koa middleware that runs before Apollo/Redux instantiation
6+
* Adds `.disableTiming()` to optionally remove the `Response-Time` header / timing middleware
7+
8+
## Server
9+
* Renames `ctx.apollo` to `ctx.apollo.client`. Now, setting `ctx.apollo.options` in before middleware will merge those settings into Apollo client creation
10+
* Adds logic to check for the presence of `ctx.apollo.client` and `ctx.store` before using default Apollo/Redux init. This allows overrides in before middleware for completely custom instantiation
11+
112
2.9.0 - 2017-10-17
213
-----------------------------------------------
314

kit/config.js

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,12 +86,19 @@ if (SERVER) {
8686
// Create a set for routes -- to retrieve based on insertion order
8787
this.routes = new Set();
8888

89+
// Custom middleware
90+
this.beforeMiddleware = new Set();
91+
this.middleware = new Set();
92+
8993
// Koa application function. But default, this is null
9094
this.koaAppFunc = null;
9195

9296
// Flag for setting whether plain HTTP should be disabled
9397
this.enableHTTP = true;
9498

99+
// Flag for enabling the `Response-Time` Koa middleware timer
100+
this.enableTiming = true;
101+
95102
// Flag for enabling Koa Helmet HTTP hardening. True, by default.
96103
this.enableKoaHelmet = true;
97104
this.koaHelmetOptions = null;
@@ -103,9 +110,6 @@ if (SERVER) {
103110
// in userland, this would instead hold an object of options
104111
this.sslOptions = null;
105112

106-
// Custom middleware -- again, based on insertion order
107-
this.middleware = new Set();
108-
109113
// GraphQL schema (if we're using an internal server)
110114
this.graphQLSchema = null;
111115

@@ -153,6 +157,11 @@ if (SERVER) {
153157
this.enableHTTP = false;
154158
}
155159

160+
// Disable timing the request. This will remove the `Response-Time` header
161+
disableTiming() {
162+
this.enableTiming = false;
163+
}
164+
156165
// Disable the optional `koa-bodyparser`, to prevent POST data being sent to
157166
// each request. By default, body parsing is enabled.
158167
disableBodyParser() {
@@ -192,7 +201,12 @@ if (SERVER) {
192201
this.errorHandler = func;
193202
}
194203

195-
// Add custom middleware. This should be an async func, for use with Koa
204+
// Add custom middleware. This should be an async func, for use with Koa.
205+
// There are two entry points - 'before' and 'after'
206+
addBeforeMiddleware(middlewareFunc) {
207+
this.beforeMiddleware.add(middlewareFunc);
208+
}
209+
196210
addMiddleware(middlewareFunc) {
197211
this.middleware.add(middlewareFunc);
198212
}

kit/entry/server.js

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,7 @@
22

33
// Server entry point, for Webpack. This will spawn a Koa web server
44
// and listen for HTTP requests. Clients will get a return render of React
5-
// or the file they have requested
6-
//
7-
// Note: No HTTP optimisation is performed here (gzip, http/2, etc). Node.js
8-
// will nearly always be slower than Nginx or an equivalent, dedicated proxy,
9-
// so it's usually better to leave that stuff to a faster upstream provider
5+
// or the file they have requested.
106

117
// ----------------------
128
// IMPORTS
@@ -163,7 +159,7 @@ export function createReactHandler(css = [], scripts = [], chunkManifest = {}) {
163159
// store it in our empty `route` object
164160
const components = (
165161
<StaticRouter location={ctx.request.url} context={routeContext}>
166-
<ApolloProvider store={ctx.store} client={ctx.apollo}>
162+
<ApolloProvider store={ctx.store} client={ctx.apollo.client}>
167163
<App />
168164
</ApolloProvider>
169165
</StaticRouter>
@@ -269,37 +265,56 @@ const app = new Koa()
269265
ctx.body = 'There was an error. Please try again later.';
270266
}
271267
}
272-
})
268+
});
273269

270+
if (config.enableTiming) {
274271
// It's useful to see how long a request takes to respond. Add the
275272
// timing to a HTTP Response header
276-
.use(async (ctx, next) => {
273+
app.use(async (ctx, next) => {
277274
const start = ms.now();
278275
await next();
279276
const end = ms.parse(ms.since(start));
280277
const total = end.microseconds + (end.milliseconds * 1e3) + (end.seconds * 1e6);
281278
ctx.set('Response-Time', `${total / 1e3}ms`);
282-
})
279+
});
280+
}
283281

284-
// Create a new Apollo client and Redux store per request. This will be
285-
// stored on the `ctx` object, making it available for the React handler or
286-
// any subsequent route/middleware
287-
.use(async (ctx, next) => {
288-
// Create a new server Apollo client for this request
289-
ctx.apollo = createClient({
282+
// Middleware to set the per-request environment, including the Apollo client.
283+
// These can be overriden/added to in userland with `config.addBeforeMiddleware()`
284+
app.use(async (ctx, next) => {
285+
ctx.apollo = {};
286+
return next();
287+
});
288+
289+
// Add 'before' middleware that needs to be invoked before the per-request
290+
// Apollo client and Redux store has instantiated
291+
config.beforeMiddleware.forEach(middlewareFunc => app.use(middlewareFunc));
292+
293+
// Create a new Apollo client and Redux store per request. This will be
294+
// stored on the `ctx` object, making it available for the React handler or
295+
// any subsequent route/middleware
296+
app.use(async (ctx, next) => {
297+
// Create a new server Apollo client for this request, if we don't already
298+
// have one
299+
if (!ctx.apollo.client) {
300+
ctx.apollo.client = createClient({
290301
ssrMode: true,
291302
// Create a network request. If we're running an internal server, this
292303
// will be a function that accepts the request's context, to feed through
293304
// to the GraphQL schema
294305
networkInterface: createNeworkInterface(ctx),
306+
...ctx.apollo.options,
295307
});
308+
}
296309

297-
// Create a new Redux store for this request
298-
ctx.store = createNewStore(ctx.apollo);
310+
// Create a new Redux store for this request, if we don't have one
311+
if (!ctx.store) {
312+
ctx.store = createNewStore(ctx.apollo.client);
313+
}
299314

300-
// Pass to the next middleware in the chain: React, custom middleware, etc
301-
return next();
302-
});
315+
// Pass to the next middleware in the chain: React, custom middleware, etc
316+
return next();
317+
});
303318

304319
/* FORCE SSL */
305320

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "reactql-app",
3-
"version": "2.9.0",
3+
"version": "2.9.1",
44
"description": "ReactQL starter kit app",
55
"license": "UNLICENSED",
66
"private": true,

src/app.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,9 +182,15 @@ if (SERVER) {
182182
// We can set custom middleware to be processed on the server. This gives us
183183
// fine-grain control over headers, requests, responses etc, and even decide
184184
// if we want to avoid the React handler until certain conditions
185+
186+
// There are two flavours of middleware -- `before` middleware, which
187+
// executes in Koa before the per-request Apollo client / Redux store has
188+
// been instantiated... and can be called with `confiig.addBeforeMiddleware`
189+
190+
// ... and 'after' middleware, which runs after per-request instantiation.
191+
// Let's use the latter to add a custom header so we can see middleware in action
185192
config.addMiddleware(async (ctx, next) => {
186-
// Let's add a custom header so we can see middleware in action
187-
ctx.set('Powered-By', ctx.engine); // <-- `ctx.engine` srt above!
193+
ctx.set('Powered-By', ctx.engine); // <-- `ctx.engine` from `config.getKoaApp()` above!
188194

189195
// For the fun of it, let's demonstrate that we can fire Redux actions
190196
// and it'll manipulate the state on the server side! View the SSR version

src/components/main/index.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,11 @@ import { Redirect } from 'kit/lib/routing';
4848
// Child React components. Note: We can either export one main React component
4949
// per file, or in the case of <Home>, <Page> and <WhenFound>, we can group
5050
// multiple components per file where it makes sense to do so
51-
import GraphQLMessage from 'src/components/graphql';
52-
import { Home, Page, WhenNotFound } from 'src/components/routes';
53-
import ReduxCounter from 'src/components/redux';
54-
import Stats from 'src/components/stats';
55-
import Styles from 'src/components/styles';
51+
import GraphQLMessage from 'components/graphql';
52+
import { Home, Page, WhenNotFound } from 'components/routes';
53+
import ReduxCounter from 'components/redux';
54+
import Stats from 'components/stats';
55+
import Styles from 'components/styles';
5656

5757
// Styles
5858
import css from './main.scss';

0 commit comments

Comments
 (0)