From c431cfc2adf22d6ff5a9eba516e43199251309b8 Mon Sep 17 00:00:00 2001 From: Sresan Thevarajah Date: Wed, 16 Nov 2016 19:40:40 -0800 Subject: [PATCH] Hook for custom middleware (#708) * Provide hook for custom middleware setup * change documentation a little * More documentation... * Small edits to describe * Fix up documentation after pr feedback --- docs/guides/react-server-cli.md | 18 ++++++++++ .../react-server-cli/src/commands/start.js | 36 +++++++++++++++---- packages/react-server-cli/src/parseCliArgs.js | 5 +++ 3 files changed, 53 insertions(+), 6 deletions(-) diff --git a/docs/guides/react-server-cli.md b/docs/guides/react-server-cli.md index d3eabbe1c..e90c6ccf6 100755 --- a/docs/guides/react-server-cli.md +++ b/docs/guides/react-server-cli.md @@ -114,9 +114,22 @@ export default (webpackConfig) => { In the `.reactserverrc` file add an option for `webpack-config` that points to that function file and when React Server is setting up Webpack it will call your function with the result of the built in Webpack options, allowing you to make any modifications needed. +### Use Custom Express Middleware +Currently the default Express Middlewares used are compression, body-parser, cookie-parser. If you need to setup custom express middleware you can do it with a setup function. +```javascript +export default (server, reactServerMiddleware) => { + server.use(compression()); + server.use(bodyParser.urlencoded({ extended: false })); + server.use(bodyParser.json()); + server.use(session(options)); + reactServerMiddleware(); // Must be called once or server will not start +} +``` +In the `.reactserverrc` file add an option for `customMiddlewarePath` that points to that function file and when React Server is setting up the server it will call your function for setup rather then the default middlewares mentioned above. This may also be specified on the command line with the `--custom-middleware-path=` option. + ### Development mode: making a great DX Development mode is the default, and its goals are rapid startup and code-test @@ -237,6 +250,11 @@ Minify client JavaScript and CSS. Defaults to **false** in development mode and **true** in production. +#### --custom-middleware-path +Path to the custom middleware function file. If it is not defined the default setup will be applied which include body-parser, compression and cookie-parser. + +Defaults to **undefined**. + #### --long-term-caching Adds hashes to all JavaScript and CSS file names output by the build, allowing for the static files to be served with far-future expires headers. This option diff --git a/packages/react-server-cli/src/commands/start.js b/packages/react-server-cli/src/commands/start.js index c4819c467..730dccfb0 100644 --- a/packages/react-server-cli/src/commands/start.js +++ b/packages/react-server-cli/src/commands/start.js @@ -1,5 +1,6 @@ import http from "http" import https from "https" +import path from "path" import express from "express" import compression from "compression" import bodyParser from "body-parser" @@ -28,6 +29,7 @@ export default function start(options){ jsUrl, httpsOptions, longTermCaching, + customMiddlewarePath, } = options; const {serverRoutes, compiler} = compileClient(options); @@ -46,7 +48,7 @@ export default function start(options){ logger.notice("Starting servers...") const jsServer = startJsServer(compiler, jsPort, host, longTermCaching, httpsOptions); - const htmlServerPromise = serverRoutes.then(serverRoutesFile => startHtmlServer(serverRoutesFile, port, host, httpsOptions)); + const htmlServerPromise = serverRoutes.then(serverRoutesFile => startHtmlServer(serverRoutesFile, port, host, httpsOptions, customMiddlewarePath)); return { stop: () => Promise.all([jsServer.stop(), htmlServerPromise.then(server => server.stop())]), @@ -59,21 +61,43 @@ export default function start(options){ return startServers(); } + // given the server routes file and a port, start a react-server HTML server at // http://host:port/. returns an object with two properties, started and stop; // see the default function doc for explanation. -const startHtmlServer = (serverRoutes, port, host, httpsOptions) => { +const startHtmlServer = (serverRoutes, port, host, httpsOptions, customMiddlewarePath) => { const server = express(); const httpServer = httpsOptions ? https.createServer(httpsOptions, server) : http.createServer(server); + let middlewareSetup = (server, rsMiddleware) => { + server.use(compression()); + server.use(bodyParser.urlencoded({ extended: false })); + server.use(bodyParser.json()); + rsMiddleware(); + } + return { stop: serverToStopPromise(httpServer), started: new Promise((resolve, reject) => { logger.info("Starting HTML server..."); - server.use(compression()); - server.use(bodyParser.urlencoded({ extended: false })) - server.use(bodyParser.json()) - reactServer.middleware(server, require(serverRoutes)); + let rsMiddlewareCalled = false; + const rsMiddleware = () => { + rsMiddlewareCalled = true; + reactServer.middleware(server, require(serverRoutes)); + } + + if (customMiddlewarePath) { + const customMiddlewareDirAb = path.resolve(process.cwd(), customMiddlewarePath); + middlewareSetup = require(customMiddlewareDirAb).default; + } + + middlewareSetup(server, rsMiddleware); + + if (!rsMiddlewareCalled) { + console.error("Error react-server middleware was never setup in custom middleware function"); + reject("Custom middleware did not setup react-server middleware"); + return; + } httpServer.on('error', (e) => { console.error("Error starting up HTML server"); diff --git a/packages/react-server-cli/src/parseCliArgs.js b/packages/react-server-cli/src/parseCliArgs.js index 4de52de2d..0620b60c7 100644 --- a/packages/react-server-cli/src/parseCliArgs.js +++ b/packages/react-server-cli/src/parseCliArgs.js @@ -62,6 +62,11 @@ export default (args = process.argv) => { default: undefined, type: "boolean", }) + .option("custom-middleware-path", { + describe: "Path to custom middleware function file. If it is not defined default setup will be applied.", + default: undefined, + type: "string", + }) .option("long-term-caching", { describe: "Use long-term cache headers for the static JS & CSS files. Default is true in production mode, false otherwise.", default: undefined,