From 0f90799cfc56dbf2709ebd4b12808295377792ce Mon Sep 17 00:00:00 2001 From: Matthew Smith Date: Fri, 8 May 2015 10:56:29 -0600 Subject: [PATCH] [added] react-hot-loader when developing docs + Enable webpack-hot-loader for css changes + Enable react-hot-loader for component changes with state retention. + Better fail over when nodemon process fail + If you change the webpack configuration this will restart the webpack-dev-server. + Video link to demo this feature in docs readme. --- docs/.eslintrc | 3 + docs/README.md | 18 ++++- docs/{src => assets}/CodeMirror.css | 0 docs/client.js | 8 +++ docs/dev-run | 66 +++++++++---------- docs/server.js | 5 +- ....client.js => CodeMirrorWrapper.client.js} | 2 +- .../{CodeMirror.js => CodeMirrorWrapper.js} | 0 docs/src/HomePage.js | 8 +-- docs/src/ReactPlayground.js | 3 +- docs/src/Root.js | 12 +++- package.json | 2 +- webpack/docs.config.js | 18 ++++- webpack/strategies/development.js | 2 +- webpack/strategies/docs-development.js | 40 +++++++++++ webpack/strategies/docs.js | 1 - webpack/strategies/index.js | 2 + 17 files changed, 140 insertions(+), 50 deletions(-) rename docs/{src => assets}/CodeMirror.css (100%) rename docs/src/{CodeMirror.client.js => CodeMirrorWrapper.client.js} (86%) rename docs/src/{CodeMirror.js => CodeMirrorWrapper.js} (100%) create mode 100644 webpack/strategies/docs-development.js diff --git a/docs/.eslintrc b/docs/.eslintrc index dc65dd4c40..87ac3840ba 100644 --- a/docs/.eslintrc +++ b/docs/.eslintrc @@ -3,5 +3,8 @@ "comma-spacing": 0, "react/no-multi-comp": 0, "react/prop-types": 0 + }, + "globals": { + "CodeMirror": true } } diff --git a/docs/README.md b/docs/README.md index 3d071c5440..a6c53990ea 100644 --- a/docs/README.md +++ b/docs/README.md @@ -11,10 +11,26 @@ Pages](http://pages.github.com/). From the repository root run `npm run docs` and navigate your browser to `http://localhost:4000`. This will start an express base node server with webpack-dev middleware that will watch your file changes and recompile all the -static assets needed to generate the site. +static assets needed to generate the site. In the console output you'll see that +we bind to two ports. The first port is the one you'll use to load the docs in +your browser. The second is the webpack-dev-server we use to build the client +side assets in watch mode. _Note: while the docs should start on port 4000 if +that port is in use we progressively look for an available port. Observe +console output for the actual port that we use._ We use the +[webpack][webpack-hot] and [react][react-hot] hot loading functionality to allow +your development experience to have quickest feedback loop possible. + +For a demo of how the hot loader works checkout this video: + + ## Production This site is statically published on github pages, to do this the static assets need to be generated. You can simulate a similar experience with `npm run docs-prod` and navigating your browser to `http://localhost:4000` + +[webpack-hot]: http://webpack.github.io/docs/hot-module-replacement-with-webpack.html +[react-hot]: http://gaearon.github.io/react-hot-loader/ diff --git a/docs/src/CodeMirror.css b/docs/assets/CodeMirror.css similarity index 100% rename from docs/src/CodeMirror.css rename to docs/assets/CodeMirror.css diff --git a/docs/client.js b/docs/client.js index 0fb9d754f5..0bf1bb699e 100644 --- a/docs/client.js +++ b/docs/client.js @@ -6,10 +6,18 @@ import './assets/carousel.png'; import './assets/logo.png'; import './assets/favicon.ico'; +import 'codemirror/mode/javascript/javascript'; +import 'codemirror/theme/solarized.css'; +import 'codemirror/lib/codemirror.css'; +import './assets/CodeMirror.css'; + import React from 'react'; +import CodeMirror from 'codemirror'; import Router from 'react-router'; import routes from './src/Routes'; +global.CodeMirror = CodeMirror; + Router.run(routes, Router.RefreshLocation, Handler => { React.render( React.createElement(Handler, window.INITIAL_PROPS), document); diff --git a/docs/dev-run b/docs/dev-run index 24fe49d995..8eed9789d1 100755 --- a/docs/dev-run +++ b/docs/dev-run @@ -7,8 +7,7 @@ import { exec } from 'child-process-promise'; portfinder.basePort = 4000; const SIGINT = 'SIGINT'; -let webpackDevServer; -let docsServer; +let processMap = {}; function output(prefix, message) { let formattedMessage = message.trim().split('\n') @@ -23,22 +22,37 @@ function listen({stdout, stderr}, name) { } function shutdown() { - if (webpackDevServer) { - webpackDevServer.kill(SIGINT); - } - if (docsServer) { - docsServer.kill(SIGINT); + for (let key in processMap) { + processMap[key].kill(SIGINT); } } function catchExec(name, err) { if (err.killed) { console.log('Shutdown: '.cyan + name.green); - } else { - console.log(`${name} -- Failed`.red); - console.log(err.toString().red); + shutdown(); + return false; } - shutdown(); + + console.log(`${name} -- Failed`.red); + console.log(err.toString().red); + return true; +} + +function runCmd(name, cmd, options) { + exec(cmd, options) + .progress(childProcess => { + listen(childProcess, name); + processMap[name] = childProcess; + return; + }) + .then(() => console.log('Shutdown: '.cyan + name.green)) + .catch(err => { + if (catchExec(name, err)) { + // Restart if not explicitly shutdown + runCmd(name, cmd, options); + } + }); } console.log('Starting docs in Development mode'.cyan); @@ -51,28 +65,14 @@ portfinder.getPorts(2, {}, (portFinderErr, [docsPort, webpackPort]) => { process.exit(1); } - exec(`webpack-dev-server --quiet --config webpack.docs.js --color --port ${webpackPort}`) - .progress(childProcess => { - listen(childProcess, 'webpack-dev-server'); - webpackDevServer = childProcess; - return; - }) - .then(() => console.log('Shutdown: '.cyan + 'webpack-dev-server'.green)) - .catch(err => catchExec('webpack-dev-server', err)); + runCmd('webpack-dev-server', `nodemon --watch webpack --watch webpack.config.js --watch node_modules --exec webpack-dev-server -- --config webpack.docs.js --color --port ${webpackPort} --debug --hot`); - exec('nodemon --exec babel-node docs/server.js', { - env: { - PORT: docsPort, - WEBPACK_DEV_PORT: webpackPort, - ...process.env - } - }) - .progress(childProcess => { - listen(childProcess, 'docs-server'); - docsServer = childProcess; - return; - }) - .then(() => console.log('Shutdown: '.cyan + 'docs-server'.green)) - .catch(err => catchExec('docs-server', err)); + runCmd('docs-server', 'nodemon --watch docs --watch src --watch node_modules --exec babel-node docs/server.js', { + env: { + PORT: docsPort, + WEBPACK_DEV_PORT: webpackPort, + ...process.env + } + }); }); diff --git a/docs/server.js b/docs/server.js index 2554a5482a..78918d8452 100644 --- a/docs/server.js +++ b/docs/server.js @@ -21,8 +21,11 @@ if (development) { }); app.use(function renderApp(req, res) { + res.header('Access-Control-Allow-Origin', target); + res.header('Access-Control-Allow-Headers', 'X-Requested-With'); + Router.run(routes, req.url, Handler => { - let html = React.renderToString(); + let html = React.renderToString(); res.send(html); }); }); diff --git a/docs/src/CodeMirror.client.js b/docs/src/CodeMirrorWrapper.client.js similarity index 86% rename from docs/src/CodeMirror.client.js rename to docs/src/CodeMirrorWrapper.client.js index ee811bb38c..7bca46333a 100644 --- a/docs/src/CodeMirror.client.js +++ b/docs/src/CodeMirrorWrapper.client.js @@ -3,7 +3,7 @@ import 'codemirror/mode/javascript/javascript'; import 'codemirror/theme/solarized.css'; import 'codemirror/lib/codemirror.css'; -import './CodeMirror.css'; +import './CodeMirrorWrapper.css'; export default { IS_NODE: false, diff --git a/docs/src/CodeMirror.js b/docs/src/CodeMirrorWrapper.js similarity index 100% rename from docs/src/CodeMirror.js rename to docs/src/CodeMirrorWrapper.js diff --git a/docs/src/HomePage.js b/docs/src/HomePage.js index b27ede755b..1248967a23 100644 --- a/docs/src/HomePage.js +++ b/docs/src/HomePage.js @@ -6,8 +6,8 @@ import Grid from '../../src/Grid'; import Alert from '../../src/Alert'; import Glyphicon from '../../src/Glyphicon'; -const HomePage = React.createClass({ - render: function () { +export default class HomePage extends React.Component{ + render() { return (
@@ -34,6 +34,4 @@ const HomePage = React.createClass({
); } -}); - -export default HomePage; +} diff --git a/docs/src/ReactPlayground.js b/docs/src/ReactPlayground.js index 3b375838d6..a88899890d 100644 --- a/docs/src/ReactPlayground.js +++ b/docs/src/ReactPlayground.js @@ -42,7 +42,6 @@ import * as modTabPane from '../../src/TabPane'; import * as modTooltip from '../../src/Tooltip'; import * as modWell from '../../src/Well'; -import {CodeMirror, IS_NODE} from './CodeMirror'; import babel from 'babel-core/browser'; const classNames = modClassNames.default; @@ -103,7 +102,7 @@ const IS_MOBILE = typeof navigator !== 'undefined' && ( const CodeMirrorEditor = React.createClass({ componentDidMount() { - if (IS_MOBILE || IS_NODE) { + if (IS_MOBILE || CodeMirror === undefined) { return; } diff --git a/docs/src/Root.js b/docs/src/Root.js index e1b20dff03..293bc24b4d 100644 --- a/docs/src/Root.js +++ b/docs/src/Root.js @@ -43,6 +43,12 @@ const Root = React.createClass({ } }, + getDefaultProps() { + return { + assetBaseUrl: '' + }; + }, + render() { // Dump out our current props to a global object via a script tag so // when initialising the browser environment we can bootstrap from the @@ -66,8 +72,8 @@ const Root = React.createClass({ __html: `React Bootstrap - - + +