From 89fb45b06c6c8b85fb6031e8b4e89f09d64aec8d Mon Sep 17 00:00:00 2001 From: Bo Borgerson Date: Mon, 1 Aug 2016 14:13:32 -0700 Subject: [PATCH 01/16] CLI command argument parsing --- packages/react-server-cli/src/parseCliArgs.js | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/packages/react-server-cli/src/parseCliArgs.js b/packages/react-server-cli/src/parseCliArgs.js index bb6c28e8c..71ba502e5 100644 --- a/packages/react-server-cli/src/parseCliArgs.js +++ b/packages/react-server-cli/src/parseCliArgs.js @@ -2,7 +2,7 @@ import yargs from "yargs" import fs from "fs" export default (args = process.argv) => { - var parsedArgs = yargs(args) + var argsDefinition = yargs(args) .usage('Usage: $0 [options]') .option("routes-file", { describe: "The routes file to load. Default is 'routes.js'.", @@ -94,7 +94,27 @@ export default (args = process.argv) => { .help('?') .alias('?', 'help') .demand(0) - .argv; + + const commands = { + "start" : "Start the server", + "compile" : "Compile static assets", + "init" : "Create a routes file and a .reactserverrc", + } + + Object.keys(commands) + .forEach(k => argsDefinition = argsDefinition.command(k, commands[k])); + + var parsedArgs = argsDefinition.argv; + + parsedArgs.command = parsedArgs._[2]; + + if (!commands[parsedArgs.command]) { + argsDefinition.showHelp(); + if (parsedArgs.command) { + console.log("Invalid command: " + parsedArgs.command); + } + process.exit(1); // eslint-disable-line no-process-exit + } if (parsedArgs.https && (parsedArgs.httpsKey || parsedArgs.httpsCert || parsedArgs.httpsCa || parsedArgs.httpsPfx || parsedArgs.httpsPassphrase)) { throw new Error("If you set https to true, you must not set https-key, https-cert, https-ca, https-pfx, or https-passphrase."); From dcc5ef73fa894922453436878c03b6aa785ce70b Mon Sep 17 00:00:00 2001 From: Bo Borgerson Date: Mon, 1 Aug 2016 15:23:02 -0700 Subject: [PATCH 02/16] Consolidate HTTPS option validation --- packages/react-server-cli/src/parseCliArgs.js | 12 ++++++++---- packages/react-server-cli/src/startServer.js | 4 ---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/react-server-cli/src/parseCliArgs.js b/packages/react-server-cli/src/parseCliArgs.js index 71ba502e5..c7928c2d9 100644 --- a/packages/react-server-cli/src/parseCliArgs.js +++ b/packages/react-server-cli/src/parseCliArgs.js @@ -116,10 +116,6 @@ export default (args = process.argv) => { process.exit(1); // eslint-disable-line no-process-exit } - if (parsedArgs.https && (parsedArgs.httpsKey || parsedArgs.httpsCert || parsedArgs.httpsCa || parsedArgs.httpsPfx || parsedArgs.httpsPassphrase)) { - throw new Error("If you set https to true, you must not set https-key, https-cert, https-ca, https-pfx, or https-passphrase."); - } - // we remove all the options that have undefined as their value; those are the // ones that weren't on the command line, and we don't want them to override // defaults or config files. @@ -139,6 +135,14 @@ const sslize = argv => { } } + if (argv.https && (argv.httpsKey || argv.httpsCert || argv.httpsCa || argv.httpsPfx || argv.httpsPassphrase)) { + throw new Error("If you set https to true, you must not set https-key, https-cert, https-ca, https-pfx, or https-passphrase."); + } + + if ((argv.key || argv.cert || argv.ca) && argv.pfx) { + throw new Error("If you set https.pfx, you can't set https.key, https.cert, or https.ca."); + } + return argv; } diff --git a/packages/react-server-cli/src/startServer.js b/packages/react-server-cli/src/startServer.js index cc28c408d..538c632bc 100644 --- a/packages/react-server-cli/src/startServer.js +++ b/packages/react-server-cli/src/startServer.js @@ -44,10 +44,6 @@ const startImpl = ({ https: httpsOptions, longTermCaching, }) => { - if ((httpsOptions.key || httpsOptions.cert || httpsOptions.ca) && httpsOptions.pfx) { - throw new Error("If you set https.pfx, you can't set https.key, https.cert, or https.ca."); - } - const routesPath = path.resolve(process.cwd(), routesFile); const routes = require(routesPath); From 010f42fced6131a4457b144907e331ebbdcfd714 Mon Sep 17 00:00:00 2001 From: Bo Borgerson Date: Mon, 1 Aug 2016 15:27:02 -0700 Subject: [PATCH 03/16] Eliminate a temporary name for `httpsOptions` --- packages/react-server-cli/src/parseCliArgs.js | 2 +- packages/react-server-cli/src/startServer.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/react-server-cli/src/parseCliArgs.js b/packages/react-server-cli/src/parseCliArgs.js index c7928c2d9..44bf9b1d0 100644 --- a/packages/react-server-cli/src/parseCliArgs.js +++ b/packages/react-server-cli/src/parseCliArgs.js @@ -126,7 +126,7 @@ export default (args = process.argv) => { const sslize = argv => { if (argv.httpsKey || argv.httpsCert || argv.httpsCa || argv.httpsPfx || argv.httpsPassphrase) { - argv.https = { + argv.httpsOptions = { key: argv.httpsKey ? fs.readFileSync(argv.httpsKey) : undefined, cert: argv.httpsCert ? fs.readFileSync(argv.httpsCert) : undefined, ca: argv.httpsCa ? fs.readFileSync(argv.httpsCa) : undefined, diff --git a/packages/react-server-cli/src/startServer.js b/packages/react-server-cli/src/startServer.js index 538c632bc..119cf4eae 100644 --- a/packages/react-server-cli/src/startServer.js +++ b/packages/react-server-cli/src/startServer.js @@ -41,7 +41,7 @@ const startImpl = ({ compileOnly, jsUrl, stats, - https: httpsOptions, + httpsOptions, longTermCaching, }) => { const routesPath = path.resolve(process.cwd(), routesFile); From 5f3a3baed610ca9539f69274f4623f7d5642eb7d Mon Sep 17 00:00:00 2001 From: Bo Borgerson Date: Mon, 1 Aug 2016 16:59:25 -0700 Subject: [PATCH 04/16] Add commands to react-server-cli - start - compile - init (not yet implemented) --- README.md | 2 +- docs/testing-ports.md | 2 +- .../generators/app/templates/package.json | 2 +- .../generators/app/templates/test.js | 2 +- packages/react-server-cli/src/cli.js | 4 +- .../react-server-cli/src/commands/compile.js | 21 +++ .../react-server-cli/src/commands/init.js | 9 + .../src/{startServer.js => commands/start.js} | 175 ++++-------------- .../react-server-cli/src/compileClient.js | 9 +- .../src/handleCompilationErrors.js | 30 +++ packages/react-server-cli/src/index.js | 6 +- packages/react-server-cli/src/run.js | 69 +++++++ .../src/specRuntime/testHelper.js | 5 +- packages/react-server-test-pages/cli.js | 4 +- packages/react-server-test-pages/package.json | 4 +- packages/react-server-website/.reactserverrc | 15 +- packages/react-server-website/cli.js | 4 +- .../content/HomeGetStartedSection.md | 2 +- packages/react-server-website/package.json | 6 +- packages/react-server/README.md | 2 +- 20 files changed, 204 insertions(+), 169 deletions(-) create mode 100644 packages/react-server-cli/src/commands/compile.js create mode 100644 packages/react-server-cli/src/commands/init.js rename packages/react-server-cli/src/{startServer.js => commands/start.js} (53%) create mode 100644 packages/react-server-cli/src/handleCompilationErrors.js create mode 100644 packages/react-server-cli/src/run.js diff --git a/README.md b/README.md index 9e39d2d83..a24393585 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ yo react-server # compile and run the new app npm run compile npm run start -# go to http://localhost:3010 +# go to http://localhost:3000 ``` That hooks you up with [`react-server-cli`](packages/react-server-cli), which diff --git a/docs/testing-ports.md b/docs/testing-ports.md index b36a3c1ec..6ef293562 100644 --- a/docs/testing-ports.md +++ b/docs/testing-ports.md @@ -4,7 +4,7 @@ simultaneously, so port conflicts will fail the tests. Make sure to update this manifest when adding a test that starts a server. ## generator-react-server -3010, 3011 +3000, 3001 ## react-server-integration-test 8771, 3001 diff --git a/packages/generator-react-server/generators/app/templates/package.json b/packages/generator-react-server/generators/app/templates/package.json index e97cf1ccf..0226dcfa3 100644 --- a/packages/generator-react-server/generators/app/templates/package.json +++ b/packages/generator-react-server/generators/app/templates/package.json @@ -4,7 +4,7 @@ "description": "A react-server instance", "main": "HelloWorld.js", "scripts": { - "start": "react-server --port 3010 --js-port 3011", + "start": "react-server start", "test": "xo && nsp check && ava test.js" }, "license": "Apache-2.0", diff --git a/packages/generator-react-server/generators/app/templates/test.js b/packages/generator-react-server/generators/app/templates/test.js index 2c4210057..5d408d455 100644 --- a/packages/generator-react-server/generators/app/templates/test.js +++ b/packages/generator-react-server/generators/app/templates/test.js @@ -23,7 +23,7 @@ function getResponseCode(url) { return new Promise((resolve, reject) => { const req = http.get({ hostname: 'localhost', - port: 3010, + port: 3000, path: url }, res => { resolve(res.statusCode); diff --git a/packages/react-server-cli/src/cli.js b/packages/react-server-cli/src/cli.js index bc25aac0d..4f59b8352 100755 --- a/packages/react-server-cli/src/cli.js +++ b/packages/react-server-cli/src/cli.js @@ -1,5 +1,5 @@ require("babel-core/register"); -const {start, parseCliArgs} = require("."); +const {run, parseCliArgs} = require("."); -start(parseCliArgs()); +run(parseCliArgs()); diff --git a/packages/react-server-cli/src/commands/compile.js b/packages/react-server-cli/src/commands/compile.js new file mode 100644 index 000000000..b6882e11c --- /dev/null +++ b/packages/react-server-cli/src/commands/compile.js @@ -0,0 +1,21 @@ +import compileClient from "../compileClient" +import callerDependency from "../callerDependency"; +import handleCompilationErrors from "../handleCompilationErrors"; + +const reactServer = require(callerDependency("react-server")); + +const logger = reactServer.logging.getLogger(__LOGGER__); + +export default function compile(options){ + const {compiler} = compileClient(options); + + logger.notice("Starting compilation of client JavaScript..."); + compiler.run((err, stats) => { + const error = handleCompilationErrors(err, stats); + if (!error) { + logger.notice("Successfully compiled client JavaScript."); + } else { + logger.error(error); + } + }); +} diff --git a/packages/react-server-cli/src/commands/init.js b/packages/react-server-cli/src/commands/init.js new file mode 100644 index 000000000..39125b72d --- /dev/null +++ b/packages/react-server-cli/src/commands/init.js @@ -0,0 +1,9 @@ +import callerDependency from "../callerDependency"; + +const reactServer = require(callerDependency("react-server")); + +const logger = reactServer.logging.getLogger(__LOGGER__); + +export default function compile(){ + logger.notice("Coming soon!"); +} diff --git a/packages/react-server-cli/src/startServer.js b/packages/react-server-cli/src/commands/start.js similarity index 53% rename from packages/react-server-cli/src/startServer.js rename to packages/react-server-cli/src/commands/start.js index 119cf4eae..3d90b11de 100644 --- a/packages/react-server-cli/src/startServer.js +++ b/packages/react-server-cli/src/commands/start.js @@ -1,15 +1,12 @@ import http from "http" import https from "https" import express from "express" -import path from "path" import pem from "pem" import compression from "compression" -import defaultOptions from "./defaultOptions" import WebpackDevServer from "webpack-dev-server" -import compileClient from "./compileClient" -import mergeOptions from "./mergeOptions" -import findOptionsInFiles from "./findOptionsInFiles" -import callerDependency from "./callerDependency"; +import compileClient from "../compileClient" +import callerDependency from "../callerDependency"; +import handleCompilationErrors from "../handleCompilationErrors"; const reactServer = require(callerDependency("react-server")); @@ -19,99 +16,56 @@ const logger = reactServer.logging.getLogger(__LOGGER__); // stop. started is a promise that resolves when all necessary servers have been // started. stop is a method to stop all servers. It takes no arguments and // returns a promise that resolves when the server has stopped. -export default (options = {}) => { - // for the option properties that weren't sent in, look for a config file - // (either .reactserverrc or a reactServer section in a package.json). for - // options neither passed in nor in a config file, use the defaults. - options = mergeOptions(defaultOptions, findOptionsInFiles() || {}, options); - - setupLogging(options.logLevel, options.timingLogLevel, options.gaugeLogLevel); - logProductionWarnings(options); - - return startImpl(options); -} - -const startImpl = ({ - routesFile, - host, +export default function start(options){ + const { port, jsPort, hot, - minify, - compileOnly, jsUrl, - stats, httpsOptions, longTermCaching, -}) => { - const routesPath = path.resolve(process.cwd(), routesFile); - const routes = require(routesPath); + } = options; - const outputUrl = jsUrl || `${httpsOptions ? "https" : "http"}://${host}:${jsPort}/`; + const {serverRoutes, compiler} = compileClient(options); - const {serverRoutes, compiler} = compileClient(routes, { - routesDir: path.dirname(routesPath), - hot, - minify, - outputUrl, - longTermCaching, - stats, - }); + const startServers = (keys) => { + // if jsUrl is set, we need to run the compiler, but we don't want to start a JS + // server. + let startJsServer = startDummyJsServer; - if (compileOnly) { - logger.notice("Starting compilation of client JavaScript..."); - compiler.run((err, stats) => { - const error = handleCompilationErrors(err, stats); - if (!error) { - logger.notice("Successfully compiled client JavaScript."); - } else { - logger.error(error); - } - }); - // TODO: it's odd that this returns something different than the other branch; - // should probably separate compile and start into two different exported functions. - return null; - } else { - const startServers = (keys) => { - // if jsUrl is set, we need to run the compiler, but we don't want to start a JS - // server. - let startJsServer = startDummyJsServer; - - if (!jsUrl) { - // if jsUrl is not set, we need to start up a JS server, either hot load - // or static. - startJsServer = hot ? startHotLoadJsServer : startStaticJsServer; - } + if (!jsUrl) { + // if jsUrl is not set, we need to start up a JS server, either hot load + // or static. + startJsServer = hot ? startHotLoadJsServer : startStaticJsServer; + } - logger.notice("Starting servers...") + logger.notice("Starting servers...") - const jsServer = startJsServer(compiler, jsPort, longTermCaching, keys); - const htmlServerPromise = serverRoutes.then(serverRoutesFile => startHtmlServer(serverRoutesFile, port, keys)); + const jsServer = startJsServer(compiler, jsPort, longTermCaching, keys); + const htmlServerPromise = serverRoutes.then(serverRoutesFile => startHtmlServer(serverRoutesFile, port, keys)); - return { - stop: () => Promise.all([jsServer.stop(), htmlServerPromise.then(server => server.stop())]), - started: Promise.all([jsServer.started, htmlServerPromise.then(server => server.started)]) - .catch(e => {logger.error(e); throw e}) - .then(() => logger.notice(`Ready for requests on port ${port}.`)), - }; - } + return { + stop: () => Promise.all([jsServer.stop(), htmlServerPromise.then(server => server.stop())]), + started: Promise.all([jsServer.started, htmlServerPromise.then(server => server.started)]) + .catch(e => {logger.error(e); throw e}) + .then(() => logger.notice(`Ready for requests on port ${port}.`)), + }; + } - if (httpsOptions === true) { - // if httpsOptions was true (and so didn't send in keys), generate keys. - pem.createCertificate({days:1, selfSigned:true}, (err, keys) => { - if (err) throw err; - return startServers({key: keys.serviceKey, cert:keys.certificate}); - }); - } else if (httpsOptions) { - // in this case, we assume that httpOptions is an object that can be passed - // in to https.createServer as options. - return startServers(httpsOptions); - } else { - // use http. - return startServers(); - } + if (httpsOptions === true) { + // if httpsOptions was true (and so didn't send in keys), generate keys. + pem.createCertificate({days:1, selfSigned:true}, (err, keys) => { + if (err) throw err; + return startServers({key: keys.serviceKey, cert:keys.certificate}); + }); + } else if (httpsOptions) { + // in this case, we assume that httpOptions is an object that can be passed + // in to https.createServer as options. + return startServers(httpsOptions); } - return null; // For eslint. :p + + // Default. Use http. + return startServers(); } // given the server routes file and a port, start a react-server HTML server at @@ -242,29 +196,6 @@ const startDummyJsServer = (compiler /*, port, longTermCaching, httpsOptions*/) }; }; -// takes in the err and stats object returned by a webpack compilation and returns -// an error object if something serious happened, or null if things are ok. -const handleCompilationErrors = (err, stats) => { - if (err) { - logger.error("Error during webpack build."); - logger.error(err); - return new Error(err); - // TODO: inspect stats to see if there are errors -sra. - } else if (stats.hasErrors()) { - console.error("There were errors in the JavaScript compilation."); - stats.toJson().errors.forEach((error) => { - console.error(error); - }); - return new Error("There were errors in the JavaScript compilation."); - } else if (stats.hasWarnings()) { - logger.warning("There were warnings in the JavaScript compilation. Note that this is normal if you are minifying your code."); - // for now, don't enumerate warnings; they are absolutely useless in minification mode. - // TODO: handle this more intelligently, perhaps with a --reportwarnings flag or with different - // behavior based on whether or not --minify is set. - } - return null; -} - // returns a method that can be used to stop the server. the returned method // returns a promise to indicate when the server is actually stopped. const serverToStopPromise = (server) => { @@ -301,31 +232,3 @@ const serverToStopPromise = (server) => { }); }; } - -const setupLogging = (logLevel, timingLogLevel, gaugeLogLevel) => { - reactServer.logging.setLevel('main', logLevel); - reactServer.logging.setLevel('time', timingLogLevel); - reactServer.logging.setLevel('gauge', gaugeLogLevel); -} - -const logProductionWarnings = ({hot, minify, jsUrl, longTermCaching}) => { - // if the server is being launched with some bad practices for production mode, then we - // should output a warning. if arg.jsurl is set, then hot and minify are moot, since - // we aren't serving JavaScript & CSS at all. - if ((!jsUrl && (hot || !minify)) || process.env.NODE_ENV !== "production" || !longTermCaching) { //eslint-disable-line no-process-env - logger.warning("PRODUCTION WARNING: the following current settings are discouraged in production environments. (If you are developing, carry on!):"); - if (hot) { - logger.warning("-- Hot reload is enabled. To disable, set hot to false (--hot=false at the command-line) or set NODE_ENV=production."); - } - - if (!minify) { - logger.warning("-- Minification is disabled. To enable, set minify to true (--minify at the command-line) or set NODE_ENV=production."); - } - - if (!longTermCaching) { - logger.warning("-- Long-term caching is disabled. To enable, set longTermCaching to true (--long-term-caching at the command-line) or set NODE_ENV=production to turn on."); - } - logger.info(`NODE_ENV is set to ${process.env.NODE_ENV}`); //eslint-disable-line no-process-env - } - -} diff --git a/packages/react-server-cli/src/compileClient.js b/packages/react-server-cli/src/compileClient.js index 37f9ac7ce..28140c8ce 100644 --- a/packages/react-server-cli/src/compileClient.js +++ b/packages/react-server-cli/src/compileClient.js @@ -20,8 +20,9 @@ import callerDependency from "./callerDependency" // once the compiler has been run. The file path returned from the promise // can be required and passed in to reactServer.middleware(). // TODO: add options for sourcemaps. -export default (routes, opts = {}) => { +export default (opts = {}) => { const { + routes, workingDir = "./__clientTemp", routesDir = ".", outputDir = workingDir + "/build", @@ -343,9 +344,9 @@ const writeClientBootstrapFile = (outputDir, opts) => { } var reactServer = require("react-server"); window.rfBootstrap = function() { - reactServer.logging.setLevel('main', ${opts.logLevel}); - reactServer.logging.setLevel('time', ${opts.timingLogLevel}); - reactServer.logging.setLevel('gauge', ${opts.gaugeLogLevel}); + reactServer.logging.setLevel('main', ${JSON.stringify(opts.logLevel)}); + reactServer.logging.setLevel('time', ${JSON.stringify(opts.timingLogLevel)}); + reactServer.logging.setLevel('gauge', ${JSON.stringify(opts.gaugeLogLevel)}); new reactServer.ClientController({routes: require("./routes_client")}).init(); }` ); diff --git a/packages/react-server-cli/src/handleCompilationErrors.js b/packages/react-server-cli/src/handleCompilationErrors.js new file mode 100644 index 000000000..84dc3b50e --- /dev/null +++ b/packages/react-server-cli/src/handleCompilationErrors.js @@ -0,0 +1,30 @@ +import callerDependency from "./callerDependency"; + +const reactServer = require(callerDependency("react-server")); + +const logger = reactServer.logging.getLogger(__LOGGER__); + +// takes in the err and stats object returned by a webpack compilation and returns +// an error object if something serious happened, or null if things are ok. +export default function handleCompilationErrors (err, stats){ + if (err) { + logger.error("Error during webpack build."); + logger.error(err); + return new Error(err); + // TODO: inspect stats to see if there are errors -sra. + } else if (stats.hasErrors()) { + console.error("There were errors in the JavaScript compilation."); + stats.toJson().errors.forEach((error) => { + console.error(error); + }); + return new Error("There were errors in the JavaScript compilation."); + } else if (stats.hasWarnings()) { + logger.warning("There were warnings in the JavaScript compilation. Note that this is normal if you are minifying your code."); + // for now, don't enumerate warnings; they are absolutely useless in minification mode. + // TODO: handle this more intelligently, perhaps with a --reportwarnings flag or with different + // behavior based on whether or not --minify is set. + } + return null; +} + + diff --git a/packages/react-server-cli/src/index.js b/packages/react-server-cli/src/index.js index 049d4411c..01565a58b 100644 --- a/packages/react-server-cli/src/index.js +++ b/packages/react-server-cli/src/index.js @@ -1,4 +1,6 @@ const fs = require('fs'); +const run = require("./run").default; +const parseCliArgs = require("./parseCliArgs").default; require.extensions['.css'] = require.extensions['.less'] = @@ -14,6 +16,6 @@ require.extensions['.md'] = }; module.exports = { - start: require("./startServer").default, - parseCliArgs: require("./parseCliArgs").default, + parseCliArgs, + run, }; diff --git a/packages/react-server-cli/src/run.js b/packages/react-server-cli/src/run.js new file mode 100644 index 000000000..363d2dfb7 --- /dev/null +++ b/packages/react-server-cli/src/run.js @@ -0,0 +1,69 @@ +import path from "path"; +import mergeOptions from "./mergeOptions" +import findOptionsInFiles from "./findOptionsInFiles" +import defaultOptions from "./defaultOptions" +import callerDependency from "./callerDependency"; + +const reactServer = require(callerDependency("react-server")); + +const logger = reactServer.logging.getLogger(__LOGGER__); + +export default function run(options = {}) { + + // for the option properties that weren't sent in, look for a config file + // (either .reactserverrc or a reactServer section in a package.json). for + // options neither passed in nor in a config file, use the defaults. + options = mergeOptions(defaultOptions, findOptionsInFiles() || {}, options); + + setupLogging(options.logLevel, options.timingLogLevel, options.gaugeLogLevel); + logProductionWarnings(options); + + const { + routesFile, + jsUrl, + jsPort, + host, + httpsOptions, + } = options; + + options.routesPath = path.resolve(process.cwd(), routesFile); + options.routesDir = path.dirname(options.routesPath); + + try { + options.routes = require(options.routesPath); + } catch (e) { + // Pass. Commands need to check for routes themselves. + } + + options.outputUrl = jsUrl || `${httpsOptions ? "https" : "http"}://${host}:${jsPort}/`; + + return require("./" + path.join("commands", options.command)).default(options); +} + +const setupLogging = (logLevel, timingLogLevel, gaugeLogLevel) => { + reactServer.logging.setLevel('main', logLevel); + reactServer.logging.setLevel('time', timingLogLevel); + reactServer.logging.setLevel('gauge', gaugeLogLevel); +} + +const logProductionWarnings = ({hot, minify, jsUrl, longTermCaching}) => { + // if the server is being launched with some bad practices for production mode, then we + // should output a warning. if arg.jsurl is set, then hot and minify are moot, since + // we aren't serving JavaScript & CSS at all. + if ((!jsUrl && (hot || !minify)) || process.env.NODE_ENV !== "production" || !longTermCaching) { //eslint-disable-line no-process-env + logger.warning("PRODUCTION WARNING: the following current settings are discouraged in production environments. (If you are developing, carry on!):"); + if (hot) { + logger.warning("-- Hot reload is enabled. To disable, set hot to false (--hot=false at the command-line) or set NODE_ENV=production."); + } + + if (!minify) { + logger.warning("-- Minification is disabled. To enable, set minify to true (--minify at the command-line) or set NODE_ENV=production."); + } + + if (!longTermCaching) { + logger.warning("-- Long-term caching is disabled. To enable, set longTermCaching to true (--long-term-caching at the command-line) or set NODE_ENV=production to turn on."); + } + logger.info(`NODE_ENV is set to ${process.env.NODE_ENV}`); //eslint-disable-line no-process-env + } + +} diff --git a/packages/react-server-integration-tests/src/specRuntime/testHelper.js b/packages/react-server-integration-tests/src/specRuntime/testHelper.js index 04161c1e8..b610093b1 100644 --- a/packages/react-server-integration-tests/src/specRuntime/testHelper.js +++ b/packages/react-server-integration-tests/src/specRuntime/testHelper.js @@ -3,7 +3,7 @@ var fs = require("fs"), mkdirp = require("mkdirp"), path = require("path"), Browser = require('zombie'), - start = require('react-server-cli').start, + CLI = require('react-server-cli'), crypto = require('crypto'); // This needs to be different from the port used by the tests that still live @@ -101,7 +101,8 @@ var startServer = function (specFile, routes) { var routesFile = writeRoutesFile(specFile, routes, testTempDir); - return start({ + return CLI.run({ + command: "start", routesFile: routesFile, hot: false, port: PORT, diff --git a/packages/react-server-test-pages/cli.js b/packages/react-server-test-pages/cli.js index 2724ef461..d146afff3 100644 --- a/packages/react-server-test-pages/cli.js +++ b/packages/react-server-test-pages/cli.js @@ -1,5 +1,5 @@ require("babel-core/register"); -const {start, parseCliArgs} = require("react-server-cli"); +const {run, parseCliArgs} = require("react-server-cli"); -start(parseCliArgs()); +run(parseCliArgs()); diff --git a/packages/react-server-test-pages/package.json b/packages/react-server-test-pages/package.json index d5ac493e1..dfbceb0de 100644 --- a/packages/react-server-test-pages/package.json +++ b/packages/react-server-test-pages/package.json @@ -6,9 +6,9 @@ "main": "index.js", "scripts": { "prepublish": "gulp build", - "start": "node ./cli.js", + "start": "node ./cli.js start", "test": "gulp test", - "debug": "node-debug --debug-brk=0 -p 9000 react-server-cli", + "debug": "node-debug --debug-brk=0 -p 9000 ./cli.js start", "clean": "rimraf npm-debug.log* __clientTemp target" }, "author": "Bo Borgerson", diff --git a/packages/react-server-website/.reactserverrc b/packages/react-server-website/.reactserverrc index 68e145741..c6c754f11 100644 --- a/packages/react-server-website/.reactserverrc +++ b/packages/react-server-website/.reactserverrc @@ -1,19 +1,18 @@ { "routes": "./routes.js", "host": "localhost", - "port": 3000, - "js-port": 3001, + "port": 3010, + "jsPort": 3011, "hot": false, "minify": false, - "long-term-caching": false, - "compile-only": false, + "longTermCaching": false, "https": false, - "log-level": "debug", + "logLevel": "debug", "env": { - "staging": { - "port": "4000" - }, "production": { + "jsUrl": "/assets/", + "logLevel": "error", + "minify": true, "port": "80" } } diff --git a/packages/react-server-website/cli.js b/packages/react-server-website/cli.js index 2724ef461..d146afff3 100755 --- a/packages/react-server-website/cli.js +++ b/packages/react-server-website/cli.js @@ -1,5 +1,5 @@ require("babel-core/register"); -const {start, parseCliArgs} = require("react-server-cli"); +const {run, parseCliArgs} = require("react-server-cli"); -start(parseCliArgs()); +run(parseCliArgs()); diff --git a/packages/react-server-website/components/content/HomeGetStartedSection.md b/packages/react-server-website/components/content/HomeGetStartedSection.md index 9a037086d..205796c0e 100644 --- a/packages/react-server-website/components/content/HomeGetStartedSection.md +++ b/packages/react-server-website/components/content/HomeGetStartedSection.md @@ -16,7 +16,7 @@ yo react-server npm run compile npm run start -# go to http://localhost:3010 +# go to http://localhost:3000 ``` That hooks you up with [react-server-cli](/docs/guides/react-server-cli), which will get you up and running right away. diff --git a/packages/react-server-website/package.json b/packages/react-server-website/package.json index 09ba1ad84..01bcfc70e 100644 --- a/packages/react-server-website/package.json +++ b/packages/react-server-website/package.json @@ -5,9 +5,9 @@ "main": "HelloWorld.js", "private": true, "scripts": { - "build-assets": "npm run docs && node ./cli.js --compile-only --minify", - "start-prod": "node ./cli.js --port 3010 --minify --js-url /assets/", - "start": "node ./cli.js --port 3010 --js-port 3011", + "build-assets": "npm run docs && NODE_ENV=production node ./cli.js compile", + "start-prod": "NODE_ENV=production node ./cli.js start", + "start": "node ./cli.js start", "test": "eslint routes.js gulpfile.js pages/ components/ && nsp check", "docs": "docco -o docs ./components/*.js ./lib/*.js ./middleware/*.js ./pages/*.js *.js && node build-dir-contents.js" }, diff --git a/packages/react-server/README.md b/packages/react-server/README.md index 2db579f06..fbb0071b4 100644 --- a/packages/react-server/README.md +++ b/packages/react-server/README.md @@ -36,7 +36,7 @@ yo react-server # compile and run the new app npm run compile npm run start -# go to http://localhost:3010 +# go to http://localhost:3000 ``` That hooks you up with [`react-server-cli`](packages/react-server-cli), which From 2f35d17ccad9d66c7e961eddd4a94e89b9b06e3c Mon Sep 17 00:00:00 2001 From: Bo Borgerson Date: Mon, 1 Aug 2016 17:07:37 -0700 Subject: [PATCH 05/16] Factor out some caller-dep commonality --- packages/react-server-cli/src/commands/compile.js | 5 +---- packages/react-server-cli/src/commands/init.js | 6 +----- packages/react-server-cli/src/commands/start.js | 4 +--- packages/react-server-cli/src/handleCompilationErrors.js | 4 +--- packages/react-server-cli/src/react-server.js | 4 ++++ packages/react-server-cli/src/run.js | 4 +--- 6 files changed, 9 insertions(+), 18 deletions(-) create mode 100644 packages/react-server-cli/src/react-server.js diff --git a/packages/react-server-cli/src/commands/compile.js b/packages/react-server-cli/src/commands/compile.js index b6882e11c..323e48bc6 100644 --- a/packages/react-server-cli/src/commands/compile.js +++ b/packages/react-server-cli/src/commands/compile.js @@ -1,10 +1,7 @@ import compileClient from "../compileClient" -import callerDependency from "../callerDependency"; import handleCompilationErrors from "../handleCompilationErrors"; -const reactServer = require(callerDependency("react-server")); - -const logger = reactServer.logging.getLogger(__LOGGER__); +const logger = require("react-server").logging.getLogger(__LOGGER__); export default function compile(options){ const {compiler} = compileClient(options); diff --git a/packages/react-server-cli/src/commands/init.js b/packages/react-server-cli/src/commands/init.js index 39125b72d..b9fcc2260 100644 --- a/packages/react-server-cli/src/commands/init.js +++ b/packages/react-server-cli/src/commands/init.js @@ -1,8 +1,4 @@ -import callerDependency from "../callerDependency"; - -const reactServer = require(callerDependency("react-server")); - -const logger = reactServer.logging.getLogger(__LOGGER__); +const logger = require("react-server").logging.getLogger(__LOGGER__); export default function compile(){ logger.notice("Coming soon!"); diff --git a/packages/react-server-cli/src/commands/start.js b/packages/react-server-cli/src/commands/start.js index 3d90b11de..f8ec169c2 100644 --- a/packages/react-server-cli/src/commands/start.js +++ b/packages/react-server-cli/src/commands/start.js @@ -5,10 +5,8 @@ import pem from "pem" import compression from "compression" import WebpackDevServer from "webpack-dev-server" import compileClient from "../compileClient" -import callerDependency from "../callerDependency"; import handleCompilationErrors from "../handleCompilationErrors"; - -const reactServer = require(callerDependency("react-server")); +import reactServer from "../react-server"; const logger = reactServer.logging.getLogger(__LOGGER__); diff --git a/packages/react-server-cli/src/handleCompilationErrors.js b/packages/react-server-cli/src/handleCompilationErrors.js index 84dc3b50e..49341cc27 100644 --- a/packages/react-server-cli/src/handleCompilationErrors.js +++ b/packages/react-server-cli/src/handleCompilationErrors.js @@ -1,6 +1,4 @@ -import callerDependency from "./callerDependency"; - -const reactServer = require(callerDependency("react-server")); +import reactServer from "./react-server"; const logger = reactServer.logging.getLogger(__LOGGER__); diff --git a/packages/react-server-cli/src/react-server.js b/packages/react-server-cli/src/react-server.js new file mode 100644 index 000000000..c17e9147d --- /dev/null +++ b/packages/react-server-cli/src/react-server.js @@ -0,0 +1,4 @@ +import callerDependency from "./callerDependency"; + +// We need react-server to be a singleton, and we want our caller's copy. +module.exports = require(callerDependency("react-server")); diff --git a/packages/react-server-cli/src/run.js b/packages/react-server-cli/src/run.js index 363d2dfb7..04528c814 100644 --- a/packages/react-server-cli/src/run.js +++ b/packages/react-server-cli/src/run.js @@ -2,9 +2,7 @@ import path from "path"; import mergeOptions from "./mergeOptions" import findOptionsInFiles from "./findOptionsInFiles" import defaultOptions from "./defaultOptions" -import callerDependency from "./callerDependency"; - -const reactServer = require(callerDependency("react-server")); +import reactServer from "./react-server"; const logger = reactServer.logging.getLogger(__LOGGER__); From f5c164cb121ad9dc4ea07bcddb98e99f1be0cf6a Mon Sep 17 00:00:00 2001 From: Bo Borgerson Date: Tue, 2 Aug 2016 12:53:54 -0700 Subject: [PATCH 06/16] Update CLI doc with commands A little optimistic. Some commands not yet implemented. :p --- docs/guides/react-server-cli.md | 283 ++++++++++++++++++++++---------- 1 file changed, 197 insertions(+), 86 deletions(-) diff --git a/docs/guides/react-server-cli.md b/docs/guides/react-server-cli.md index 12020cf08..d268ef826 100644 --- a/docs/guides/react-server-cli.md +++ b/docs/guides/react-server-cli.md @@ -1,71 +1,77 @@ -A simple command line app that will compile a routes file for the client and start up express. To use: +## A simple command line tool to build and run React Server sites -1. `npm install --save react-server-cli react-server` -2. Add `./node_modules/react-server-cli/bin/react-server-cli` as the value for `scripts.start` in package.json. -3. `npm start` from the directory that has your routes.js file. +To get started: -## Routes Format - -Note that the routes file needs to be in a bit different format than what we have used in the past in `react-server`. Rather than `routes.route.page` being a function, it needs to be a path to a file that exports a page class. Middleware also needs to be an array of file paths. For example: - -```javascript -module.exports = { - // these will be applied to every page in the site. - middleware: ["./FooMiddleware", "./BarMiddleware"], - - // this maps URLs to modules that export a Page class. - routes: { - BazRoute: { - path: ["/"], - method: "get", // optional - page: "./BazPage" - }, - BakRoute: { - path: ["/bak"], - page: "./BakPage" - } - } -}; +```bash +$ npm install -g react-server-cli +$ npm init +$ react-server init +$ react-server add-page '/' Homepage +$ react-server start ``` ## What It Does -The CLI builds and runs a `react-server` project, using Express. It compiles JS(X) and CSS into efficiently loadable bundles with code splitting using webpack, and it supports hot reloading of React components on the client-side during development. +The CLI builds and runs a React Server project, using Express. It compiles +JS(X) and CSS into efficiently loadable bundles with code splitting using +webpack, and it supports hot reloading of React components on the client-side +during development. ## Built-in Features ### Babel Compilation -It's rare to see a project these days in the JavaScript world that isn't at least experimenting with ES2015 and ES7. To make this easier, all code in your project will be run through Babel, and source maps will be generated back to the original file. +It's rare to see a project these days in the JavaScript world that isn't at +least experimenting with ES2015 and ES7. To make this easier, all code in your +project will be run through Babel, and source maps will be generated back to +the original file. -To take advantage of the Babel compilation, you need to install the Babel plugins and presets you want and reference them in a `.babelrc` file in your code directory. For more on the `.babelrc` format, see [its documentation here](https://babeljs.io/docs/usage/babelrc/). +To take advantage of the Babel compilation, you need to install the Babel +plugins and presets you want and reference them in a `.babelrc` file in your +code directory. For more on the `.babelrc` format, see [its documentation +here](https://babeljs.io/docs/usage/babelrc/). -## Options -Smart defaults are the goal, and `react-server-cli` has two base modes: **development** and **production**. `react-server-cli` will determine which base mode it's in by looking at the NODE_ENV environment variable. If it's not "production", then `react-server-cli` will assume we are in development mode. +## Configuration -### Ways to add options +### Routes + +This is where URLs are mapped to pages. It's also where global middleware +(applied to all pages in the site) is defined. + +By default this is created at the site's root directory as `routes.json`. -There are three ways to pass options to the CLI, through the command line, `.reactserverrc` JSON files, or as a `reactServer` entry in `package.json` files. It searches for options this way: +```json +{ + "middleware": [ + "middleware/FooMiddleware", + "middleware/BarMiddleware" + ], + "routes": { + "BazPage": { + "path": ["/"], + "page": "pages/BazPage" + }, + "BakPage": { + "path": ["/bak"], + "page": "pages/BakPage" + } + } +} +``` -1. If there are any options arguments on the command line, they are used. For the options which aren't specified: -1. `react-server-cli` looks at the current directory. - 1. If there is a JSON file named `.reactserverrc` in the directory, its settings are used and we skip to step #4. Otherwise: - 1. If there is a `package.json` file in the current directory with an entry named `reactServer`, its settings are used and we skip to step #4. Otherwise: -1. Go back to step 2 in the parent of the current directory. Repeat until you either find a config or hit the root directory. -1. If there are any options that still aren't specified, the defaults are used. +## Server config -Note that the programmatic API also searches for config files, although options sent in explicitly to the API function override the config file. +You can define JSON options either in a `.reactserverrc` or in a +`reactServer` object in your `package.json`. -### JSON options can be set per environment +You can provide environment-specific values in a sub-object at the key `env`. -If you are using either `.reactserverrc` or `package.json` to set your react-server options, you can provide environment-specific values in a sub-object at the key `env`. It looks like this: +It looks like this: ```json { + "routes": "routes.json", "port": "5000", "env": { - "staging": { - "port": "4000" - }, "production": { "port": "80" } @@ -73,33 +79,111 @@ If you are using either `.reactserverrc` or `package.json` to set your react-ser } ``` -The values in a particular environment override the main settings. In this example configuration `port` will be set to 80 if `process.env.NODE_ENV` is `production`, 4000 if `process.env.NODE_ENV` is `staging`, and 5000 for any other situation. +The values in a particular environment override the main settings. In this +example configuration `port` will be set to 80 if `process.env.NODE_ENV` is +`production`, and 5000 otherwise. + + +## Options +Smart defaults are the goal, and `react-server-cli` has two base modes: +**development** and **production**. `react-server-cli` will determine which +base mode it's in by looking at the NODE_ENV environment variable. If it's not +"production", then `react-server-cli` will assume we are in development mode. + +### Ways to add options + +There are three ways to pass options to the CLI, through the command line, +`.reactserverrc` JSON files, or as a `reactServer` entry in `package.json` +files. If there's no config file (or package.json config) in the current +working directory, then parent directories are searched up to the root of the +filesystem. Options passed to the CLI take final precedence. ### Development mode: making a great DX -Development mode is the default, and its goals are rapid startup and code-test loops. Hot mode is enabled for all code, although at this time, editing the routes file or modules that export a Page class still requires a browser reload to see changes. Modules that export a React component should reload without a browser refresh. +Development mode is the default, and its goals are rapid startup and code-test +loops. Hot mode is enabled for all code, although at this time, editing the +routes file or modules that export a Page class still requires a browser +reload to see changes. Modules that export a React component should reload +without a browser refresh. -In development mode, code is not minified in order to speed up startup time, so please do not think that the sizes of bundles in development mode is indicative of how big they will be in production. In fact, it's really best not to do any kind of perf testing in development mode; it will just lead you astray. +In development mode, code is not minified in order to speed up startup time, +so please do not think that the sizes of bundles in development mode is +indicative of how big they will be in production. In fact, it's really best +not to do any kind of perf testing in development mode; it will just lead you +astray. -We are also considering completely getting rid of server-side rendering in development mode by default to speed startup. +We are also considering completely getting rid of server-side rendering in +development mode by default to speed startup. ### Production mode: optimizing delivery -Production mode's priority is optimization at the expense of startup time. A separate code bundle is generated for every entry point into your app so that there is at most just one JS and one CSS file loaded by the framework. All code is minified, and hot reloading is turned off. +Production mode's priority is optimization at the expense of startup time. A +separate code bundle is generated for every entry point into your app so that +there is at most just one JS and one CSS file loaded by the framework. All +code is minified, and hot reloading is turned off. #### Building static files for production use -In many production configurations, you may not want `react-server-cli` to serve up your static JavaScript and CSS files. Typically, this is because you have a more performant static file server already set up or because you upload all your static files to a CDN server. +In many production configurations, you may not want `react-server-cli` to +serve up your static JavaScript and CSS files. Typically, this is because you +have a more performant static file server already set up or because you upload +all your static files to a CDN server. -To use `react-server-cli` in this sort of production setup, follow these steps: +To use `react-server-cli` in this sort of production setup, use `react-server +compile` to generate static assets. -1. `react-server-cli --production --compile-only` compiles the JavaScript and CSS files into the directory `__clientTemp/build`. -1. Upload the contents of `__clientTemp/build` to your static file server. -1. `react-server-cli --production --js-url="http://mystaticfileserver.com/somedirectory/"` to start your HTML server depending on JavaScript and CSS files from your static file server. +```bash +$ NODE_ENV=production react-server compile +$ # Upload `__clientTemp/build` to static file server +$ NODE_ENV=production react-server start +``` -### Setting Options Manually +In this case you'll want to specify a `jsUrl` key in your production config: -While development and production mode are good starting points, you can of course choose to override any of the setup by setting the following options: +```json +{ + ... + env: { + "production": { + ... + "jsUrl": "http://mystaticfileserver.com/somedirectory/" + } + } +} +``` + +### Commands + +#### init + +Generate: +- `routes.json` +- `.reactserverrc` +- `.babelrc` + +Install: +- `react-server` + +#### add-page PATH CLASSNAME + +Add a stub of a new page class. + +#### start + +Start the server. If running with local client assets, build those. + +#### compile + +Compile the client JavaScript only, and don't start any servers. This is what +you want to do if you are building the client JavaScript to be hosted on a CDN +or separate server. Unless you have a very specific reason, it's almost always +a good idea to only do this in production mode. + +### Options + +The following options are available. Note that options on the command-line +are dash-separated (e.g. `--js-port`), but options in config files are +camel-cased (e.g. `jsPort`). (TODO: Support dash-separated options in config) #### --routes The routes file to load. @@ -107,7 +191,8 @@ The routes file to load. Defaults to **"./routes.js"**. #### --host -The hostname to use when starting up the server. If `jsUrl` is set, then this argument is ignored, and any host name can be used. +The hostname to use when starting up the server. If `jsUrl` is set, then this +argument is ignored, and any host name can be used. Defaults to **localhost**. @@ -122,7 +207,9 @@ The port to use when `react-server-cli` is serving up the client JavaScript. Defaults to **3001**. #### --hot, -h -Use hot reloading of client JavaScript. Modules that export React components will reload without refreshing the browser. This option is incompatible with --long-term-caching. +Use hot reloading of client JavaScript. Modules that export React components +will reload without refreshing the browser. This option is incompatible with +--long-term-caching. Defaults to **true** in development mode and **false** in production mode. @@ -132,58 +219,72 @@ Minify client JavaScript and CSS. Defaults to **false** in development mode and **true** in production. #### --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 is incompatible with --hot. +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 +is incompatible with --hot. Defaults to **false** in development mode and **true** in production. -#### --compile-only -Compile the client JavaScript only, and don't start any servers. This is what you want to do if you are building the client JavaScript to be hosted on a CDN or separate server. Unless you have a very specific reason, it's almost always a good idea to only do this in production mode. - -Defaults to **false**. - #### --js-url -A URL base for the pre-compiled client JavaScript; usually this is a base URL on a CDN or separate server. Setting a value for js-url means that react-server-cli will not compile the client JavaScript at all, and it will not serve up any of the client JavaScript. Obviously, this means that --js-url overrides and ignores all of the options related to JavaScript compilation and serving: --hot, --js-port, and --minify. +A URL base for the pre-compiled client JavaScript; usually this is a base URL +on a CDN or separate server. Setting a value for js-url means that +react-server-cli will not compile the client JavaScript at all, and it will +not serve up any of the client JavaScript. Obviously, this means that --js-url +overrides and ignores all of the options related to JavaScript compilation and +serving: --hot, --js-port, and --minify. Defaults to **null**. #### --https -If true, the server will start up using https with a self-signed certificate. Note that browsers do not trust self-signed certificates by default, so you will have to click through some warning screens. This is a quick and dirty way to test HTTPS, but it has some limitations and should never be used in production. Requires OpenSSL to be installed. +If true, the server will start up using https with a self-signed certificate. +Note that browsers do not trust self-signed certificates by default, so you +will have to click through some warning screens. This is a quick and dirty way +to test HTTPS, but it has some limitations and should never be used in +production. Requires OpenSSL to be installed. Defaults to **false**. #### --https-key -Start the server using HTTPS with this private key file in PEM format. Requires `https-cert` to be set as well. +Start the server using HTTPS with this private key file in PEM format. +Requires `https-cert` to be set as well. Default is **none**. #### --https-cert -Start the server using HTTPS with this cert file in PEM format. Requires `https-key` to be set as well. +Start the server using HTTPS with this cert file in PEM format. Requires +`https-key` to be set as well. Default is **none**. #### --https-ca -Start the server using HTTPS with this certificate authority file in PEM format. Also requires `https-key` and `https-cert` to start the server. +Start the server using HTTPS with this certificate authority file in PEM +format. Also requires `https-key` and `https-cert` to start the server. Default is **none**. #### --https-pfx -Start the server using HTTPS with this file containing the private key, certificate and CA certs of the server in PFX or PKCS12 format. Mutually exclusive with `https-key`, `https-cert`, and `https-ca`. +Start the server using HTTPS with this file containing the private key, +certificate and CA certs of the server in PFX or PKCS12 format. Mutually +exclusive with `https-key`, `https-cert`, and `https-ca`. Default is **none**. #### --https-passphrase -A passphrase for the private key or pfx file. Requires `https-key` or `https-pfx` to be set. +A passphrase for the private key or pfx file. Requires `https-key` or +`https-pfx` to be set. Default is **none**. #### --log-level -Sets the severity level for the logs being reported. Values are, in ascending order of severity: 'debug', 'info', 'notice', 'warning', 'error', 'critical', 'alert', 'emergency'. +Sets the severity level for the logs being reported. Values are, in ascending +order of severity: 'debug', 'info', 'notice', 'warning', 'error', 'critical', +'alert', 'emergency'. Default is **'debug'** in development mode and **'notice'** in production. @@ -192,20 +293,30 @@ Shows command line options. ## API -You can also call `react-server-cli` programmatically. The module has a single named export, `start`, which takes has the following signature: +You can also call `react-server-cli` programmatically. The module has a +named export, `run`, which takes has the following signature: ```javascript -import {start} from `react-server-cli` - -start(routesRelativePath, { - port: 3000, - jsPort: 3001, - hot: true, - minify: false, - compileOnly: false, - jsUrl: null, - longTermCaching: true, -}) +import {run} from "react-server-cli" + +start({ + command : "start", + routes : "./routes.json", + port : 3000, + jsPort : 3001, + hot : true, + minify : false, + compileOnly : false, + jsUrl : null, + longTermCaching : true, +}); ``` -All of the values in the second argument are optional, and they have the same defaults as the corresponding CLI arguments explained above. (Also note that if an option isn't present, the programmatic API will search for a config file in the same way as the CLI.) +The module also exports a `parseCliArgs` function that will let you implement +your own CLI: + +```javascript +import {run, parseCliArgs} from "react-server-cli" + +start(parseCliArgs()); +``` From 2952ae7161707e689edb7aae7efb2e4d3ba7aece Mon Sep 17 00:00:00 2001 From: Bo Borgerson Date: Tue, 2 Aug 2016 13:57:03 -0700 Subject: [PATCH 07/16] Basic `react-server init` working --- packages/react-server-cli/package.json | 1 + .../src/ConfigurationError.js | 13 +++ .../react-server-cli/src/commands/compile.js | 5 ++ .../react-server-cli/src/commands/init.js | 80 ++++++++++++++++++- .../react-server-cli/src/commands/start.js | 5 ++ .../src/logProductionWarnings.js | 25 ++++++ packages/react-server-cli/src/run.js | 34 -------- packages/react-server-cli/src/setupLogging.js | 7 ++ 8 files changed, 133 insertions(+), 37 deletions(-) create mode 100644 packages/react-server-cli/src/ConfigurationError.js create mode 100644 packages/react-server-cli/src/logProductionWarnings.js create mode 100644 packages/react-server-cli/src/setupLogging.js diff --git a/packages/react-server-cli/package.json b/packages/react-server-cli/package.json index 5b88e05b1..c42cf9346 100644 --- a/packages/react-server-cli/package.json +++ b/packages/react-server-cli/package.json @@ -26,6 +26,7 @@ "json-loader": "^0.5.4", "less": "^2.7.1", "less-loader": "^2.2.3", + "lodash": "^4.14.1", "mkdirp": "~0.5.1", "node-libs-browser": "~0.5.2", "null-loader": "~0.1.1", diff --git a/packages/react-server-cli/src/ConfigurationError.js b/packages/react-server-cli/src/ConfigurationError.js new file mode 100644 index 000000000..5702e4a46 --- /dev/null +++ b/packages/react-server-cli/src/ConfigurationError.js @@ -0,0 +1,13 @@ +// Can't use `instanceof` with babel-ified subclasses of builtins. +// +// https://phabricator.babeljs.io/T3083 +// +// Gotta do this the old-fashioned way. :p +// +export default function ConfigurationError(message) { + this.name = 'ConfigurationError'; + this.message = message; + this.stack = (new Error()).stack; +} +ConfigurationError.prototype = Object.create(Error.prototype); +ConfigurationError.prototype.constructor = ConfigurationError; diff --git a/packages/react-server-cli/src/commands/compile.js b/packages/react-server-cli/src/commands/compile.js index 323e48bc6..30bdeccda 100644 --- a/packages/react-server-cli/src/commands/compile.js +++ b/packages/react-server-cli/src/commands/compile.js @@ -1,9 +1,14 @@ import compileClient from "../compileClient" import handleCompilationErrors from "../handleCompilationErrors"; +import setupLogging from "../setupLogging"; +import logProductionWarnings from "../logProductionWarnings"; const logger = require("react-server").logging.getLogger(__LOGGER__); export default function compile(options){ + setupLogging(options); + logProductionWarnings(options); + const {compiler} = compileClient(options); logger.notice("Starting compilation of client JavaScript..."); diff --git a/packages/react-server-cli/src/commands/init.js b/packages/react-server-cli/src/commands/init.js index b9fcc2260..60ad172ca 100644 --- a/packages/react-server-cli/src/commands/init.js +++ b/packages/react-server-cli/src/commands/init.js @@ -1,5 +1,79 @@ -const logger = require("react-server").logging.getLogger(__LOGGER__); +import _ from "lodash"; +import fs from "fs"; +import {spawnSync} from "child_process"; +import chalk from "chalk"; +import ConfigurationError from "../ConfigurationError"; -export default function compile(){ - logger.notice("Coming soon!"); +const DEPENDENCIES = [ + "react-server", + "babel-preset-react-server", + + // TODO: Modernize our peer deps and remove versions here. + "superagent@1.2.0", + "react@~0.14.2", + "react-dom@~0.14.2", +] + +const CONFIG = { + "routes.json": { + middleware: [], + routes: [], + }, + ".reactserverrc": { + routesFile: "routes.json", + port: 3000, + env: { + production: { + port: 80, + }, + }, + }, + ".babelrc": { + presets: ["react-server"], + }, +} + +export default function init(options){ + try { + _init(options); + } catch (e) { + if (e instanceof ConfigurationError) { + console.error(chalk.red(e.message)); + } else { + throw e; + } + } +} + +function _init() { + if (!fileExists("package.json")) { + throw new ConfigurationError("Missing package.json. Please run `npm init` first."); + } + + Object.keys(CONFIG).forEach(fn => { + if (fileExists(fn)) { + throw new ConfigurationError(`Found a pre-existing ${fn}. Aborting.`); + } + }); + + console.log(chalk.yellow("Installing dependencies")); + + spawnSync("npm", ["install", "--save", ...DEPENDENCIES], {stdio: "inherit"}); + + _.forEach(CONFIG, (config, fn) => { + console.log(chalk.yellow("Generating " + fn)); + + fs.writeFileSync(fn, JSON.stringify(config, null, " ") + "\n"); + }); + + console.log(chalk.green("All set!")); +} + +function fileExists(fn) { + try { + fs.statSync(fn); + return true; + } catch (e) { + return false; + } } diff --git a/packages/react-server-cli/src/commands/start.js b/packages/react-server-cli/src/commands/start.js index f8ec169c2..f0b6d5865 100644 --- a/packages/react-server-cli/src/commands/start.js +++ b/packages/react-server-cli/src/commands/start.js @@ -7,6 +7,8 @@ import WebpackDevServer from "webpack-dev-server" import compileClient from "../compileClient" import handleCompilationErrors from "../handleCompilationErrors"; import reactServer from "../react-server"; +import setupLogging from "../setupLogging"; +import logProductionWarnings from "../logProductionWarnings"; const logger = reactServer.logging.getLogger(__LOGGER__); @@ -15,6 +17,9 @@ const logger = reactServer.logging.getLogger(__LOGGER__); // started. stop is a method to stop all servers. It takes no arguments and // returns a promise that resolves when the server has stopped. export default function start(options){ + setupLogging(options); + logProductionWarnings(options); + const { port, jsPort, diff --git a/packages/react-server-cli/src/logProductionWarnings.js b/packages/react-server-cli/src/logProductionWarnings.js new file mode 100644 index 000000000..36c507b34 --- /dev/null +++ b/packages/react-server-cli/src/logProductionWarnings.js @@ -0,0 +1,25 @@ +import reactServer from "./react-server"; + +const logger = reactServer.logging.getLogger(__LOGGER__); + +export default function logProductionWarnings({hot, minify, jsUrl, longTermCaching}){ + // if the server is being launched with some bad practices for production mode, then we + // should output a warning. if arg.jsurl is set, then hot and minify are moot, since + // we aren't serving JavaScript & CSS at all. + if ((!jsUrl && (hot || !minify)) || process.env.NODE_ENV !== "production" || !longTermCaching) { //eslint-disable-line no-process-env + logger.warning("PRODUCTION WARNING: the following current settings are discouraged in production environments. (If you are developing, carry on!):"); + if (hot) { + logger.warning("-- Hot reload is enabled. To disable, set hot to false (--hot=false at the command-line) or set NODE_ENV=production."); + } + + if (!minify) { + logger.warning("-- Minification is disabled. To enable, set minify to true (--minify at the command-line) or set NODE_ENV=production."); + } + + if (!longTermCaching) { + logger.warning("-- Long-term caching is disabled. To enable, set longTermCaching to true (--long-term-caching at the command-line) or set NODE_ENV=production to turn on."); + } + logger.info(`NODE_ENV is set to ${process.env.NODE_ENV}`); //eslint-disable-line no-process-env + } + +} diff --git a/packages/react-server-cli/src/run.js b/packages/react-server-cli/src/run.js index 04528c814..2fd22381b 100644 --- a/packages/react-server-cli/src/run.js +++ b/packages/react-server-cli/src/run.js @@ -2,9 +2,6 @@ import path from "path"; import mergeOptions from "./mergeOptions" import findOptionsInFiles from "./findOptionsInFiles" import defaultOptions from "./defaultOptions" -import reactServer from "./react-server"; - -const logger = reactServer.logging.getLogger(__LOGGER__); export default function run(options = {}) { @@ -13,9 +10,6 @@ export default function run(options = {}) { // options neither passed in nor in a config file, use the defaults. options = mergeOptions(defaultOptions, findOptionsInFiles() || {}, options); - setupLogging(options.logLevel, options.timingLogLevel, options.gaugeLogLevel); - logProductionWarnings(options); - const { routesFile, jsUrl, @@ -37,31 +31,3 @@ export default function run(options = {}) { return require("./" + path.join("commands", options.command)).default(options); } - -const setupLogging = (logLevel, timingLogLevel, gaugeLogLevel) => { - reactServer.logging.setLevel('main', logLevel); - reactServer.logging.setLevel('time', timingLogLevel); - reactServer.logging.setLevel('gauge', gaugeLogLevel); -} - -const logProductionWarnings = ({hot, minify, jsUrl, longTermCaching}) => { - // if the server is being launched with some bad practices for production mode, then we - // should output a warning. if arg.jsurl is set, then hot and minify are moot, since - // we aren't serving JavaScript & CSS at all. - if ((!jsUrl && (hot || !minify)) || process.env.NODE_ENV !== "production" || !longTermCaching) { //eslint-disable-line no-process-env - logger.warning("PRODUCTION WARNING: the following current settings are discouraged in production environments. (If you are developing, carry on!):"); - if (hot) { - logger.warning("-- Hot reload is enabled. To disable, set hot to false (--hot=false at the command-line) or set NODE_ENV=production."); - } - - if (!minify) { - logger.warning("-- Minification is disabled. To enable, set minify to true (--minify at the command-line) or set NODE_ENV=production."); - } - - if (!longTermCaching) { - logger.warning("-- Long-term caching is disabled. To enable, set longTermCaching to true (--long-term-caching at the command-line) or set NODE_ENV=production to turn on."); - } - logger.info(`NODE_ENV is set to ${process.env.NODE_ENV}`); //eslint-disable-line no-process-env - } - -} diff --git a/packages/react-server-cli/src/setupLogging.js b/packages/react-server-cli/src/setupLogging.js new file mode 100644 index 000000000..1ca8f5eab --- /dev/null +++ b/packages/react-server-cli/src/setupLogging.js @@ -0,0 +1,7 @@ +import reactServer from "./react-server"; + +export default function setupLogging({logLevel, timingLogLevel, gaugeLogLevel}){ + reactServer.logging.setLevel("main", logLevel); + reactServer.logging.setLevel("time", timingLogLevel); + reactServer.logging.setLevel("gauge", gaugeLogLevel); +} From b7d02ce0a88ab1ee23f1cd3684e7dc4aeb1bca96 Mon Sep 17 00:00:00 2001 From: Bo Borgerson Date: Tue, 2 Aug 2016 14:37:46 -0700 Subject: [PATCH 08/16] Get basic `react-server add-page` working --- .../react-server-cli/src/commands/add-page.js | 53 +++++++++++++++++++ .../react-server-cli/src/commands/init.js | 36 +++++-------- packages/react-server-cli/src/fileExists.js | 10 ++++ packages/react-server-cli/src/parseCliArgs.js | 7 +-- packages/react-server-cli/src/run.js | 12 ++++- 5 files changed, 92 insertions(+), 26 deletions(-) create mode 100644 packages/react-server-cli/src/commands/add-page.js create mode 100644 packages/react-server-cli/src/fileExists.js diff --git a/packages/react-server-cli/src/commands/add-page.js b/packages/react-server-cli/src/commands/add-page.js new file mode 100644 index 000000000..e7b73e081 --- /dev/null +++ b/packages/react-server-cli/src/commands/add-page.js @@ -0,0 +1,53 @@ +import _ from "lodash"; +import fs from "fs"; +import {join} from "path"; +import chalk from "chalk"; +import mkdirp from "mkdirp"; +import fileExists from "../fileExists"; +import ConfigurationError from "../ConfigurationError"; + +const PAGE_SOURCE = _.template(` +import React from "react"; + +export default class <%= className %> { + handleRoute(next) { + // Kick off data requests here. + return next(); + } + + getElements() { + return
This is <%= className %>.
+ } +} +`); + +export default function addPage(options){ + const {routesFile, routesPath, routes} = options; + + const path = options._[3]; + const className = options._[4]; + + if (!path || !className) { + throw new ConfigurationError("Usage: react-server add-page "); + } + + const page = join("pages", className + ".js"); + + if (fileExists(page)) { + throw new ConfigurationError(`Found a pre-existing ${page}. Aborting.`); + } + + mkdirp("pages"); + + console.log(chalk.yellow("Generating " + page)); + + fs.writeFileSync(page, PAGE_SOURCE({className})); + + routes.routes[className] = { path, page }; + + console.log(chalk.yellow("Updating " + routesFile)); + + fs.writeFileSync(routesPath, JSON.stringify(routes, null, " ") + "\n"); + + console.log(chalk.green("All set!")); +} diff --git a/packages/react-server-cli/src/commands/init.js b/packages/react-server-cli/src/commands/init.js index 60ad172ca..73541aed3 100644 --- a/packages/react-server-cli/src/commands/init.js +++ b/packages/react-server-cli/src/commands/init.js @@ -2,6 +2,7 @@ import _ from "lodash"; import fs from "fs"; import {spawnSync} from "child_process"; import chalk from "chalk"; +import fileExists from "../fileExists"; import ConfigurationError from "../ConfigurationError"; const DEPENDENCIES = [ @@ -14,10 +15,17 @@ const DEPENDENCIES = [ "react-dom@~0.14.2", ] +const DEV_DEPENDENCIES = [ + + // TODO: These, too. + "webpack-dev-server@~1.13.0", + "webpack@^1.13.1", +] + const CONFIG = { "routes.json": { middleware: [], - routes: [], + routes: {}, }, ".reactserverrc": { routesFile: "routes.json", @@ -33,19 +41,8 @@ const CONFIG = { }, } -export default function init(options){ - try { - _init(options); - } catch (e) { - if (e instanceof ConfigurationError) { - console.error(chalk.red(e.message)); - } else { - throw e; - } - } -} +export default function init(){ -function _init() { if (!fileExists("package.json")) { throw new ConfigurationError("Missing package.json. Please run `npm init` first."); } @@ -60,6 +57,10 @@ function _init() { spawnSync("npm", ["install", "--save", ...DEPENDENCIES], {stdio: "inherit"}); + console.log(chalk.yellow("Installing devDependencies")); + + spawnSync("npm", ["install", "--save-dev", ...DEV_DEPENDENCIES], {stdio: "inherit"}); + _.forEach(CONFIG, (config, fn) => { console.log(chalk.yellow("Generating " + fn)); @@ -68,12 +69,3 @@ function _init() { console.log(chalk.green("All set!")); } - -function fileExists(fn) { - try { - fs.statSync(fn); - return true; - } catch (e) { - return false; - } -} diff --git a/packages/react-server-cli/src/fileExists.js b/packages/react-server-cli/src/fileExists.js new file mode 100644 index 000000000..627b5e89b --- /dev/null +++ b/packages/react-server-cli/src/fileExists.js @@ -0,0 +1,10 @@ +import fs from "fs"; + +export default function fileExists(fn) { + try { + fs.statSync(fn); + return true; + } catch (e) { + return false; + } +} diff --git a/packages/react-server-cli/src/parseCliArgs.js b/packages/react-server-cli/src/parseCliArgs.js index 44bf9b1d0..ed9605da7 100644 --- a/packages/react-server-cli/src/parseCliArgs.js +++ b/packages/react-server-cli/src/parseCliArgs.js @@ -96,9 +96,10 @@ export default (args = process.argv) => { .demand(0) const commands = { - "start" : "Start the server", - "compile" : "Compile static assets", - "init" : "Create a routes file and a .reactserverrc", + "start" : "Start the server", + "compile" : "Compile static assets", + "init" : "Initialize a React Server site", + "add-page" : "Add a page to an existing site", } Object.keys(commands) diff --git a/packages/react-server-cli/src/run.js b/packages/react-server-cli/src/run.js index 2fd22381b..ba231a5b5 100644 --- a/packages/react-server-cli/src/run.js +++ b/packages/react-server-cli/src/run.js @@ -1,7 +1,9 @@ import path from "path"; +import chalk from "chalk"; import mergeOptions from "./mergeOptions" import findOptionsInFiles from "./findOptionsInFiles" import defaultOptions from "./defaultOptions" +import ConfigurationError from "./ConfigurationError" export default function run(options = {}) { @@ -29,5 +31,13 @@ export default function run(options = {}) { options.outputUrl = jsUrl || `${httpsOptions ? "https" : "http"}://${host}:${jsPort}/`; - return require("./" + path.join("commands", options.command)).default(options); + try { + require("./" + path.join("commands", options.command)).default(options); + } catch (e) { + if (e instanceof ConfigurationError) { + console.error(chalk.red(e.message)); + } else { + throw e; + } + } } From 996c58983a252b984e3869d3ef2d17da30bf792b Mon Sep 17 00:00:00 2001 From: Bo Borgerson Date: Tue, 2 Aug 2016 14:51:02 -0700 Subject: [PATCH 09/16] Update usage to include command --- packages/react-server-cli/src/parseCliArgs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-server-cli/src/parseCliArgs.js b/packages/react-server-cli/src/parseCliArgs.js index ed9605da7..5f3627196 100644 --- a/packages/react-server-cli/src/parseCliArgs.js +++ b/packages/react-server-cli/src/parseCliArgs.js @@ -3,7 +3,7 @@ import fs from "fs" export default (args = process.argv) => { var argsDefinition = yargs(args) - .usage('Usage: $0 [options]') + .usage('Usage: $0 [options]') .option("routes-file", { describe: "The routes file to load. Default is 'routes.js'.", }) From 04ed22b6828c7d1e0f8ddae7d10d5ebad2aa3cc4 Mon Sep 17 00:00:00 2001 From: Bo Borgerson Date: Tue, 2 Aug 2016 15:07:38 -0700 Subject: [PATCH 10/16] Still need to return command output from `run` --- packages/react-server-cli/src/run.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/react-server-cli/src/run.js b/packages/react-server-cli/src/run.js index ba231a5b5..820f008d0 100644 --- a/packages/react-server-cli/src/run.js +++ b/packages/react-server-cli/src/run.js @@ -5,6 +5,7 @@ import findOptionsInFiles from "./findOptionsInFiles" import defaultOptions from "./defaultOptions" import ConfigurationError from "./ConfigurationError" +/* eslint-disable consistent-return */ export default function run(options = {}) { // for the option properties that weren't sent in, look for a config file @@ -32,7 +33,7 @@ export default function run(options = {}) { options.outputUrl = jsUrl || `${httpsOptions ? "https" : "http"}://${host}:${jsPort}/`; try { - require("./" + path.join("commands", options.command)).default(options); + return require("./" + path.join("commands", options.command)).default(options); } catch (e) { if (e instanceof ConfigurationError) { console.error(chalk.red(e.message)); From b436d0384c2a6174c4f15e088ca43da81370281b Mon Sep 17 00:00:00 2001 From: Bo Borgerson Date: Tue, 2 Aug 2016 15:26:10 -0700 Subject: [PATCH 11/16] Update start => run in CLI docs --- docs/guides/react-server-cli.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/guides/react-server-cli.md b/docs/guides/react-server-cli.md index d268ef826..b75c1ce70 100644 --- a/docs/guides/react-server-cli.md +++ b/docs/guides/react-server-cli.md @@ -299,7 +299,7 @@ named export, `run`, which takes has the following signature: ```javascript import {run} from "react-server-cli" -start({ +run({ command : "start", routes : "./routes.json", port : 3000, @@ -318,5 +318,5 @@ your own CLI: ```javascript import {run, parseCliArgs} from "react-server-cli" -start(parseCliArgs()); +run(parseCliArgs()); ``` From 1183e10851aafa58af664464173a3b570085f0df Mon Sep 17 00:00:00 2001 From: Bo Borgerson Date: Tue, 2 Aug 2016 15:27:44 -0700 Subject: [PATCH 12/16] Try to avoid port collision during tests --- docs/testing-ports.md | 2 +- .../src/specRuntime/testHelper.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/testing-ports.md b/docs/testing-ports.md index 6ef293562..47e7be041 100644 --- a/docs/testing-ports.md +++ b/docs/testing-ports.md @@ -7,4 +7,4 @@ to update this manifest when adding a test that starts a server. 3000, 3001 ## react-server-integration-test -8771, 3001 +8771, 8772 diff --git a/packages/react-server-integration-tests/src/specRuntime/testHelper.js b/packages/react-server-integration-tests/src/specRuntime/testHelper.js index b610093b1..3c6d7f001 100644 --- a/packages/react-server-integration-tests/src/specRuntime/testHelper.js +++ b/packages/react-server-integration-tests/src/specRuntime/testHelper.js @@ -106,6 +106,7 @@ var startServer = function (specFile, routes) { routesFile: routesFile, hot: false, port: PORT, + jsPort: +PORT+1, logLevel: "emergency", timingLogLevel: "none", gaugeLogLevel: "no", From 4e1b941dac03bca3acb0143ad91daa1f9a3e2936 Mon Sep 17 00:00:00 2001 From: Bo Borgerson Date: Tue, 2 Aug 2016 15:35:25 -0700 Subject: [PATCH 13/16] Fix a weird logger instantiation --- packages/react-server-cli/src/commands/compile.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/react-server-cli/src/commands/compile.js b/packages/react-server-cli/src/commands/compile.js index 30bdeccda..b9009e055 100644 --- a/packages/react-server-cli/src/commands/compile.js +++ b/packages/react-server-cli/src/commands/compile.js @@ -2,8 +2,9 @@ import compileClient from "../compileClient" import handleCompilationErrors from "../handleCompilationErrors"; import setupLogging from "../setupLogging"; import logProductionWarnings from "../logProductionWarnings"; +import {logging} from "../react-server"; -const logger = require("react-server").logging.getLogger(__LOGGER__); +const logger = logging.getLogger(__LOGGER__); export default function compile(options){ setupLogging(options); From 534b63eebdc42ea59b85c1b39ea3a03ecf7993ac Mon Sep 17 00:00:00 2001 From: Bo Borgerson Date: Tue, 2 Aug 2016 15:45:40 -0700 Subject: [PATCH 14/16] Auto-generate package.json if missing during init --- docs/guides/react-server-cli.md | 1 - packages/react-server-cli/src/commands/init.js | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/guides/react-server-cli.md b/docs/guides/react-server-cli.md index b75c1ce70..f40260509 100644 --- a/docs/guides/react-server-cli.md +++ b/docs/guides/react-server-cli.md @@ -4,7 +4,6 @@ To get started: ```bash $ npm install -g react-server-cli -$ npm init $ react-server init $ react-server add-page '/' Homepage $ react-server start diff --git a/packages/react-server-cli/src/commands/init.js b/packages/react-server-cli/src/commands/init.js index 73541aed3..9bbd18009 100644 --- a/packages/react-server-cli/src/commands/init.js +++ b/packages/react-server-cli/src/commands/init.js @@ -44,7 +44,8 @@ const CONFIG = { export default function init(){ if (!fileExists("package.json")) { - throw new ConfigurationError("Missing package.json. Please run `npm init` first."); + console.log(chalk.yellow("No package.json found. Running `npm init --yes`")); + spawnSync("npm", ["init", "--yes"], {stdio: "inherit"}); } Object.keys(CONFIG).forEach(fn => { From 06e76096954d77809051659e3af2890fcf0960d8 Mon Sep 17 00:00:00 2001 From: Bo Borgerson Date: Tue, 2 Aug 2016 15:49:14 -0700 Subject: [PATCH 15/16] Fix another weird logger instantiation --- packages/react-server-cli/src/handleCompilationErrors.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/react-server-cli/src/handleCompilationErrors.js b/packages/react-server-cli/src/handleCompilationErrors.js index 49341cc27..929b14fe7 100644 --- a/packages/react-server-cli/src/handleCompilationErrors.js +++ b/packages/react-server-cli/src/handleCompilationErrors.js @@ -1,6 +1,6 @@ -import reactServer from "./react-server"; +import {logging} from "./react-server"; -const logger = reactServer.logging.getLogger(__LOGGER__); +const logger = logging.getLogger(__LOGGER__); // takes in the err and stats object returned by a webpack compilation and returns // an error object if something serious happened, or null if things are ok. From 7cc1420e1c54601c6b8c4276911544b3614d1097 Mon Sep 17 00:00:00 2001 From: Bo Borgerson Date: Tue, 2 Aug 2016 15:57:39 -0700 Subject: [PATCH 16/16] CLI doc tweaks for readability --- docs/guides/react-server-cli.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/guides/react-server-cli.md b/docs/guides/react-server-cli.md index f40260509..f7ab0a818 100644 --- a/docs/guides/react-server-cli.md +++ b/docs/guides/react-server-cli.md @@ -142,7 +142,7 @@ In this case you'll want to specify a `jsUrl` key in your production config: ```json { ... - env: { + "env": { "production": { ... "jsUrl": "http://mystaticfileserver.com/somedirectory/" @@ -153,7 +153,7 @@ In this case you'll want to specify a `jsUrl` key in your production config: ### Commands -#### init +#### `init` Generate: - `routes.json` @@ -163,15 +163,15 @@ Generate: Install: - `react-server` -#### add-page PATH CLASSNAME +#### `add-page ` Add a stub of a new page class. -#### start +#### `start` Start the server. If running with local client assets, build those. -#### compile +#### `compile` Compile the client JavaScript only, and don't start any servers. This is what you want to do if you are building the client JavaScript to be hosted on a CDN