diff --git a/.env b/.env new file mode 100644 index 0000000..0f69927 --- /dev/null +++ b/.env @@ -0,0 +1,2 @@ +REACT_APP_HOST=localhost +REACT_APP_PORT=8080 diff --git a/config/production.js b/config/production.js new file mode 100644 index 0000000..c92db27 --- /dev/null +++ b/config/production.js @@ -0,0 +1,9 @@ +'use-strict' + +const conf = { + port: 8080, + port_ssl: 443, + host: '127.0.0.1' +} + +module.exports = conf diff --git a/config/webpack.config.base.js b/config/webpack.config.base.js index 7dc9373..1b0ccad 100644 --- a/config/webpack.config.base.js +++ b/config/webpack.config.base.js @@ -18,6 +18,7 @@ const PROD = process.env.NODE_ENV === 'production'; // Omit trailing slash as %PUBLIC_PATH%/xyz looks better than %PUBLIC_PATH%xyz. const publicUrl = ''; // Get environment variables to inject into our app. + const env = getClientEnvironment(publicUrl); // This is the development configuration. diff --git a/config/webpack.config.client.dev.js b/config/webpack.config.client.dev.js index f47b8ad..6fde822 100644 --- a/config/webpack.config.client.dev.js +++ b/config/webpack.config.client.dev.js @@ -6,6 +6,7 @@ const webpack = require('webpack'); const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin'); const WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin'); const paths = require('./paths'); +const getClientEnvironment = require('./env'); const base = require('./webpack.config.base'); diff --git a/config/webpack.config.server.js b/config/webpack.config.server.js index 108a2d2..225f581 100644 --- a/config/webpack.config.server.js +++ b/config/webpack.config.server.js @@ -6,8 +6,11 @@ const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin'); const WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin'); const paths = require('./paths'); const nodeExternals = require('webpack-node-externals'); - +const getClientEnvironment = require('./env'); const base = require('./webpack.config.base'); +const publicUrl = ''; +// Get environment variables to inject into our app. +const env = getClientEnvironment(publicUrl); const config = Object.assign({}, base) @@ -18,22 +21,14 @@ config.output = { path: paths.serverBuild, filename: 'bundle.js', publicPath: '/' -}, -/* +} + config.plugins = config.plugins.concat([ - // This is necessary to emit hot updates (currently CSS only): - new webpack.HotModuleReplacementPlugin(), - // Watcher doesn't work well if you mistype casing in a path so we use - // a plugin that prints an error when you attempt to do this. - // See https://github.com/facebookincubator/create-react-app/issues/240 - new CaseSensitivePathsPlugin(), - // If you require a missing module and then `npm install` it, you still have - // to restart the development server for Webpack to discover it. This plugin - // makes the discovery automatic so you don't have to restart. - // See https://github.com/facebookincubator/create-react-app/issues/186 - new WatchMissingNodeModulesPlugin(paths.appNodeModules), + // Makes some environment variables available to the JS code, for example: + // if (process.env.NODE_ENV === 'development') { ... }. See `./env.js`. + new webpack.DefinePlugin(env.stringified), ]) -*/ + config.node = { console: false, global: false, diff --git a/package.json b/package.json index d14e67c..730d196 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "start": "node scripts/start.js", "clean-build": "node_modules/.bin/rimraf ./build", "build-client": "node scripts/build-client.js", - "build-server": "NODE_ENV=production webpack --config config/webpack.config.server.js", + "build-server": "node scripts/build-server.js", "build": "npm run clean-build && npm run build-client && npm run build-server", "test": "node scripts/test.js --env=jsdom" }, diff --git a/scripts/build-server.js b/scripts/build-server.js new file mode 100644 index 0000000..3c75499 --- /dev/null +++ b/scripts/build-server.js @@ -0,0 +1,68 @@ +'use strict'; + +// Do this as the first thing so that any code reading it knows the right env. +process.env.BABEL_ENV = 'production'; +process.env.NODE_ENV = 'production'; + +const assetManifest = require('../build/client/asset-manifest.json'); +if (!assetManifest) { + console.log(chalk.red('No assets-manifest.json. Did you run the build-client script?.\n')); +} +process.env.REACT_APP_ASSET_MANIFEST = JSON.stringify(assetManifest); + +const path = require('path'); +const chalk = require('chalk'); +const fs = require('fs-extra'); +const webpack = require('webpack'); +const formatWebpackMessages = require('react-dev-utils/formatWebpackMessages'); +const config = require('../config/webpack.config.server'); + +function build(previousFileSizes) { + console.log('Creating an optimized production build...'); + + let compiler = webpack(config); + return new Promise((resolve, reject) => { + compiler.run((err, stats) => { + if (err) { + return reject(err); + } + const messages = formatWebpackMessages(stats.toJson({}, true)); + if (messages.errors.length) { + return reject(new Error(messages.errors.join('\n\n'))); + } + if (process.env.CI && messages.warnings.length) { + console.log( + chalk.yellow( + '\nTreating warnings as errors because process.env.CI = true.\n' + + 'Most CI servers set it automatically.\n' + ) + ); + return reject(new Error(messages.warnings.join('\n\n'))); + } + return resolve({ + stats, + warnings: messages.warnings, + }); + }); + }) +} + +build() + .then( ({ stats, previousFileSizes, warnings }) => { + if (warnings.length) { + console.log(chalk.yellow('Compiled with warnings.\n')); + console.log(warnings.join('\n\n')); + console.log( + '\nSearch for the ' + + chalk.underline(chalk.yellow('keywords')) + + ' to learn more about each warning.' + ); + console.log( + 'To ignore, add ' + + chalk.cyan('// eslint-disable-next-line') + + ' to the line before.\n' + ); + } else { + console.log(chalk.green('Compiled successfully.\n')); + } + }) diff --git a/scripts/start.js b/scripts/start.js index 20efb3f..34cd3d3 100644 --- a/scripts/start.js +++ b/scripts/start.js @@ -27,9 +27,7 @@ const { prepareUrls, } = require('react-dev-utils/WebpackDevServerUtils'); const openBrowser = require('react-dev-utils/openBrowser'); -const createDevServerConfig = require('../config/webpackDevServer.config'); const paths = require('../config/paths'); -const configWebpackClient = require('../config/webpack.config.client.dev'); // const useYarn = fs.existsSync(paths.yarnLockFile); const isInteractive = process.stdout.isTTY; @@ -58,6 +56,11 @@ choosePort(HOST, DEFAULT_CLIENT_PORT) const appName = require(paths.appPackageJson).name; const urls = prepareUrls(protocol, HOST, port); + // We do this before importing the wepack.config.client.dev otherwise + // REACT_APP_CLIENT_PORT won't be set at new webpack.DefinePlugin(env.stringified) + process.env.REACT_APP_CLIENT_PORT = port + const configWebpackClient = require('../config/webpack.config.client.dev'); + // Create a webpack compiler that is configured with custom messages. // we use different compiler //const compiler = createCompiler(webpack, configWebpackClient, appName, urls, useYarn); @@ -66,6 +69,7 @@ choosePort(HOST, DEFAULT_CLIENT_PORT) // Load proxy config const proxySetting = require(paths.appPackageJson).proxy; const proxyConfig = prepareProxy(proxySetting, paths.appPublic); + const createDevServerConfig = require('../config/webpackDevServer.config'); // Serve webpack assets generated by the compiler over a web sever. const serverConfig = createDevServerConfig( proxyConfig, @@ -73,7 +77,6 @@ choosePort(HOST, DEFAULT_CLIENT_PORT) ); const clientServer = new WebpackDevServer(compiler, serverConfig); - global.CLIENT_PORT = port // Launch WebpackDevServer. clientServer.listen(port, HOST, err => { @@ -81,7 +84,7 @@ choosePort(HOST, DEFAULT_CLIENT_PORT) return console.log(err); } if (isInteractive) { - clearConsole(); + // clearConsole(); } console.log(chalk.cyan(`Starting the client on port ${port}...\n`)); @@ -92,9 +95,11 @@ choosePort(HOST, DEFAULT_CLIENT_PORT) return; } - global.SERVER_PORT = portServer; + process.env.REACT_APP_SERVER_PORT = portServer; const configWebpackServer = require('../config/webpack.config.server'); const compiler = webpack(configWebpackServer); + const urls = prepareUrls(protocol, HOST, portServer); + let browserOpened; compiler.watch({ // watch options: aggregateTimeout: 300, // wait so long for more changes @@ -103,8 +108,10 @@ choosePort(HOST, DEFAULT_CLIENT_PORT) console.log('error on webpack server', err); const server = require('../build/server/bundle.js'); - const urls = prepareUrls(protocol, HOST, portServer); - openBrowser(urls.localUrlForBrowser); + if (!browserOpened) { + browserOpened = true + openBrowser(urls.localUrlForBrowser); + } }); }) .catch(err => { diff --git a/src/config/index.js b/src/config/index.js deleted file mode 100644 index 225630f..0000000 --- a/src/config/index.js +++ /dev/null @@ -1,6 +0,0 @@ -const config = { - port: 5678, - host: 'localhost' -} - -module.exports = config diff --git a/src/server/index.js b/src/server/index.js index 7b033d2..8848df4 100755 --- a/src/server/index.js +++ b/src/server/index.js @@ -3,9 +3,13 @@ import favicon from 'serve-favicon' import path from 'path' import proxy from 'http-proxy-middleware' -import config from '../config' import reactApp from './app' +const host = process.env.REACT_APP_HOST || 'localhost' +const serverPort = process.env.NODE_ENV === 'development'? + process.env.REACT_APP_SERVER_PORT : + process.env.REACT_APP_PORT || 80 + const app = express() app.use('/public', express.static('public')) @@ -17,16 +21,14 @@ if (process.env.NODE_ENV === 'production') { app.use('/static', express.static(path.join(process.cwd(), 'build/client/static'))); } else { // Otherwise we want to proxy the webpack development server. - app.use('/static', proxy({ - target: `http://localhost:${global.CLIENT_PORT || 3020}`, + target: `http://localhost:${process.env.REACT_APP_CLIENT_PORT}`, ws: true, - logLevel: 'info' + logLevel: 'error' })); } app.use(reactApp) -const port = global.SERVER_PORT || config.port -app.listen(port) -console.log(`Listening at http://${config.host}:${port}`) +app.listen(serverPort) +console.log(`Listening at http://${host}:${serverPort}`) diff --git a/src/server/render.js b/src/server/render.js index 6dfa881..c41fd65 100644 --- a/src/server/render.js +++ b/src/server/render.js @@ -1,26 +1,25 @@ import { renderToString } from 'react-dom/server' const DEV = process.env.NODE_ENV === 'development' - +const assetManifest = JSON.parse(process.env.REACT_APP_ASSET_MANIFEST || '{}') const bundleUrl = DEV ? '/static/js/bundle.js' : - '/static/js/main[hash].js' - + `/${assetManifest['main.js']}` const css = DEV ? - '' : - `` + '' : // in DEV the css is hot loaded + `` export default (component, storeInitiaState = undefined) => ` - + + + ${css} - Masters Directory - + + React App
${renderToString(component)}