From 68cdd56585642ea2a0f0c73305ca07072eeb867d Mon Sep 17 00:00:00 2001 From: Chris McGee Date: Thu, 25 Feb 2016 18:06:25 -0500 Subject: [PATCH 1/7] initial work on hot module reloading for the uploader --- package.json | 6 ++++-- webpack.config.js | 16 ++++++++++++---- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 3cf3d9cd7f..43a0a678d0 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "browser-tests": "./node_modules/karma/bin/karma start --browsers PhantomJS,Chrome", "node-tests": "mocha test/node/ && mocha test/node/**/*.js", "karma-watch": "./node_modules/karma/bin/karma start --no-single-run", - "start": "bash ./scripts/config.sh && webpack -d --progress --colors --watch", + "start": "bash ./scripts/config.sh && webpack-dev-server --hot --inline --progress --colors", "build": "bash ./scripts/build.sh", "lint": "./node_modules/.bin/eslint lib test" }, @@ -62,6 +62,7 @@ "phantomjs-prebuilt": "2.1.3", "proxyquire": "1.7.4", "react-addons-test-utils": "0.14.7", + "react-hot-loader": "^1.3.0", "redux-devtools": "3.0.2", "redux-devtools-dock-monitor": "1.0.1", "redux-devtools-log-monitor": "1.0.2", @@ -69,6 +70,7 @@ "redux-mock-store": "0.0.6", "salinity": "0.0.8", "style-loader": "0.13.0", - "webpack": "1.12.12" + "webpack": "1.12.12", + "write-file-webpack-plugin": "^3.1.7" } } diff --git a/webpack.config.js b/webpack.config.js index 37e2f65813..ba87ce2bd6 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,6 +1,7 @@ var path = require('path'); var _ = require('lodash'); var webpack = require('webpack'); +var WriteFilePlugin = require('write-file-webpack-plugin'); var definePlugin = new webpack.DefinePlugin({ // this first as advised to get the correct production build of redux @@ -30,20 +31,27 @@ if ((!process.env.API_URL || !process.env.UPLOAD_URL || !process.env.BLIP_URL)) var config = { entry: './entry.js', + devtool: '#cheap-module-source-map', + devServer: { + outputPath: path.join(__dirname, '/build'), + publicPath: '/build/' + }, output: { path: path.join(__dirname, '/build'), - filename: 'bundle.js' + filename: 'bundle.js', + publicPath: '/build/', }, module: { loaders: [ - { test: /\.js$/, exclude: /(node_modules)/, loader: 'babel-loader' }, - { test: /\.jsx$/, exclude: /(node_modules)/, loader: 'babel-loader' }, + { test: /\.js$/, exclude: /(node_modules)/, loaders: ['react-hot', 'babel-loader'] }, + { test: /\.jsx$/, exclude: /(node_modules)/, loaders: ['react-hot', 'babel-loader'] }, { test: /\.less$/, loader: 'style!css!less' }, { test: /\.json$/, loader: 'json' } ] }, plugins: [ - definePlugin + definePlugin, + new WriteFilePlugin() ], // to fix the 'broken by design' issue with npm link-ing modules resolve: { fallback: path.join(__dirname, 'node_modules') }, From 7301d43932a02e381760fdbfb4333b7f6174768f Mon Sep 17 00:00:00 2001 From: Chris McGee Date: Fri, 26 Feb 2016 10:16:05 -0500 Subject: [PATCH 2/7] adding webpack-dev-server dev dependency --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 43a0a678d0..3dcc2c8068 100644 --- a/package.json +++ b/package.json @@ -71,6 +71,7 @@ "salinity": "0.0.8", "style-loader": "0.13.0", "webpack": "1.12.12", + "webpack-dev-server": "^1.14.1", "write-file-webpack-plugin": "^3.1.7" } } From a918430b015ca4b158eb4ec4c6a58445bbca8f7d Mon Sep 17 00:00:00 2001 From: "Jana E. Beck" Date: Mon, 29 Feb 2016 15:49:26 -0800 Subject: [PATCH 3/7] on hot reload don't reinitialize the app if it's already been initialized --- lib/redux/actions/async.js | 6 ++++++ test/browser/redux/actions/async.test.js | 19 ++++++++++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/lib/redux/actions/async.js b/lib/redux/actions/async.js index 706cdb3078..d6ff83f273 100644 --- a/lib/redux/actions/async.js +++ b/lib/redux/actions/async.js @@ -41,6 +41,12 @@ let daysForCareLink = null; export function doAppInit(opts, servicesToInit) { return (dispatch, getState) => { + // when we are developing with hot reload, we get into trouble if we try to initialize the app + // when it's already been initialized, so we check the working.initializingApp flag first + if (getState().working.initializingApp === false) { + console.log('App already initialized! Skipping initialization.'); + return; + } services = servicesToInit; versionInfo.semver = opts.version; versionInfo.name = opts.namedVersion; diff --git a/test/browser/redux/actions/async.test.js b/test/browser/redux/actions/async.test.js index 3d928fd44c..59dfe16a12 100644 --- a/test/browser/redux/actions/async.test.js +++ b/test/browser/redux/actions/async.test.js @@ -55,6 +55,18 @@ describe('Asynchronous Actions', () => { asyncActions.__ResetDependency__('services'); }); + describe('doAppInit [hot reload, app already initialized]', () => { + it('should dispatch no actions!', (done) => { + const expectedActions = []; + const store = mockStore({working: {initializingApp: false}}, expectedActions, done.fail); + store.dispatch(asyncActions.doAppInit({}, {})); + // somewhat hacky solution to testing for no actions + // discussed here: https://github.com/arnaudbenard/redux-mock-store/issues/17 + // happy to live with the hack since this is only for hot-reloading anyway + setTimeout(() => done(), 1000); + }); + }); + describe('doAppInit [no session token in local storage]', () => { it('should dispatch SET_VERSION, INIT_APP_REQUEST, SET_OS, HIDE_UNAVAILABLE_DEVICES, SET_FORGOT_PASSWORD_URL, SET_SIGNUP_URL, SET_PAGE, INIT_APP_SUCCESS, VERSION_CHECK_REQUEST, VERSION_CHECK_SUCCESS actions', (done) => { const config = { @@ -126,7 +138,7 @@ describe('Asynchronous Actions', () => { asyncActions.__Rewire__('versionInfo', { semver: config.version }); - const store = mockStore({}, expectedActions, done); + const store = mockStore({working: {initializingApp: true}}, expectedActions, done); store.dispatch(asyncActions.doAppInit(config, servicesToInit)); }); }); @@ -223,7 +235,8 @@ describe('Asynchronous Actions', () => { semver: config.version }); const state = { - uploadTargetUser: pwd.user.userid + uploadTargetUser: pwd.user.userid, + working: {initializingApp: true} }; const store = mockStore(state, expectedActions, done); store.dispatch(asyncActions.doAppInit(config, servicesToInit)); @@ -277,7 +290,7 @@ describe('Asynchronous Actions', () => { asyncActions.__Rewire__('versionInfo', { semver: config.version }); - const store = mockStore({}, expectedActions, done); + const store = mockStore({working: {initializingApp: true}}, expectedActions, done); store.dispatch(asyncActions.doAppInit(config, servicesToInit)); }); }); From dbf94365af518ca32df7e9b207773f92763e5ce1 Mon Sep 17 00:00:00 2001 From: Chris McGee Date: Tue, 1 Mar 2016 10:04:02 -0500 Subject: [PATCH 4/7] using exact versions of npm dev dependencies --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 3dcc2c8068..5259a87cab 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "phantomjs-prebuilt": "2.1.3", "proxyquire": "1.7.4", "react-addons-test-utils": "0.14.7", - "react-hot-loader": "^1.3.0", + "react-hot-loader": "1.3.0", "redux-devtools": "3.0.2", "redux-devtools-dock-monitor": "1.0.1", "redux-devtools-log-monitor": "1.0.2", @@ -71,7 +71,7 @@ "salinity": "0.0.8", "style-loader": "0.13.0", "webpack": "1.12.12", - "webpack-dev-server": "^1.14.1", - "write-file-webpack-plugin": "^3.1.7" + "webpack-dev-server": "1.14.1", + "write-file-webpack-plugin": "3.1.8" } } From b828112203b5734484329dde4358df7892e3f71d Mon Sep 17 00:00:00 2001 From: Chris McGee Date: Tue, 1 Mar 2016 10:28:23 -0500 Subject: [PATCH 5/7] Add information about the key file warning chrome throws on the unpacked extension --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3b886020c9..8daa593d4d 100644 --- a/README.md +++ b/README.md @@ -13,11 +13,13 @@ This is a [Chrome App](https://developer.chrome.com/apps/about_apps) that acts a 1. Run `npm start` (This will bundle the application with webpack and watch for changes. When it stops printing output you can continue to the next step.) 1. Open Chrome. Go to chrome://extensions and turn on Developer mode (checkbox on the top line). 1. Click "Load Unpacked Extension". -1. Choose the directory where you cloned the repository and click OK. +1. Choose the directory where you cloned the repository and click OK.[1](#f1) 1. To run it, you can choose "Launch" from the chrome://extensions page. You can also run it from the Chrome App Launcher, which Chrome may install for you whether you want it or not. 1. To open the JavaScript console/Chrome Dev Tools, click on the `index.html` link in the section of chrome://extensions devoted to the uploader. (Note: this link will only appear after you've launched the uploader.) 1. If you're developing, you may find that the only way it runs properly is to hit the "Reload" link in chrome://extensions after each change to the source. You will definitely need to reload any time you change the manifest. +--- +1 You may see a warning from Chrome concerning the inclusion of a key file. (`This extension includes the key file '/node_modules/webpack-dev-server/node_modules/sockjs-client/node_modules/eventsource/test/key.pem`) This is due to the loading of all the `node_modules` and their various internal testing utilities. This isn't a security issue, nor is the associated key used or referenced anywhere in the running code and can safely be ignored. [↩](#a1) ## Config From 8b9e44fd4ad50bd90b5ef3b4958c232b626f0ad4 Mon Sep 17 00:00:00 2001 From: Chris McGee Date: Tue, 1 Mar 2016 10:28:23 -0500 Subject: [PATCH 6/7] Add information about the key file warning chrome throws on the unpacked extension --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3b886020c9..696e5153ab 100644 --- a/README.md +++ b/README.md @@ -13,11 +13,13 @@ This is a [Chrome App](https://developer.chrome.com/apps/about_apps) that acts a 1. Run `npm start` (This will bundle the application with webpack and watch for changes. When it stops printing output you can continue to the next step.) 1. Open Chrome. Go to chrome://extensions and turn on Developer mode (checkbox on the top line). 1. Click "Load Unpacked Extension". -1. Choose the directory where you cloned the repository and click OK. +1. Choose the directory where you cloned the repository and click OK.[1](#f1) 1. To run it, you can choose "Launch" from the chrome://extensions page. You can also run it from the Chrome App Launcher, which Chrome may install for you whether you want it or not. 1. To open the JavaScript console/Chrome Dev Tools, click on the `index.html` link in the section of chrome://extensions devoted to the uploader. (Note: this link will only appear after you've launched the uploader.) 1. If you're developing, you may find that the only way it runs properly is to hit the "Reload" link in chrome://extensions after each change to the source. You will definitely need to reload any time you change the manifest. +--- +1 You may see a warning from Chrome concerning the inclusion of a key file. (`This extension includes the key file '/node_modules/webpack-dev-server/node_modules/sockjs-client/node_modules/eventsource/test/key.pem`) This is due to the loading of all the `node_modules` and their various internal testing utilities. This isn't a security issue, nor is the associated key used or referenced anywhere in the running code and can safely be ignored. [↩](#a1) ## Config From 044b3eddcc435c345ba7f7f37b1722db20e3a638 Mon Sep 17 00:00:00 2001 From: Chris McGee Date: Tue, 1 Mar 2016 11:48:45 -0500 Subject: [PATCH 7/7] Add some detail about the hot loader development flow --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 696e5153ab..8dfa1e6a84 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ This is a [Chrome App](https://developer.chrome.com/apps/about_apps) that acts a 1. Choose the directory where you cloned the repository and click OK.[1](#f1) 1. To run it, you can choose "Launch" from the chrome://extensions page. You can also run it from the Chrome App Launcher, which Chrome may install for you whether you want it or not. 1. To open the JavaScript console/Chrome Dev Tools, click on the `index.html` link in the section of chrome://extensions devoted to the uploader. (Note: this link will only appear after you've launched the uploader.) -1. If you're developing, you may find that the only way it runs properly is to hit the "Reload" link in chrome://extensions after each change to the source. You will definitely need to reload any time you change the manifest. +1. React components and CSS will hot load after changes (this can be confirmed by watching the JavaScript console), but changes to device drivers and other code outside of the React components will not - use 'Reload' from chrome://extensions to reload after such changes. If the compilation/hot reload of a component fails for any reason (e.g. from a syntax error) you may need to reinitialize the hot loader by reloading the extension. You will definitely need to reload any time you change the manifest. --- 1 You may see a warning from Chrome concerning the inclusion of a key file. (`This extension includes the key file '/node_modules/webpack-dev-server/node_modules/sockjs-client/node_modules/eventsource/test/key.pem`) This is due to the loading of all the `node_modules` and their various internal testing utilities. This isn't a security issue, nor is the associated key used or referenced anywhere in the running code and can safely be ignored. [↩](#a1)