|
1 | 1 | // Simple class to act as a singleton for app-wide configuration. |
2 | 2 |
|
3 | | -class Config { |
| 3 | +// We'll start with a common config that can be extended separately by the |
| 4 | +// server/client, to provide environment-specific functionality |
| 5 | +class Common { |
4 | 6 | constructor() { |
5 | 7 | // Store reducers in a `Map`, for easy key retrieval |
6 | 8 | this.reducers = new Map(); |
7 | 9 |
|
8 | | - // Create a set for routes -- to retrieve based on insertion order |
9 | | - this.routes = new Set(); |
10 | | - |
11 | | - // Custom middleware -- again, based on insertion order |
12 | | - this.middleware = new Set(); |
| 10 | + // Apollo (middle|after)ware |
| 11 | + this.apolloMiddleware = []; |
| 12 | + this.apolloAfterware = []; |
13 | 13 |
|
14 | 14 | // GraphQL endpoint. This needs setting via either `config.enableGraphQLServer()` |
15 | 15 | // or `config.setGraphQLEndpoint()` |
16 | 16 | this.graphQLEndpoint = null; |
17 | 17 |
|
18 | 18 | // Set to true if we're using an internal GraphQL server |
19 | 19 | this.graphQLServer = false; |
20 | | - |
21 | | - // GraphQL schema (if we're using an internal server) |
22 | | - this.graphQLSchema = null; |
23 | | - |
24 | | - // Attach a GraphiQL IDE endpoint to our server? By default - no. If |
25 | | - // this === true, this will default to `/graphql`. If it's a string, it'll |
26 | | - // default to the string value |
27 | | - this.graphiQL = false; |
28 | | - |
29 | | - // Enable body parsing by default. Leave `koa-bodyparser` opts as default |
30 | | - this.enableBodyParser = true; |
31 | | - this.bodyParserOptions = {}; |
32 | 20 | } |
33 | 21 |
|
34 | 22 | /* REDUX */ |
35 | 23 |
|
36 | | - // Adds a new reducer. Checks that `reducer` fits the right shape, otherwise |
37 | | - // throws an error |
38 | | - addReducer(key, reducer) { |
39 | | - if (typeof reducer !== 'object' || !reducer.state || typeof reducer.reducer !== 'function') { |
40 | | - throw new Error(`Can't add reducer for '${key}' - reducer must be an object of {state, reducer}`); |
| 24 | + // Adds a new reducer. Accepts a `key` string, a `reducer` function, and a |
| 25 | + // (by default empty) `initialState` object, which will ultimately become immutable |
| 26 | + addReducer(key, reducer, initialState = {}) { |
| 27 | + if (typeof reducer !== 'function') { |
| 28 | + throw new Error(`Can't add reducer for '${key}' - reducer must be a function`); |
41 | 29 | } |
42 | | - this.reducers.set(key, reducer); |
| 30 | + this.reducers.set(key, { |
| 31 | + reducer, |
| 32 | + initialState, |
| 33 | + }); |
43 | 34 | } |
44 | 35 |
|
45 | | - /* WEB SERVER / SSR */ |
| 36 | + /* GRAPHQL */ |
46 | 37 |
|
47 | | - // Disable the optional `koa-bodyparser`, to prevent POST data being sent to |
48 | | - // each request. By default, body parsing is enabled. |
49 | | - disableBodyParser() { |
50 | | - this.enableBodyParser = false; |
| 38 | + // Enables internal GraphQL server. Default GraphQL and GraphiQL endpoints |
| 39 | + // can be overridden |
| 40 | + enableGraphQLServer(endpoint = '/graphql', graphiQL = true) { |
| 41 | + this.graphQLServer = true; |
| 42 | + this.graphQLEndpoint = endpoint; |
| 43 | + this.graphiQL = graphiQL; |
51 | 44 | } |
52 | 45 |
|
53 | | - setBodyParserOptions(opt = {}) { |
54 | | - this.bodyParserOptions = opt; |
| 46 | + // Set an external GraphQL URI for use with Apollo |
| 47 | + setGraphQLEndpoint(uri, graphiQL = true) { |
| 48 | + this.graphQLEndpoint = uri; |
| 49 | + this.graphiQL = graphiQL; |
55 | 50 | } |
56 | 51 |
|
57 | | - // Add custom middleware. This should be an async func, for use with Koa |
58 | | - addMiddleware(middlewareFunc) { |
59 | | - this.middleware.add(middlewareFunc); |
| 52 | + // Register Apollo middleware function |
| 53 | + addApolloMiddleware(middlewareFunc) { |
| 54 | + this.apolloMiddleware.push(middlewareFunc); |
60 | 55 | } |
61 | 56 |
|
62 | | - // Adds a custom server route to attach to our Koa router |
63 | | - addRoute(method, route, handler) { |
64 | | - this.routes.add({ |
65 | | - method, |
66 | | - route, |
67 | | - handler, |
68 | | - }); |
| 57 | + // Register Apollo afterware function |
| 58 | + addApolloAfterware(afterwareFunc) { |
| 59 | + this.apolloAfterware.push(afterwareFunc); |
69 | 60 | } |
| 61 | +} |
70 | 62 |
|
71 | | - // Adds custom GET route |
72 | | - addGetRoute(route, handler) { |
73 | | - this.addRoute('get', route, handler); |
74 | | - } |
| 63 | +// Placeholder for the class we'll attach |
| 64 | +let Config; |
75 | 65 |
|
76 | | - // Adds custom POST route |
77 | | - addPostRoute(route, handler) { |
78 | | - this.addRoute('post', route, handler); |
79 | | - } |
| 66 | +// Server Config extensions. This is wrapped in a `SERVER` block to avoid |
| 67 | +// adding unnecessary functionality to the server bundle. Every byte counts! |
| 68 | +if (SERVER) { |
| 69 | + Config = class ServerConfig extends Common { |
| 70 | + constructor() { |
| 71 | + super(); |
| 72 | + // Create a set for routes -- to retrieve based on insertion order |
| 73 | + this.routes = new Set(); |
80 | 74 |
|
81 | | - // Adds custom PUT route |
82 | | - addPutRoute(route, handler) { |
83 | | - this.addRoute('put', route, handler); |
84 | | - } |
| 75 | + // Custom middleware -- again, based on insertion order |
| 76 | + this.middleware = new Set(); |
85 | 77 |
|
86 | | - // Adds custom PATCH route |
87 | | - addPatchRoute(route, handler) { |
88 | | - this.addRoute('patch', route, handler); |
89 | | - } |
| 78 | + // GraphQL schema (if we're using an internal server) |
| 79 | + this.graphQLSchema = null; |
90 | 80 |
|
91 | | - // Adds custom DELETE route |
92 | | - addDeleteRoute(route, handler) { |
93 | | - this.addRoute('delete', route, handler); |
94 | | - } |
| 81 | + // Attach a GraphiQL IDE endpoint to our server? By default - no. If |
| 82 | + // this === true, this will default to `/graphql`. If it's a string, it'll |
| 83 | + // default to the string value |
| 84 | + this.graphiQL = false; |
95 | 85 |
|
96 | | - // 404 handler for the server. By default, `kit/entry/server.js` will |
97 | | - // simply return a 404 status code without modifying the HTML render. By |
98 | | - // setting a handler here, this will be returned instead |
99 | | - set404Handler(func) { |
100 | | - if (typeof func !== 'function') { |
101 | | - throw new Error('404 handler must be a function'); |
| 86 | + // Enable body parsing by default. Leave `koa-bodyparser` opts as default |
| 87 | + this.enableBodyParser = true; |
| 88 | + this.bodyParserOptions = {}; |
102 | 89 | } |
103 | | - this.handler404 = func; |
104 | | - } |
105 | 90 |
|
106 | | - /* GRAPHQL */ |
| 91 | + /* WEB SERVER / SSR */ |
107 | 92 |
|
108 | | - // Enables internal GraphQL server. Default GraphQL and GraphiQL endpoints |
109 | | - // can be overridden |
110 | | - enableGraphQLServer(endpoint = '/graphql', graphiQL = true) { |
111 | | - this.graphQLServer = true; |
112 | | - this.graphQLEndpoint = endpoint; |
113 | | - this.graphiQL = graphiQL; |
114 | | - } |
| 93 | + // Disable the optional `koa-bodyparser`, to prevent POST data being sent to |
| 94 | + // each request. By default, body parsing is enabled. |
| 95 | + disableBodyParser() { |
| 96 | + this.enableBodyParser = false; |
| 97 | + } |
115 | 98 |
|
116 | | - // Set the GraphQL schema. This should only be called on the server, otherwise |
117 | | - // the bundle size passed by the `schema` object will be unnecessarily inflated |
118 | | - setGraphQLSchema(schema) { |
119 | | - this.graphQLSchema = schema; |
120 | | - } |
| 99 | + setBodyParserOptions(opt = {}) { |
| 100 | + this.bodyParserOptions = opt; |
| 101 | + } |
121 | 102 |
|
122 | | - // Set an external GraphQL URI for use with Apollo |
123 | | - setGraphQLEndpoint(uri, graphiQL = true) { |
124 | | - this.graphQLEndpoint = uri; |
125 | | - this.graphiQL = graphiQL; |
126 | | - } |
| 103 | + // 404 handler for the server. By default, `kit/entry/server.js` will |
| 104 | + // simply return a 404 status code without modifying the HTML render. By |
| 105 | + // setting a handler here, this will be returned instead |
| 106 | + set404Handler(func) { |
| 107 | + if (typeof func !== 'function') { |
| 108 | + throw new Error('404 handler must be a function'); |
| 109 | + } |
| 110 | + this.handler404 = func; |
| 111 | + } |
| 112 | + |
| 113 | + // Add custom middleware. This should be an async func, for use with Koa |
| 114 | + addMiddleware(middlewareFunc) { |
| 115 | + this.middleware.add(middlewareFunc); |
| 116 | + } |
| 117 | + |
| 118 | + // Adds a custom server route to attach to our Koa router |
| 119 | + addRoute(method, route, handler) { |
| 120 | + this.routes.add({ |
| 121 | + method, |
| 122 | + route, |
| 123 | + handler, |
| 124 | + }); |
| 125 | + } |
| 126 | + |
| 127 | + // Adds custom GET route |
| 128 | + addGetRoute(route, handler) { |
| 129 | + this.addRoute('get', route, handler); |
| 130 | + } |
| 131 | + |
| 132 | + // Adds custom POST route |
| 133 | + addPostRoute(route, handler) { |
| 134 | + this.addRoute('post', route, handler); |
| 135 | + } |
| 136 | + |
| 137 | + // Adds custom PUT route |
| 138 | + addPutRoute(route, handler) { |
| 139 | + this.addRoute('put', route, handler); |
| 140 | + } |
| 141 | + |
| 142 | + // Adds custom PATCH route |
| 143 | + addPatchRoute(route, handler) { |
| 144 | + this.addRoute('patch', route, handler); |
| 145 | + } |
| 146 | + |
| 147 | + // Adds custom DELETE route |
| 148 | + addDeleteRoute(route, handler) { |
| 149 | + this.addRoute('delete', route, handler); |
| 150 | + } |
| 151 | + |
| 152 | + // Set the GraphQL schema. This should only be called on the server, otherwise |
| 153 | + // the bundle size passed by the `schema` object will be unnecessarily inflated |
| 154 | + setGraphQLSchema(schema) { |
| 155 | + this.graphQLSchema = schema; |
| 156 | + } |
| 157 | + }; |
| 158 | +} else { |
| 159 | + // For the client config, we'll extend `Common` by default -- but if we need |
| 160 | + // anything unique to the browser in the future, we'd add it here... |
| 161 | + Config = class ClientConfig extends Common {}; |
127 | 162 | } |
128 | 163 |
|
129 | 164 | // Since there's only one `Config` instance globally, we'll create the new |
|
0 commit comments