diff --git a/Makefile b/Makefile index af29bab545..a91dec0379 100644 --- a/Makefile +++ b/Makefile @@ -109,7 +109,7 @@ endif ifeq ($(BUILD_IN_CONTAINER),true) -client/build/app.js: $(shell find client/app/scripts -type f) $(SCOPE_UI_BUILD_UPTODATE) +client/build/app.js: $(shell find client/app -type f) $(SCOPE_UI_BUILD_UPTODATE) mkdir -p client/build $(SUDO) docker run $(RM) $(RUN_FLAGS) -v $(shell pwd)/client/app:/home/weave/app \ -v $(shell pwd)/client/build:/home/weave/build \ diff --git a/client/.gitignore b/client/.gitignore index 034f1b004f..1026d13311 100644 --- a/client/.gitignore +++ b/client/.gitignore @@ -1,5 +1,4 @@ node_modules -build/app.js -build/*[woff2?|ttf|eot|svg] +build/ coverage/ test/*png diff --git a/client/README.md b/client/README.md index 34fef21542..93405d0382 100644 --- a/client/README.md +++ b/client/README.md @@ -1,14 +1,10 @@ # Scope UI -## Requirements - - ## Getting Started (using local node) - You need nodejs 4.2.2 and a running `weavescope` container - Setup: `npm install` -- Build: `npm run build`, output will be in `build/` -- Develop: `BACKEND_HOST=:4040 npm start` and then open `http://localhost:4042/` +- Develop: `BACKEND_HOST= npm start` and then open `http://localhost:4042/` This will start a webpack-dev-server that serves the UI and proxies API requests to the container. @@ -19,6 +15,11 @@ This will start a webpack-dev-server that serves the UI and proxies API requests This will start a webpack-dev-server that serves the UI from the UI build container and proxies API requests to the weavescope container. +## Test Production Bundles Locally + +- Build: `npm run build`, output will be in `build/` +- Serve files from `build/`: `BACKEND_HOST= npm run start-production` and then open `http://localhost:4042/` + ## Coding This directory has a `.eslintrc`, make sure your editor supports linter hints. @@ -26,15 +27,15 @@ To run a linter, you also run `npm run lint`. ## Logging -The Scope UI uses [debug](https://www.npmjs.com/package/debug) for logging, e.g.,: +To enable logging in the console, activate it via `localStorage` in the dev tools console: ``` -const debug = require('debug')('scope:app-store'); -debug('Store log message'); +localStorage["debug"] = "scope:*" ``` -To enable logging in the console, activate it via `localStorage` in the dev tools console: +The Scope UI uses [debug](https://www.npmjs.com/package/debug) for logging, e.g.,: ``` -localStorage["debug"] = "scope:*" +const debug = require('debug')('scope:app-store'); +debug('Store log message'); ``` diff --git a/client/build/index.html b/client/app/html/index.html similarity index 87% rename from client/build/index.html rename to client/app/html/index.html index e4431f72d0..b9fd6f2205 100644 --- a/client/build/index.html +++ b/client/app/html/index.html @@ -13,8 +13,5 @@
- - - diff --git a/client/app/images/favicon.ico b/client/app/images/favicon.ico new file mode 100644 index 0000000000..2d15c78088 Binary files /dev/null and b/client/app/images/favicon.ico differ diff --git a/client/app/scripts/contrast-main.js b/client/app/scripts/contrast-main.js index 18de464be8..20d66e8788 100644 --- a/client/app/scripts/contrast-main.js +++ b/client/app/scripts/contrast-main.js @@ -1,5 +1,6 @@ require('font-awesome-webpack'); require('../styles/contrast.less'); +require('../images/favicon.ico'); import React from 'react'; import ReactDOM from 'react-dom'; diff --git a/client/app/scripts/main.js b/client/app/scripts/main.js index 129e1d6ab8..61a28bc1a7 100644 --- a/client/app/scripts/main.js +++ b/client/app/scripts/main.js @@ -1,5 +1,6 @@ require('font-awesome-webpack'); require('../styles/main.less'); +require('../images/favicon.ico'); import React from 'react'; import ReactDOM from 'react-dom'; diff --git a/client/app/scripts/terminal-main.js b/client/app/scripts/terminal-main.js index 8e99c525de..9e651ade8c 100644 --- a/client/app/scripts/terminal-main.js +++ b/client/app/scripts/terminal-main.js @@ -1,4 +1,5 @@ require('../styles/main.less'); +require('../images/favicon.ico'); import React from 'react'; import ReactDOM from 'react-dom'; diff --git a/client/build/contrast.html b/client/build/contrast.html deleted file mode 100644 index 11c0941ef2..0000000000 --- a/client/build/contrast.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - Weave Scope - - - - - -
-
-
- - - - - diff --git a/client/build/debug.html b/client/build/debug.html deleted file mode 100644 index e4431f72d0..0000000000 --- a/client/build/debug.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - Weave Scope - - - - - -
-
-
- - - - - diff --git a/client/build/terminal.html b/client/build/terminal.html deleted file mode 100644 index f4846dec4c..0000000000 --- a/client/build/terminal.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - Weave Scope Terminal - - - - - -
-
-
- - - - - diff --git a/client/package.json b/client/package.json index 51d0875cf4..fbcb349183 100644 --- a/client/package.json +++ b/client/package.json @@ -37,13 +37,16 @@ "babel-loader": "6.2.4", "babel-preset-es2015": "6.6.0", "babel-preset-react": "6.5.0", + "clean-webpack-plugin": "^0.1.8", "css-loader": "0.23.1", "eslint": "2.4.0", "eslint-config-airbnb": "6.1.0", "eslint-loader": "1.3.0", "eslint-plugin-jasmine": "1.6.0", "eslint-plugin-react": "4.2.2", + "extract-text-webpack-plugin": "^1.0.1", "file-loader": "0.8.5", + "html-webpack-plugin": "^2.16.0", "http-proxy-rules": "^1.0.1", "immutable-devtools": "0.0.6", "jest-cli": "~0.9.2", diff --git a/client/server.js b/client/server.js index f9c7e7acc1..a27ac30c7d 100644 --- a/client/server.js +++ b/client/server.js @@ -21,34 +21,33 @@ var WEBPACK_SERVER_HOST = process.env.WEBPACK_SERVER_HOST || 'localhost'; * ************************************************************/ - -// Serve application file depending on environment -app.get(/(app|contrast-app|terminal-app|vendors).js/, function(req, res) { - var filename = req.originalUrl; - if (process.env.NODE_ENV === 'production') { - res.sendFile(__dirname + '/build' + filename); - } else { - res.redirect('//' + WEBPACK_SERVER_HOST + ':4041/build' + filename); - } -}); - // Proxy to backend -var proxy = httpProxy.createProxy({ +var backendProxy = httpProxy.createProxy({ ws: true, target: 'http://' + BACKEND_HOST + ':4040' }); - -proxy.on('error', function(err) { +backendProxy.on('error', function(err) { console.error('Proxy error', err); }); +app.all('/api*', backendProxy.web.bind(backendProxy)); -app.all('/api*', proxy.web.bind(proxy)); - -// Serve index page - -app.use(express.static('build')); +// Serve application file depending on environment +if (process.env.NODE_ENV === 'production') { + // serve all precompiled content from build/ + app.use(express.static('build')); +} else { + // redirect the JS bundles + app.get(/.*js/, function(req, res) { + res.redirect('//' + WEBPACK_SERVER_HOST + ':4041' + req.originalUrl); + }); + // proxy everything else + var staticProxy = httpProxy.createProxy({ + target: 'http://' + WEBPACK_SERVER_HOST + ':4041' + }); + app.all('*', staticProxy.web.bind(staticProxy)); +} /************************************************************* * @@ -64,7 +63,6 @@ if (process.env.NODE_ENV !== 'production') { var config = require('./webpack.local.config'); new WebpackDevServer(webpack(config), { - publicPath: 'http://' + WEBPACK_SERVER_HOST + ':4041/build/', hot: true, noInfo: true, historyApiFallback: true, @@ -91,7 +89,7 @@ var server = app.listen(port, function () { console.log('Scope UI listening at http://%s:%s', host, port); }); -server.on('upgrade', proxy.ws.bind(proxy)); +server.on('upgrade', backendProxy.ws.bind(backendProxy)); /************************************************************* diff --git a/client/webpack.local.config.js b/client/webpack.local.config.js index db9f958cb3..4a58c97750 100644 --- a/client/webpack.local.config.js +++ b/client/webpack.local.config.js @@ -1,6 +1,7 @@ var webpack = require('webpack'); var autoprefixer = require('autoprefixer'); var path = require('path'); +var HtmlWebpackPlugin = require('html-webpack-plugin'); /** * This is the Webpack configuration file for local development. It contains @@ -47,7 +48,6 @@ module.exports = { // by the dev server for dynamic hot loading. output: { path: path.join(__dirname, 'build/'), - publicPath: 'http://' + WEBPACK_SERVER_HOST + ':4041/build/', filename: '[name].js' }, @@ -55,7 +55,22 @@ module.exports = { plugins: [ new webpack.optimize.CommonsChunkPlugin('vendors', 'vendors.js'), new webpack.HotModuleReplacementPlugin(), - new webpack.NoErrorsPlugin() + new webpack.NoErrorsPlugin(), + new HtmlWebpackPlugin({ + chunks: ['vendors', 'contrast-app'], + template: 'app/html/index.html', + filename: 'contrast.html' + }), + new HtmlWebpackPlugin({ + chunks: ['vendors', 'terminal-app'], + template: 'app/html/index.html', + filename: 'terminal.html' + }), + new HtmlWebpackPlugin({ + chunks: ['vendors', 'app'], + template: 'app/html/index.html', + filename: 'index.html' + }) ], // Transform source code using Babel and React Hot Loader @@ -85,7 +100,7 @@ module.exports = { loader: 'url-loader?limit=10000&minetype=application/font-woff' }, { - test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, + test: /\.(ttf|eot|svg|ico)(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: 'file-loader' }, { diff --git a/client/webpack.production.config.js b/client/webpack.production.config.js index 1d56404b23..3b45e39908 100644 --- a/client/webpack.production.config.js +++ b/client/webpack.production.config.js @@ -2,6 +2,10 @@ var webpack = require('webpack'); var autoprefixer = require('autoprefixer'); var path = require('path'); +var CleanWebpackPlugin = require('clean-webpack-plugin'); +var ExtractTextPlugin = require("extract-text-webpack-plugin"); +var HtmlWebpackPlugin = require('html-webpack-plugin'); + var GLOBALS = { 'process.env': {NODE_ENV: '"production"'} }; @@ -43,16 +47,21 @@ module.exports = { loaders: [ { test: /\.less$/, - loader: 'style-loader!css-loader?minimize!postcss-loader!less-loader' + loader: ExtractTextPlugin.extract('style-loader', + 'css-loader?minimize!postcss-loader!less-loader') }, { test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: 'url-loader?limit=10000&minetype=application/font-woff' }, { - test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, + test: /\.(ttf|eot|svg|ico)(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: 'file-loader' }, + { + test: /\.ico$/, + loader: 'file-loader?name=[name].[ext]' + }, { test: /\.jsx?$/, exclude: /node_modules|vendor/, loader: 'babel' } ] }, @@ -72,6 +81,7 @@ module.exports = { }, plugins: [ + new CleanWebpackPlugin(['build']), new webpack.DefinePlugin(GLOBALS), new webpack.optimize.CommonsChunkPlugin('vendors', 'vendors.js'), new webpack.optimize.OccurenceOrderPlugin(true), @@ -80,6 +90,25 @@ module.exports = { compress: { warnings: false } + }), + new ExtractTextPlugin('style-[name].css'), + new HtmlWebpackPlugin({ + hash: true, + chunks: ['vendors', 'contrast-app'], + template: 'app/html/index.html', + filename: 'contrast.html' + }), + new HtmlWebpackPlugin({ + hash: true, + chunks: ['vendors', 'terminal-app'], + template: 'app/html/index.html', + filename: 'terminal.html' + }), + new HtmlWebpackPlugin({ + hash: true, + chunks: ['vendors', 'app'], + template: 'app/html/index.html', + filename: 'index.html' }) ] };